From 696954c631bd1eca256d58f37f9d225f6d2e7f95 Mon Sep 17 00:00:00 2001 From: Olivier 'reivilibre Date: Tue, 23 Nov 2021 23:07:57 +0000 Subject: [PATCH] Initial definition of the on-disk format --- .gitignore | 2 + bare-metrics-core/.gitignore | 2 + bare-metrics-core/Cargo.toml | 11 ++++ bare-metrics-core/src/lib.rs | 1 + bare-metrics-core/src/structures.rs | 89 +++++++++++++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 .gitignore create mode 100644 bare-metrics-core/.gitignore create mode 100644 bare-metrics-core/Cargo.toml create mode 100644 bare-metrics-core/src/lib.rs create mode 100644 bare-metrics-core/src/structures.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44dddc2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +.idea \ No newline at end of file diff --git a/bare-metrics-core/.gitignore b/bare-metrics-core/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/bare-metrics-core/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/bare-metrics-core/Cargo.toml b/bare-metrics-core/Cargo.toml new file mode 100644 index 0000000..f2f418c --- /dev/null +++ b/bare-metrics-core/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "bare-metrics-core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.130", features = ["derive"] } +serde_bare = "0.5.0" +hdrhistogram = "7.4.0" diff --git a/bare-metrics-core/src/lib.rs b/bare-metrics-core/src/lib.rs new file mode 100644 index 0000000..9ed9287 --- /dev/null +++ b/bare-metrics-core/src/lib.rs @@ -0,0 +1 @@ +pub mod structures; diff --git a/bare-metrics-core/src/structures.rs b/bare-metrics-core/src/structures.rs new file mode 100644 index 0000000..1b699dd --- /dev/null +++ b/bare-metrics-core/src/structures.rs @@ -0,0 +1,89 @@ +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::HashMap; + +pub fn get_supported_version() -> String { + format!("bare-metrics:{}", env!("CARGO_PKG_VERSION")) +} + +/// 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, + /// Unix timestamp (milliseconds) describing the start of the metrics. + pub start_time_ms: u64, +} + +/// 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_ms: u64, + /// Absolute values of updated gauges. + pub gauge_updates: HashMap, + /// Absolute values of updated counters. + /// TODO should this be counts only for this window? + pub counter_updates: HashMap, + /// Histograms only for this frame (this keeps them compact). + pub histograms: HashMap, + /// Descriptors of NEW metrics. + pub new_metrics: HashMap, +} + +#[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, + pub description: String, +} + +#[derive(Clone, Debug)] +pub struct SerialisableHistogram { + pub underlying: Histogram, +} + +impl Serialize for SerialisableHistogram { + fn serialize(&self, serializer: S) -> Result + 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(deserializer: D) -> Result + where + D: Deserializer<'a>, + { + let bytes = Vec::::deserialize(deserializer)?; + let histogram = HistogramDeserialiser::new() + .deserialize(&mut &bytes[..]) + .map_err(|e| D::Error::custom(format!("{:?}", e)))?; + Ok(SerialisableHistogram { + underlying: histogram, + }) + } +}