Skip to main content

entrenar/monitor/prometheus/
types.rs

1//! Prometheus metric types and definitions.
2
3/// Metric type for Prometheus
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum MetricType {
6    /// Gauge: current value that can go up or down
7    Gauge,
8    /// Counter: monotonically increasing value
9    Counter,
10    /// Histogram: distribution of values
11    Histogram,
12}
13
14/// A single metric definition
15#[derive(Debug, Clone)]
16pub struct MetricDef {
17    /// Metric name (must be valid Prometheus name)
18    pub name: String,
19    /// Help text describing the metric
20    pub help: String,
21    /// Metric type
22    pub metric_type: MetricType,
23    /// Label names
24    pub labels: Vec<String>,
25}
26
27impl MetricDef {
28    /// Create a new gauge metric
29    pub fn gauge(name: &str, help: &str) -> Self {
30        Self {
31            name: name.to_string(),
32            help: help.to_string(),
33            metric_type: MetricType::Gauge,
34            labels: Vec::new(),
35        }
36    }
37
38    /// Create a new counter metric
39    pub fn counter(name: &str, help: &str) -> Self {
40        Self {
41            name: name.to_string(),
42            help: help.to_string(),
43            metric_type: MetricType::Counter,
44            labels: Vec::new(),
45        }
46    }
47
48    /// Add labels to the metric
49    pub fn with_labels(mut self, labels: &[&str]) -> Self {
50        self.labels = labels.iter().map(|s| (*s).to_string()).collect();
51        self
52    }
53}
54
55/// Label values for a specific metric series
56#[derive(Debug, Clone, PartialEq, Eq, Hash)]
57pub struct LabelSet {
58    pub(crate) values: Vec<(String, String)>,
59}
60
61impl LabelSet {
62    /// Create an empty label set
63    pub fn new() -> Self {
64        Self { values: Vec::new() }
65    }
66
67    /// Create label set from key-value pairs
68    pub fn from_pairs(pairs: &[(&str, &str)]) -> Self {
69        Self { values: pairs.iter().map(|(k, v)| ((*k).to_string(), (*v).to_string())).collect() }
70    }
71
72    /// Add a label
73    pub fn add(mut self, key: &str, value: &str) -> Self {
74        self.values.push((key.to_string(), value.to_string()));
75        self
76    }
77
78    /// Format labels for Prometheus output
79    pub(crate) fn format(&self) -> String {
80        if self.values.is_empty() {
81            return String::new();
82        }
83
84        let parts: Vec<String> = self
85            .values
86            .iter()
87            .map(|(k, v)| format!("{}=\"{}\"", k, escape_label_value(v)))
88            .collect();
89
90        format!("{{{}}}", parts.join(","))
91    }
92}
93
94impl Default for LabelSet {
95    fn default() -> Self {
96        Self::new()
97    }
98}
99
100/// Escape label values for Prometheus format
101pub(crate) fn escape_label_value(s: &str) -> String {
102    s.replace('\\', "\\\\").replace('"', "\\\"").replace('\n', "\\n")
103}
104
105/// A metric value with optional labels
106#[derive(Debug, Clone)]
107pub(crate) struct MetricValue {
108    pub(crate) labels: LabelSet,
109    pub(crate) value: f64,
110    pub(crate) timestamp: Option<u64>,
111}