Initial commit
This commit is contained in:
143
src/lib.rs
Normal file
143
src/lib.rs
Normal file
@@ -0,0 +1,143 @@
|
||||
use chrony_candm::reply;
|
||||
use figment::{
|
||||
providers::{Format, Serialized, Toml},
|
||||
util::map,
|
||||
value::Map,
|
||||
Figment,
|
||||
};
|
||||
use gethostname::gethostname;
|
||||
use influxdb2::models::DataPoint;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::{
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
path::Path,
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct InfluxConfig {
|
||||
pub url: String,
|
||||
pub org: String,
|
||||
pub bucket: String,
|
||||
pub token: String,
|
||||
pub tags: Map<String, String>,
|
||||
}
|
||||
|
||||
impl Default for InfluxConfig {
|
||||
fn default() -> Self {
|
||||
let host = gethostname().into_string().unwrap();
|
||||
InfluxConfig {
|
||||
url: "http://localhost:8086".into(),
|
||||
org: "default".into(),
|
||||
bucket: "default".into(),
|
||||
token: "".into(),
|
||||
tags: map! { "host".into() => host },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct ChronyConfig {
|
||||
pub enabled: bool,
|
||||
pub timeout: u64,
|
||||
pub poll_interval: u64,
|
||||
pub measurement_prefix: String,
|
||||
pub tracking_measurement: String,
|
||||
pub sources_measurement: String,
|
||||
pub host: IpAddr,
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
impl Default for ChronyConfig {
|
||||
fn default() -> Self {
|
||||
ChronyConfig {
|
||||
enabled: false,
|
||||
timeout: 5,
|
||||
poll_interval: 60,
|
||||
measurement_prefix: "chrony.".into(),
|
||||
tracking_measurement: "tracking".into(),
|
||||
sources_measurement: "sources".into(),
|
||||
host: IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)),
|
||||
port: 323,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct SourcesConfig {
|
||||
pub chrony: ChronyConfig,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Default)]
|
||||
pub struct Config {
|
||||
pub influxdb: InfluxConfig,
|
||||
pub sources: SourcesConfig,
|
||||
}
|
||||
|
||||
pub fn load_config(filename: &Path) -> Result<Config, Box<dyn std::error::Error>> {
|
||||
let config = Figment::from(Serialized::defaults(Config::default()))
|
||||
.merge(Toml::file(filename))
|
||||
.extract()?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn datapoint_from_tracking(
|
||||
t: &reply::Tracking,
|
||||
config: &Config,
|
||||
) -> Result<DataPoint, Box<dyn std::error::Error>> {
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
|
||||
let measurement = config.sources.chrony.measurement_prefix.to_owned()
|
||||
+ &config.sources.chrony.tracking_measurement;
|
||||
let mut builder =
|
||||
DataPoint::builder(&measurement).timestamp(now.as_nanos().try_into().unwrap());
|
||||
for (key, value) in &config.influxdb.tags {
|
||||
builder = builder.tag(key, value);
|
||||
}
|
||||
|
||||
let point = builder
|
||||
.field("ref_id", t.ref_id as i64)
|
||||
.field("ref_ip_addr", t.ip_addr.to_string())
|
||||
.field("stratum", t.stratum as i64)
|
||||
.field("leap_status", t.leap_status as i64)
|
||||
.field("current_correction", f64::from(t.current_correction))
|
||||
.field("last_offset", f64::from(t.last_offset))
|
||||
.field("rms_offset", f64::from(t.rms_offset))
|
||||
.field("freq_ppm", f64::from(t.freq_ppm))
|
||||
.field("resid_freq_ppm", f64::from(t.resid_freq_ppm))
|
||||
.field("skew_ppm", f64::from(t.skew_ppm))
|
||||
.field("root_delay", f64::from(t.root_delay))
|
||||
.field("root_dispersion", f64::from(t.root_dispersion))
|
||||
.field("last_update_interval", f64::from(t.last_update_interval))
|
||||
.build()?;
|
||||
|
||||
Ok(point)
|
||||
}
|
||||
|
||||
pub fn datapoint_from_sourcedata(
|
||||
d: &reply::SourceData,
|
||||
config: &Config,
|
||||
) -> Result<DataPoint, Box<dyn std::error::Error>> {
|
||||
let now = SystemTime::now().duration_since(UNIX_EPOCH)?;
|
||||
let measurement = config.sources.chrony.measurement_prefix.to_owned()
|
||||
+ &config.sources.chrony.sources_measurement;
|
||||
let mut builder =
|
||||
DataPoint::builder(&measurement).timestamp(now.as_nanos().try_into().unwrap());
|
||||
for (key, value) in &config.influxdb.tags {
|
||||
builder = builder.tag(key, value)
|
||||
}
|
||||
builder = builder
|
||||
.tag("ip", d.ip_addr.to_string())
|
||||
.field("poll", d.poll as i64)
|
||||
.field("stratum", d.stratum as i64)
|
||||
.field("state", d.state as i64)
|
||||
.field("mode", d.mode as i64)
|
||||
.field("flags", d.flags.bits() as i64)
|
||||
.field("reachability", d.reachability as i64)
|
||||
.field("since_sample", d.since_sample as i64)
|
||||
.field("orig_latest_meas", f64::from(d.orig_latest_meas))
|
||||
.field("latest_meas", f64::from(d.latest_meas))
|
||||
.field("latest_meas_err", f64::from(d.latest_meas_err));
|
||||
let point = builder.build()?;
|
||||
|
||||
Ok(point)
|
||||
}
|
||||
Reference in New Issue
Block a user