use serde::{Deserialize, Serialize};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Metric {
pub name: String,
pub description: Option<String>,
pub unit: Option<String>,
pub metric_type: MetricType,
pub timestamp: i64,
pub attributes: HashMap<String, String>,
pub resource: Option<super::Resource>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum MetricType {
Gauge(f64),
Counter(u64),
Histogram {
count: u64,
sum: f64,
buckets: Vec<HistogramBucket>,
},
Summary {
count: u64,
sum: f64,
quantiles: Vec<Quantile>,
},
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct HistogramBucket {
pub upper_bound: f64,
pub count: u64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct Quantile {
pub quantile: f64,
pub value: f64,
}
impl Metric {
pub fn gauge(name: impl Into<String>, value: f64, timestamp: i64) -> Self {
Self {
name: name.into(),
description: None,
unit: None,
metric_type: MetricType::Gauge(value),
timestamp,
attributes: HashMap::new(),
resource: None,
}
}
pub fn counter(name: impl Into<String>, value: u64, timestamp: i64) -> Self {
Self {
name: name.into(),
description: None,
unit: None,
metric_type: MetricType::Counter(value),
timestamp,
attributes: HashMap::new(),
resource: None,
}
}
pub fn with_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.attributes.insert(key.into(), value.into());
self
}
pub fn with_resource(mut self, resource: super::Resource) -> Self {
self.resource = Some(resource);
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_gauge_metric() {
let metric = Metric::gauge("cpu.usage", 75.5, 1234567890);
assert_eq!(metric.name, "cpu.usage");
assert_eq!(metric.metric_type, MetricType::Gauge(75.5));
assert_eq!(metric.timestamp, 1234567890);
}
#[test]
fn test_counter_metric() {
let metric = Metric::counter("requests.total", 1000, 1234567890);
assert_eq!(metric.name, "requests.total");
assert_eq!(metric.metric_type, MetricType::Counter(1000));
}
#[test]
fn test_metric_with_attributes() {
let metric = Metric::gauge("temperature", 22.5, 1234567890)
.with_attribute("location", "server-room")
.with_attribute("sensor", "temp-01");
assert_eq!(metric.attributes.len(), 2);
assert_eq!(
metric.attributes.get("location"),
Some(&"server-room".to_string())
);
}
}