use chrono::{FixedOffset, NaiveDate, NaiveTime};
use prometheus_client::{
collector::Collector,
encoding::DescriptorEncoder,
metrics::{gauge::ConstGauge, info::Info},
registry::{Registry, Unit},
};
use serde_with::{serde_as, DisplayFromStr};
use super::deserialize_bool;
use crate::{
prometheus_ext::{AsMetrics, EncodeExt},
MikrotikClient,
};
impl MikrotikClient {
#[tracing::instrument(level = "debug", err)]
pub async fn get_clock(&self) -> anyhow::Result<Clock> {
self.get_all("/rest/system/clock").await
}
}
#[serde_as]
#[derive(serde::Deserialize, Debug, Clone)]
#[serde(rename_all = "kebab-case")]
pub struct Clock {
pub date: NaiveDate,
#[serde(deserialize_with = "deserialize_bool")]
pub dst_active: bool,
#[serde_as(as = "DisplayFromStr")]
pub gmt_offset: FixedOffset,
pub time: NaiveTime,
#[serde(deserialize_with = "deserialize_bool")]
pub time_zone_autodetect: bool,
pub time_zone_name: String,
}
impl AsMetrics for Clock {
fn register_as_metrics(self: Box<Self>, registry: &mut Registry) {
registry
.sub_registry_with_prefix("clock")
.register_collector(self);
}
}
impl Collector for Clock {
fn encode(&self, mut encoder: DescriptorEncoder) -> Result<(), std::fmt::Error> {
if let Some(datetime) = self
.date
.and_time(self.time)
.and_local_timezone(self.gmt_offset)
.single()
{
ConstGauge::new(datetime.timestamp()).encode_e(
&mut encoder,
"datetime",
"Internal mikrotik time normalized to UTC as unix timestamp",
)?;
};
ConstGauge::new(i64::from(self.gmt_offset.local_minus_utc())).encode_e_unit(
&mut encoder,
"time_zone_offset",
"Current TimeZone offset from UTC",
&Unit::Seconds,
)?;
ConstGauge::new(i64::from(self.time_zone_autodetect)).encode_e(
&mut encoder,
"time_zone_autodetect",
"Is time zone autodetect enabled",
)?;
ConstGauge::new(i64::from(self.dst_active)).encode_e(
&mut encoder,
"dst_active",
"Is daylight-savings time enabled",
)?;
Info::new(&[("time_zone_name", self.time_zone_name.clone())][..]).encode_e(
&mut encoder,
"time_zone_name",
"Current timezone name",
)?;
Ok(())
}
}