bare-metrics-core 0.1.0

Core package for the BARE metrics system
Documentation
use hdrhistogram::serialization::{
    Deserializer as HistogramDeserialiser, Serializer as HistogramSerializer, V2Serializer,
};
use hdrhistogram::Histogram;
use serde::de::Error;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_bare::Uint;
use std::collections::{BTreeMap, HashMap};

pub fn get_supported_version() -> String {
    format!("bare-metrics:{}", env!("CARGO_PKG_VERSION"))
}

#[derive(
    Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Serialize, Deserialize, Default,
)]
pub struct UnixTimestampMilliseconds(pub u64);

impl UnixTimestampMilliseconds {
    pub fn as_f64_seconds(self) -> f64 {
        self.0 as f64 * 0.001
    }
}

/// Header for a metric log file.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct LogHeader {
    /// String describing the version of this metrics log file.
    pub bare_metrics_version: String,
    /// Name of the application that emitted this metrics log file.
    /// Useful for auto-detection of rules for e.g. the GUI.
    pub application_name: String,
    /// Unix timestamp (milliseconds) describing the start of the metrics.
    pub start_time: UnixTimestampMilliseconds,
}

/// A single frame of metrics.
/// Has an end timestamp (the start timestamp should be inferred from the previous frame or the
/// header of the log file.
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct Frame {
    /// Unix timestamp (milliseconds) describing the end of this frame of metrics.
    pub end_time: UnixTimestampMilliseconds,
    /// Absolute values of updated gauges.
    pub gauge_updates: HashMap<MetricId, f64>,
    /// Absolute values of updated counters.
    /// TODO should this be counts only for this window?
    pub counter_updates: HashMap<MetricId, Uint>,
    /// Histograms only for this frame (this keeps them compact).
    pub histograms: HashMap<MetricId, SerialisableHistogram>,
    /// Descriptors of NEW metrics.
    pub new_metrics: HashMap<MetricId, MetricDescriptor>,
}

#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub enum MetricKind {
    Histogram,
    Gauge,
    Counter,
}

#[derive(Serialize, Deserialize, Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct MetricId(pub u16);

#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct MetricDescriptor {
    pub kind: MetricKind,
    pub unit: Option<String>,
    pub description: String,
    pub name: String,
    pub labels: BTreeMap<String, String>,
}

#[derive(Clone, Debug)]
pub struct SerialisableHistogram {
    pub underlying: Histogram<u64>,
}

impl Serialize for SerialisableHistogram {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut buf = Vec::new();
        V2Serializer::new()
            .serialize(&self.underlying, &mut buf)
            .expect("can't fail writing to buf");
        serializer.serialize_bytes(&buf)
    }
}

impl<'a> Deserialize<'a> for SerialisableHistogram {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'a>,
    {
        let bytes = Vec::<u8>::deserialize(deserializer)?;
        let histogram = HistogramDeserialiser::new()
            .deserialize(&mut &bytes[..])
            .map_err(|e| D::Error::custom(format!("{:?}", e)))?;
        Ok(SerialisableHistogram {
            underlying: histogram,
        })
    }
}