openmetrics_parser/public/
model.rs

1use std::{
2    collections::HashMap,
3    fmt::{self, Write},
4    sync::Arc,
5};
6
7use auto_ops::impl_op_ex;
8
9use crate::internal::{render_label_values, RenderableMetricValue};
10
11pub type Timestamp = f64;
12
13/// An OpenMetrics Exemplar (that is also valid in Prometheus)
14/// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#exemplars
15/// Exemplars are references to data outside of the MetricSet. A common use case are IDs of program traces.
16/// Exemplars MUST consist of a LabelSet and a value, and MAY have a timestamp. They MAY each be different from the MetricPoints' LabelSet and timestamp.
17/// The combined length of the label names and values of an Exemplar's LabelSet MUST NOT exceed 128 UTF-8 characters.
18/// Other characters in the text rendering of an exemplar such as ",= are not included in this limit for implementation
19/// simplicity and for consistency between the text and proto formats.
20#[derive(Debug, Clone, PartialEq)]
21pub struct Exemplar {
22    pub labels: HashMap<String, String>,
23    pub timestamp: Option<f64>,
24    pub id: f64,
25}
26
27impl Exemplar {
28    pub fn new(labels: HashMap<String, String>, id: f64, timestamp: Option<f64>) -> Exemplar {
29        Exemplar {
30            labels,
31            id,
32            timestamp,
33        }
34    }
35}
36
37impl fmt::Display for Exemplar {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        let names: Vec<&str> = self.labels.keys().map(|s| s.as_str()).collect();
40        let values: Vec<&str> = self.labels.keys().map(|s| s.as_str()).collect();
41        write!(f, "# {} {}", render_label_values(&names, &values), self.id)?;
42        if let Some(timestamp) = self.timestamp {
43            write!(f, " {}", format_float(timestamp))?;
44        }
45
46        Ok(())
47    }
48}
49
50/// A MetricFamily is a collection of metrics with the same type, name, and label names
51/// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#metricfamily
52/// A MetricFamily MAY have zero or more Metrics. A MetricFamily MUST have a name, HELP, TYPE, and UNIT metadata.
53/// Every Metric within a MetricFamily MUST have a unique LabelSet.
54#[derive(Debug)]
55pub struct MetricFamily<TypeSet, ValueType> {
56    pub family_name: String,
57    label_names: Arc<Vec<String>>,
58    pub family_type: TypeSet,
59    pub help: String,
60    pub unit: String,
61    metrics: Vec<Sample<ValueType>>,
62}
63
64impl<TypeSet, ValueType> MetricFamily<TypeSet, ValueType>
65where
66    TypeSet: Clone,
67    ValueType: RenderableMetricValue + Clone,
68{
69    pub fn new(
70        family_name: String,
71        label_names: Vec<String>,
72        family_type: TypeSet,
73        help: String,
74        unit: String,
75    ) -> Self {
76        Self {
77            family_name,
78            label_names: Arc::new(label_names),
79            family_type,
80            help,
81            unit,
82            metrics: Vec::new(),
83        }
84    }
85
86    pub fn get_label_names(&self) -> &[String] {
87        return self.label_names.as_ref().as_slice();
88    }
89
90    pub fn clone_and_convert_type<T: RenderableMetricValue + Clone>(&self) -> MetricFamily<TypeSet, T> where T: From<ValueType> {
91        MetricFamily {
92            family_name: self.family_name.clone(),
93            label_names: Arc::new((*self.label_names).clone()),
94            family_type: self.family_type.clone(),
95            help: self.help.clone(),
96            unit: self.unit.clone(),
97            metrics: self
98                .metrics
99                .iter()
100                .map(|m| m.clone_with_new_value(m.value.clone().into()))
101                .collect(),
102        }
103    }
104
105    pub fn with_labels<'a, T>(&self, labels: T) -> Self
106    where
107        T: IntoIterator<Item = (&'a str, &'a str)>,
108    {
109        let mut label_names = self.label_names.as_ref().clone();
110        let mut samples = self.metrics.clone();
111        for (k, v) in labels {
112            match label_names.binary_search(&k.to_owned() ) {
113                Ok(idx) => {
114                    for sample in samples.iter_mut() {
115                        sample.label_values[idx] = v.to_owned();
116                    }
117                }
118                Err(idx) => {
119                    label_names.insert(idx, k.to_owned());
120                    for sample in samples.iter_mut() {
121                        sample.label_values.insert(idx,v.to_owned());
122                    }
123                }
124            }
125        }
126
127        Self::new(
128            self.family_name.clone(),
129            label_names,
130            self.family_type.clone(),
131            self.help.clone(),
132            self.unit.clone(),
133        )
134        .with_samples(samples)
135        .unwrap()
136    }
137
138    pub fn without_label(&self, label_name: &str) -> Result<Self, ParseError> {
139        match self.label_names.iter().position(|n| n == label_name) {
140            Some(idx) => {
141                let mut label_names = self.label_names.as_ref().clone();
142                label_names.remove(idx);
143                let mut base = Self::new(
144                    self.family_name.clone(),
145                    label_names,
146                    self.family_type.clone(),
147                    self.help.clone(),
148                    self.unit.clone(),
149                );
150
151                for sample in self.metrics.iter() {
152                    let mut label_values = sample.label_values.clone();
153                    label_values.remove(idx);
154                    let new_sample =
155                        Sample::new(label_values, sample.timestamp, sample.value.clone());
156                    base.add_sample(new_sample)?;
157                }
158
159                Ok(base)
160            }
161            None => Err(ParseError::InvalidMetric(format!(
162                "No label `{}` in metric family",
163                label_name
164            ))),
165        }
166    }
167
168    pub fn into_iter_samples(self) -> impl Iterator<Item = Sample<ValueType>> {
169        self.metrics.into_iter()
170    }
171
172    pub fn iter_samples(&self) -> impl Iterator<Item = &Sample<ValueType>> {
173        self.metrics.iter()
174    }
175
176    pub fn iter_samples_mut(&mut self) -> impl Iterator<Item = &mut Sample<ValueType>> {
177        self.metrics.iter_mut()
178    }
179
180    pub fn with_samples<T>(mut self, samples: T) -> Result<Self, ParseError>
181    where
182        T: IntoIterator<Item = Sample<ValueType>>,
183    {
184        for sample in samples {
185            self.add_sample(sample)?;
186        }
187
188        Ok(self)
189    }
190
191    pub fn get_sample_matches(&self, sample: &Sample<ValueType>) -> Option<&Sample<ValueType>> {
192        return self
193            .metrics
194            .iter()
195            .find(|&s| s.label_values == sample.label_values);
196    }
197
198    pub fn get_sample_matches_mut(
199        &mut self,
200        sample: &Sample<ValueType>,
201    ) -> Option<&mut Sample<ValueType>> {
202        return self
203            .metrics
204            .iter_mut()
205            .find(|s| s.label_values == sample.label_values);
206    }
207
208    pub fn get_sample_by_label_values(
209        &self,
210        label_values: &[String],
211    ) -> Option<&Sample<ValueType>> {
212        return self.metrics.iter().find(|s| s.label_values == label_values);
213    }
214
215    pub fn get_sample_by_label_values_mut(
216        &mut self,
217        label_values: &[String],
218    ) -> Option<&mut Sample<ValueType>> {
219        return self
220            .metrics
221            .iter_mut()
222            .find(|s| s.label_values == label_values);
223    }
224
225    pub fn get_sample_by_labelset(&self, labelset: &LabelSet) -> Option<&Sample<ValueType>> {
226        return self.metrics.iter().find(|s| labelset.matches_sample(s));
227    }
228
229    pub fn get_sample_by_labelset_mut(
230        &mut self,
231        labelset: &LabelSet,
232    ) -> Option<&mut Sample<ValueType>> {
233        return self.metrics.iter_mut().find(|s| labelset.matches_sample(s));
234    }
235
236    pub fn set_label(&mut self, label_name: &str, label_value: &str) -> Result<(), ParseError> {
237        let index = match self.label_names.iter().position(|s| s == label_name) {
238            Some(position) => position,
239            None => {
240                return Err(ParseError::ParseError(format!(
241                    "No Label {} on Metric Family",
242                    label_name
243                )));
244            }
245        };
246
247        for metric in self.metrics.iter_mut() {
248            if index == metric.label_values.len() {
249                metric.label_values.push(label_value.to_owned());
250            } else {
251                metric.label_values[index] = label_value.to_owned();
252            }
253        }
254
255        Ok(())
256    }
257
258    pub fn add_sample(&mut self, mut s: Sample<ValueType>) -> Result<(), ParseError> {
259        if s.label_values.len() != self.label_names.len() {
260            return Err(ParseError::InvalidMetric(format!(
261                "Cannot add a sample with {} labels into a family with {}",
262                s.label_values.len(),
263                self.label_names.len()
264            )));
265        }
266
267        if self.get_sample_by_label_values(&s.label_values).is_some() {
268            return Err(ParseError::InvalidMetric(format!(
269                "Cannot add a duplicate metric to a MetricFamily (Label Values: {:?})",
270                s.label_values
271            )));
272        }
273
274        s.set_label_names(self.label_names.clone());
275        self.metrics.push(s);
276
277        Ok(())
278    }
279}
280
281impl<TypeSet, ValueType> fmt::Display for MetricFamily<TypeSet, ValueType>
282where
283    TypeSet: fmt::Display + Default + PartialEq,
284    ValueType: RenderableMetricValue + Clone,
285{
286    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
287        if !self.help.is_empty() {
288            writeln!(f, "# HELP {} {}", self.family_name, self.help)?;
289        }
290
291        if self.family_type != <TypeSet>::default() {
292            writeln!(f, "# TYPE {} {}", self.family_name, self.family_type)?;
293        }
294
295        if !self.unit.is_empty() {
296            writeln!(f, "# UNIT {} {}", self.family_name, self.unit)?;
297        }
298
299        let label_names: Vec<&str> = self.label_names.iter().map(|s| s.as_str()).collect();
300
301        for metric in self.metrics.iter() {
302            metric.render(f, &self.family_name, &label_names)?;
303        }
304
305        Ok(())
306    }
307}
308
309/// Exposition is the top level object of the parser. It's a collection of metric families, indexed by name
310#[derive(Debug)]
311pub struct MetricsExposition<TypeSet, ValueType> {
312    pub families: HashMap<String, MetricFamily<TypeSet, ValueType>>,
313}
314
315impl<TypeSet, ValueType> fmt::Display for MetricsExposition<TypeSet, ValueType>
316where
317    TypeSet: fmt::Display + Default + PartialEq,
318    ValueType: RenderableMetricValue + Clone,
319{
320    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
321        for (i, (_, family)) in self.families.iter().enumerate() {
322            write!(f, "{}", family)?;
323            if i != self.families.len()-1 {
324                write!(f, "\n")?;
325            }
326        }
327
328        Ok(())
329    }
330}
331
332impl<TypeSet, ValueType> Default for MetricsExposition<TypeSet, ValueType> {
333    fn default() -> Self {
334        Self::new()
335    }
336}
337
338impl<TypeSet, ValueType> MetricsExposition<TypeSet, ValueType> {
339    pub fn new() -> MetricsExposition<TypeSet, ValueType> {
340        MetricsExposition {
341            families: HashMap::new(),
342        }
343    }
344}
345
346#[derive(Debug, Clone, PartialEq)]
347pub struct CounterValue {
348    pub value: MetricNumber,
349    pub created: Option<Timestamp>,
350    pub exemplar: Option<Exemplar>,
351}
352
353fn format_float(f: f64) -> String {
354    if f == f64::NEG_INFINITY {
355        String::from("-Inf")
356    }
357    else if f == f64::INFINITY {
358        String::from("+Inf")
359    }
360    else if f.is_nan() {
361        String::from("NaN")
362    }
363    else {
364        format!("{}", f)
365    }
366}
367
368#[derive(Debug, Clone, PartialEq)]
369pub struct HistogramBucket {
370    pub count: MetricNumber,
371    pub upper_bound: f64,
372    pub exemplar: Option<Exemplar>,
373}
374
375impl RenderableMetricValue for HistogramBucket {
376    fn render(
377        &self,
378        f: &mut fmt::Formatter<'_>,
379        metric_name: &str,
380        _: Option<&Timestamp>,
381        label_names: &[&str],
382        label_values: &[&str],
383    ) -> fmt::Result {
384        let upper_bound_str = format_float(self.upper_bound);
385        let label_names = {
386            let mut names = Vec::from(label_names);
387            names.push("le");
388            names
389        };
390
391        let label_values = {
392            let mut values = Vec::from(label_values);
393            values.push(&upper_bound_str);
394            values
395        };
396
397        write!(
398            f,
399            "{}_bucket{} {}",
400            metric_name,
401            render_label_values(&label_names, &label_values),
402            self.count
403        )?;
404
405        if let Some(ex) = self.exemplar.as_ref() {
406            write!(f, "{}", ex)?;
407        }
408
409        f.write_char('\n')?;
410
411        Ok(())
412    }
413}
414
415#[derive(Debug, Default, Clone, PartialEq)]
416pub struct HistogramValue {
417    pub sum: Option<MetricNumber>,
418    pub count: Option<u64>,
419    pub created: Option<Timestamp>,
420    pub buckets: Vec<HistogramBucket>,
421}
422
423impl RenderableMetricValue for HistogramValue {
424    fn render(
425        &self,
426        f: &mut fmt::Formatter<'_>,
427        metric_name: &str,
428        timestamp: Option<&Timestamp>,
429        label_names: &[&str],
430        label_values: &[&str],
431    ) -> fmt::Result {
432        for bucket in self.buckets.iter() {
433            bucket.render(f, metric_name, timestamp, label_names, label_values)?;
434        }
435
436        let labels = render_label_values(label_names, label_values);
437
438        if let Some(s) = self.sum {
439            writeln!(f, "{}_sum{} {}", metric_name, labels, s)?;
440        }
441
442        if let Some(c) = self.count {
443            writeln!(f, "{}_count{} {}", metric_name, labels, c)?;
444        }
445
446        if let Some(c) = self.created {
447            writeln!(f, "{}_created{} {}", metric_name, labels, c)?;
448        }
449
450        Ok(())
451    }
452}
453
454#[derive(Debug, Clone)]
455pub struct State {
456    pub name: String,
457    pub enabled: bool,
458}
459
460#[derive(Debug, Clone, PartialEq)]
461pub struct Quantile {
462    pub quantile: f64,
463    pub value: MetricNumber,
464}
465
466impl RenderableMetricValue for Quantile {
467    fn render(
468        &self,
469        f: &mut fmt::Formatter<'_>,
470        metric_name: &str,
471        _: Option<&Timestamp>,
472        label_names: &[&str],
473        label_values: &[&str],
474    ) -> fmt::Result {
475        let quantile_str = format_float(self.quantile);
476        let label_names = {
477            let mut names = Vec::from(label_names);
478            names.push("quantile");
479            names
480        };
481
482        let label_values = {
483            let mut values = Vec::from(label_values);
484            values.push(&quantile_str);
485            values
486        };
487
488        writeln!(
489            f,
490            "{}{} {}",
491            metric_name,
492            render_label_values(&label_names, &label_values),
493            self.value
494        )
495    }
496}
497
498#[derive(Debug, Default, Clone, PartialEq)]
499pub struct SummaryValue {
500    pub sum: Option<MetricNumber>,
501    pub count: Option<u64>,
502    pub created: Option<Timestamp>,
503    pub quantiles: Vec<Quantile>,
504}
505
506impl RenderableMetricValue for SummaryValue {
507    fn render(
508        &self,
509        f: &mut fmt::Formatter<'_>,
510        metric_name: &str,
511        timestamp: Option<&Timestamp>,
512        label_names: &[&str],
513        label_values: &[&str],
514    ) -> fmt::Result {
515        for q in self.quantiles.iter() {
516            q.render(f, metric_name, timestamp, label_names, label_values)?;
517        }
518
519        let labels = render_label_values(label_names, label_values);
520
521        if let Some(s) = self.sum {
522            writeln!(f, "{}_sum{} {}", metric_name, labels, s)?;
523        }
524
525        if let Some(s) = self.count {
526            writeln!(f, "{}_count{} {}", metric_name, labels, s)?;
527        }
528
529        if let Some(s) = self.created {
530            writeln!(f, "{}_created{} {}", metric_name, labels, s)?;
531        }
532
533        Ok(())
534    }
535}
536
537#[derive(Debug, PartialEq, Clone, Copy)]
538pub enum OpenMetricsType {
539    /// A Counter that only goes up
540    /// Counters measure discrete events. Common examples are the number of HTTP requests received,
541    /// CPU seconds spent, or bytes sent. For counters how quickly they are increasing over time is what is of interest to a user.
542    /// A MetricPoint in a Metric with the type Counter MUST have one value called Total. A Total is a non-NaN and MUST be
543    /// monotonically non-decreasing over time, starting from 0.
544    /// A MetricPoint in a Metric with the type Counter SHOULD have a Timestamp value called Created. This can help ingestors discern between new metrics and long-running ones it did not see before.
545    /// A MetricPoint in a Metric's Counter's Total MAY reset to 0. If present, the corresponding Created time MUST also be set to the timestamp of the reset.
546    /// A MetricPoint in a Metric's Counter's Total MAY have an exemplar.
547    Counter,
548
549    /// A Gauge that can go up or down
550    /// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#gauge
551    /// Gauges are current measurements, such as bytes of memory currently used or the number of items in a queue.
552    /// For gauges the absolute value is what is of interest to a user.
553    /// A MetricPoint in a Metric with the type gauge MUST have a single value.
554    /// Gauges MAY increase, decrease, or stay constant over time. Even if they only ever go in one direction,
555    /// they might still be gauges and not counters. The size of a log file would usually only increase,
556    /// a resource might decrease, and the limit of a queue size may be constant.
557    /// A gauge MAY be used to encode an enum where the enum has many states and changes over time, it is the most efficient but least user friendly.
558    Gauge,
559
560    /// A Histogram that has a number of buckets that count events, and a _sum and _count
561    /// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#histogram
562    /// Histograms measure distributions of discrete events. Common examples are the latency of HTTP requests, function runtimes, or I/O request sizes.
563    /// A Histogram MetricPoint MUST contain at least one bucket, and SHOULD contain Sum, and Created values. Every bucket MUST have a threshold and a value.
564    /// Histogram MetricPoints MUST have at least a bucket with an +Inf threshold. Buckets MUST be cumulative. As an example for a metric representing
565    /// request latency in seconds its values for buckets with thresholds 1, 2, 3, and +Inf MUST follow value_1 <= value_2 <= value_3 <= value_+Inf.
566    /// If ten requests took 1 second each, the values of the 1, 2, 3, and +Inf buckets MUST equal 10.
567    /// The +Inf bucket counts all requests. If present, the Sum value MUST equal the Sum of all the measured event values.
568    /// Bucket thresholds within a MetricPoint MUST be unique.
569    /// Semantically, Sum, and buckets values are counters so MUST NOT be NaN or negative.
570    /// Negative threshold buckets MAY be used, but then the Histogram MetricPoint MUST NOT contain a sum value as it would
571    /// no longer be a counter semantically. Bucket thresholds MUST NOT equal NaN. Count and bucket values MUST be integers.
572    /// A Histogram MetricPoint SHOULD have a Timestamp value called Created. This can help ingestors discern between new
573    /// metrics and long-running ones it did not see before.
574    /// A Histogram's Metric's LabelSet MUST NOT have a "le" label name.
575    /// Bucket values MAY have exemplars. Buckets are cumulative to allow monitoring systems to drop any non-+Inf bucket for performance/anti-denial-of-service reasons in a way that loses granularity but is still a valid Histogram.
576    Histogram,
577
578    /// GaugeHistograms measure current distributions. Common examples are how long items have been waiting in a queue, or size of the requests in a queue.
579    /// A GaugeHistogram MetricPoint MUST have at least one bucket with an +Inf threshold, and SHOULD contain a Gsum value.
580    /// Every bucket MUST have a threshold and a value.
581    /// The buckets for a GaugeHistogram follow all the same rules as for a Histogram.
582    /// The bucket and Gsum of a GaugeHistogram are conceptually gauges, however bucket values MUST NOT be negative or NaN.
583    /// If negative threshold buckets are present, then sum MAY be negative. Gsum MUST NOT be NaN. Bucket values MUST be integers.
584    /// A GaugeHistogram's Metric's LabelSet MUST NOT have a "le" label name.
585    /// Bucket values can have exemplars.
586    /// Each bucket covers the values less and or equal to it, and the value of the exemplar MUST be within this range. E
587    /// Exemplars SHOULD be put into the bucket with the highest value. A bucket MUST NOT have more than one exemplar.
588    GaugeHistogram,
589
590    /// StateSets represent a series of related boolean values, also called a bitset. If ENUMs need to be encoded this MAY be done via StateSet.
591    /// A point of a StateSet metric MAY contain multiple states and MUST contain one boolean per State. States have a name which are Strings.
592    /// A StateSet Metric's LabelSet MUST NOT have a label name which is the same as the name of its MetricFamily.
593    /// If encoded as a StateSet, ENUMs MUST have exactly one Boolean which is true within a MetricPoint.
594    /// This is suitable where the enum value changes over time, and the number of States isn't much more than a handful.
595    StateSet,
596
597    /// Summaries also measure distributions of discrete events and MAY be used when Histograms are too expensive and/or an average event size is sufficient.
598    /// They MAY also be used for backwards compatibility, because some existing instrumentation libraries
599    /// expose precomputed quantiles and do not support Histograms. Precomputed quantiles SHOULD NOT be used,
600    /// because quantiles are not aggregatable and the user often can not deduce what timeframe they cover.
601    /// A Summary MetricPoint MAY consist of a Count, Sum, Created, and a set of quantiles.
602    /// Semantically, Count and Sum values are counters so MUST NOT be NaN or negative. Count MUST be an integer.
603    /// A MetricPoint in a Metric with the type Summary which contains Count or Sum values SHOULD have a
604    /// Timestamp value called Created. This can help ingestors discern between new metrics and long-running ones it did not see before.
605    /// Created MUST NOT relate to the collection period of quantile values.
606    /// Quantiles are a map from a quantile to a value. An example is a quantile 0.95 with value 0.2 in a metric called
607    /// myapp_http_request_duration_seconds which means that the 95th percentile latency is 200ms over an unknown timeframe.
608    /// If there are no events in the relevant timeframe, the value for a quantile MUST be NaN.
609    /// A Quantile's Metric's LabelSet MUST NOT have "quantile" label name. Quantiles MUST be between 0 and 1 inclusive.
610    /// Quantile values MUST NOT be negative. Quantile values SHOULD represent the recent values. Commonly this would be over the last 5-10 minutes.
611    Summary,
612
613    /// Info metrics are used to expose textual information which SHOULD NOT change during process lifetime.
614    /// Common examples are an application's version, revision control commit, and the version of a compiler.
615    /// A MetricPoint of an Info Metric contains a LabelSet. An Info MetricPoint's LabelSet MUST NOT have a label name which
616    /// is the same as the name of a label of the LabelSet of its Metric.
617    /// Info MAY be used to encode ENUMs whose values do not change over time, such as the type of a network interface.
618    /// MetricFamilies of type Info MUST have an empty Unit string.
619    Info,
620
621    /// Unknown SHOULD NOT be used. Unknown MAY be used when it is impossible to determine the types of individual metrics from 3rd party systems.
622    /// A point in a metric with the unknown type MUST have a single value.
623    Unknown,
624}
625
626#[derive(Debug, Clone)]
627pub enum OpenMetricsValue {
628    Unknown(MetricNumber),
629    Gauge(MetricNumber),
630    Counter(CounterValue),
631    Histogram(HistogramValue),
632    StateSet(MetricNumber),
633    GaugeHistogram(HistogramValue),
634    Info,
635    Summary(SummaryValue),
636}
637
638impl RenderableMetricValue for OpenMetricsValue {
639    fn render(
640        &self,
641        f: &mut fmt::Formatter<'_>,
642        metric_name: &str,
643        timestamp: Option<&Timestamp>,
644        label_names: &[&str],
645        label_values: &[&str],
646    ) -> fmt::Result {
647        let timestamp_str = timestamp.map(|t| format!(" {}", format_float(*t))).unwrap_or_default();
648        match self {
649            OpenMetricsValue::Unknown(n)
650            | OpenMetricsValue::Gauge(n)
651            | OpenMetricsValue::StateSet(n) =>{
652                writeln!(
653                    f,
654                    "{}{} {}{}",
655                    metric_name,
656                    render_label_values(label_names, label_values),
657                    n,
658                    timestamp_str
659                )
660            },
661            OpenMetricsValue::Counter(c) => {
662                write!(
663                    f,
664                    "{}{} {}{}",
665                    metric_name,
666                    render_label_values(label_names, label_values),
667                    c.value,
668                    timestamp_str
669                )?;
670                if let Some(ex) = c.exemplar.as_ref() {
671                    write!(f, "{}", ex)?;
672                }
673
674                f.write_char('\n')
675            }
676            OpenMetricsValue::Histogram(h) | OpenMetricsValue::GaugeHistogram(h) => {
677                // TODO: This is actually wrong for GaugeHistograms (they should have _gsum and _gcount), but I'm too lazy to fix this at the moment
678                h.render(f, metric_name, timestamp, label_names, label_values)
679            }
680            OpenMetricsValue::Summary(s) => {
681                s.render(f, metric_name, timestamp, label_names, label_values)
682            }
683            OpenMetricsValue::Info => {
684                writeln!(
685                    f,
686                    "{}{} {} {}",
687                    metric_name,
688                    render_label_values(label_names, label_values),
689                    MetricNumber::Int(1),
690                    timestamp_str
691                )
692            }
693        }
694    }
695}
696
697#[derive(Debug, PartialEq, Clone)]
698pub enum PrometheusType {
699    Counter,
700    Gauge,
701    Histogram,
702    Summary,
703    Unknown,
704}
705
706impl fmt::Display for PrometheusType {
707    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
708        let out = match self {
709            PrometheusType::Counter => "counter",
710            PrometheusType::Gauge => "gauge",
711            PrometheusType::Histogram => "histogram",
712            PrometheusType::Summary => "summary",
713            PrometheusType::Unknown => "unknown",
714        };
715
716        f.write_str(out)
717    }
718}
719
720#[derive(Debug, Clone, PartialEq)]
721pub struct PrometheusCounterValue {
722    pub value: MetricNumber,
723    pub exemplar: Option<Exemplar>,
724}
725
726#[derive(Debug, Clone, PartialEq)]
727pub enum PrometheusValue {
728    Unknown(MetricNumber),
729    Gauge(MetricNumber),
730    Counter(PrometheusCounterValue),
731    Histogram(HistogramValue),
732    Summary(SummaryValue),
733}
734
735impl RenderableMetricValue for PrometheusValue {
736    fn render(
737        &self,
738        f: &mut fmt::Formatter<'_>,
739        metric_name: &str,
740        timestamp: Option<&Timestamp>,
741        label_names: &[&str],
742        label_values: &[&str],
743    ) -> fmt::Result {
744        let timestamp_str = timestamp.map(|t| format!(" {}", format_float(*t))).unwrap_or_default();
745        match self {
746            PrometheusValue::Unknown(n) | PrometheusValue::Gauge(n) => writeln!(
747                f,
748                "{}{} {}{}",
749                metric_name,
750                render_label_values(label_names, label_values),
751                n,
752                timestamp_str
753            ),
754            PrometheusValue::Counter(c) => {
755                write!(
756                    f,
757                    "{}{} {}{}",
758                    metric_name,
759                    render_label_values(label_names, label_values),
760                    c.value,
761                    timestamp_str
762                )?;
763                if let Some(ex) = c.exemplar.as_ref() {
764                    write!(f, "{}", ex)?;
765                }
766
767                f.write_char('\n')
768            }
769            PrometheusValue::Histogram(h) => {
770                h.render(f, metric_name, timestamp, label_names, label_values)
771            }
772            PrometheusValue::Summary(s) => {
773                s.render(f, metric_name, timestamp, label_names, label_values)
774            }
775        }
776    }
777}
778
779#[derive(Debug, Clone)]
780pub struct Sample<ValueType> {
781    label_names: Option<Arc<Vec<String>>>,
782    label_values: Vec<String>,
783    pub timestamp: Option<Timestamp>,
784    pub value: ValueType,
785}
786
787impl<ValueType> Sample<ValueType>
788where
789    ValueType: RenderableMetricValue + Clone,
790{
791    pub fn new(label_values: Vec<String>, timestamp: Option<Timestamp>, value: ValueType) -> Self {
792        Self {
793            label_values,
794            timestamp,
795            value,
796            label_names: None,
797        }
798    }
799
800    fn clone_with_new_value<T>(&self, value: T) -> Sample<T> where T: RenderableMetricValue + Clone {
801        return Sample {
802            label_names: self.label_names.clone(),
803            label_values: self.label_values.clone(),
804            timestamp: self.timestamp.clone(),
805            value,
806        }
807    }
808
809    fn set_label_names(&mut self, label_names: Arc<Vec<String>>) {
810        self.label_names = Some(label_names);
811    }
812
813    pub fn without_label(&self, label_name: &str) -> Result<Self, ParseError> {
814        if let Some(labels) = &self.label_names {
815            if let Some(idx) = labels.iter().position(|name| name == label_name) {
816                let mut label_values = self.label_values.clone();
817                label_values.remove(idx);
818
819                return Ok(Self::new(label_values, self.timestamp.clone(), self.value.clone()));
820            }
821
822            return Err(ParseError::InvalidMetric(format!("Label {} doesn't existin in metric", label_name)));
823        }
824
825        return Err(ParseError::InvalidMetric(format!("Metric isn't bound to a family, so doesn't have names")));
826    }
827
828    pub fn get_labelset(&self) -> Result<LabelSet, ParseError> {
829        if let Some(label_names) = &self.label_names {
830            return LabelSet::new(label_names.clone(), self);
831        }
832
833        Err(ParseError::InvalidMetric(
834            "Metric has not been bound to a family yet, and thus doesn't have label names"
835                .to_string(),
836        ))
837    }
838
839    fn render(
840        &self,
841        f: &mut fmt::Formatter<'_>,
842        metric_name: &str,
843        label_names: &[&str],
844    ) -> fmt::Result {
845        let values: Vec<&str> = self.label_values.iter().map(|s| s.as_str()).collect();
846        self.value.render(
847            f,
848            metric_name,
849            self.timestamp.as_ref(),
850            label_names,
851            &values,
852        )
853    }
854}
855
856#[derive(Debug, Copy, Clone, PartialEq)]
857pub enum MetricNumber {
858    Float(f64),
859    Int(i64),
860}
861
862impl fmt::Display for MetricNumber {
863    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
864        match self {
865            MetricNumber::Float(n) => write!(f, "{}", format_float(*n)),
866            MetricNumber::Int(n) => write!(f, "{}", n),
867        }
868    }
869}
870
871impl MetricNumber {
872    pub fn as_f64(&self) -> f64 {
873        match self {
874            MetricNumber::Int(i) => *i as f64,
875            MetricNumber::Float(f) => *f,
876        }
877    }
878
879    pub fn as_i64(&self) -> Option<i64> {
880        match self {
881            MetricNumber::Int(i) => Some(*i),
882            MetricNumber::Float(f) if (f.round() - *f).abs() < f64::EPSILON => Some(*f as i64),
883            _ => None,
884        }
885    }
886}
887
888impl_op_ex!(+ |a: &MetricNumber, b: &MetricNumber| -> MetricNumber {
889    match (a, b) {
890        (MetricNumber::Float(f), MetricNumber::Float(f2)) => MetricNumber::Float(f + f2),
891        (MetricNumber::Float(f), MetricNumber::Int(i)) => MetricNumber::Float(f + *i as f64),
892        (MetricNumber::Int(i), MetricNumber::Float(f)) => MetricNumber::Float(f + *i as f64),
893        (MetricNumber::Int(i), MetricNumber::Int(i2)) => MetricNumber::Int(i + i2),
894    }
895});
896
897impl_op_ex!(+= |a: &mut MetricNumber, b: &MetricNumber| {
898    match (&a, b) {
899        (MetricNumber::Float(f), MetricNumber::Float(f2)) => *a = MetricNumber::Float(*f + f2),
900        (MetricNumber::Float(f), MetricNumber::Int(i)) => *a = MetricNumber::Float(*f + *i as f64),
901        (MetricNumber::Int(i), MetricNumber::Float(f)) => *a = MetricNumber::Float(*i as f64 + *f),
902        (MetricNumber::Int(i), MetricNumber::Int(i2)) => *a = MetricNumber::Int(*i + i2),
903    }
904});
905
906impl_op_ex!(-|a: &MetricNumber, b: &MetricNumber| -> MetricNumber {
907    match (a, b) {
908        (MetricNumber::Float(f), MetricNumber::Float(f2)) => MetricNumber::Float(f - f2),
909        (MetricNumber::Float(f), MetricNumber::Int(i)) => MetricNumber::Float(f - *i as f64),
910        (MetricNumber::Int(i), MetricNumber::Float(f)) => MetricNumber::Float(*i as f64 - f),
911        (MetricNumber::Int(i), MetricNumber::Int(i2)) => MetricNumber::Int(i - i2),
912    }
913});
914
915impl_op_ex!(-= |a: &mut MetricNumber, b: &MetricNumber| {
916    match (&a, b) {
917        (MetricNumber::Float(f), MetricNumber::Float(f2)) => *a = MetricNumber::Float(*f - f2),
918        (MetricNumber::Float(f), MetricNumber::Int(i)) => *a = MetricNumber::Float(*f - *i as f64),
919        (MetricNumber::Int(i), MetricNumber::Float(f)) => *a = MetricNumber::Float(*i as f64 - *f),
920        (MetricNumber::Int(i), MetricNumber::Int(i2)) => *a = MetricNumber::Int(*i - i2),
921    }
922});
923
924impl_op_ex!(*|a: &MetricNumber, b: &MetricNumber| -> MetricNumber {
925    match (a, b) {
926        (MetricNumber::Float(f), MetricNumber::Float(f2)) => MetricNumber::Float(f * f2),
927        (MetricNumber::Float(f), MetricNumber::Int(i)) => MetricNumber::Float(f * *i as f64),
928        (MetricNumber::Int(i), MetricNumber::Float(f)) => MetricNumber::Float(*i as f64 * *f),
929        (MetricNumber::Int(i), MetricNumber::Int(i2)) => MetricNumber::Int(i * i2),
930    }
931});
932
933impl_op_ex!(*= |a: &mut MetricNumber, b: &MetricNumber| {
934    match (&a, b) {
935        (MetricNumber::Float(f), MetricNumber::Float(f2)) => *a = MetricNumber::Float(*f * f2),
936        (MetricNumber::Float(f), MetricNumber::Int(i)) => *a = MetricNumber::Float(*f * *i as f64),
937        (MetricNumber::Int(i), MetricNumber::Float(f)) => *a = MetricNumber::Float(*i as f64 * *f),
938        (MetricNumber::Int(i), MetricNumber::Int(i2)) => *a = MetricNumber::Int(*i * i2),
939    }
940});
941
942impl_op_ex!(/ |a: &MetricNumber, b: &MetricNumber| -> MetricNumber {
943    match (a, b) {
944        (MetricNumber::Float(f), MetricNumber::Float(f2)) => MetricNumber::Float(f / f2),
945        (MetricNumber::Float(f), MetricNumber::Int(i)) => MetricNumber::Float(f / *i as f64),
946        (MetricNumber::Int(i), MetricNumber::Float(f)) => MetricNumber::Float(*i as f64 / f),
947        (MetricNumber::Int(i), MetricNumber::Int(i2)) => MetricNumber::Int(i / i2),
948    }
949});
950
951impl_op_ex!(/= |a: &mut MetricNumber, b: &MetricNumber| {
952    match (&a, b) {
953        (MetricNumber::Float(f), MetricNumber::Float(f2)) => *a = MetricNumber::Float(*f / f2),
954        (MetricNumber::Float(f), MetricNumber::Int(i)) => *a = MetricNumber::Float(*f / *i as f64),
955        (MetricNumber::Int(i), MetricNumber::Float(f)) => *a = MetricNumber::Float(*i as f64 / f),
956        (MetricNumber::Int(i), MetricNumber::Int(i2)) => *a = MetricNumber::Int(*i / i2),
957    }
958});
959
960#[derive(Debug)]
961pub enum ParseError {
962    ParseError(String),
963    DuplicateMetric,
964    InvalidMetric(String),
965}
966
967impl fmt::Display for ParseError {
968    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
969        match self {
970            ParseError::ParseError(e) => e.fmt(f),
971            ParseError::DuplicateMetric => f.write_str("Found two metrics with the same labelset"),
972            ParseError::InvalidMetric(s) => f.write_str(s),
973        }
974    }
975}
976
977pub struct LabelSet<'a> {
978    label_names: Arc<Vec<String>>,
979    label_values: &'a [String],
980}
981
982impl<'a> LabelSet<'a> {
983    pub fn new<ValueType>(
984        label_names: Arc<Vec<String>>,
985        sample: &'a Sample<ValueType>,
986    ) -> Result<Self, ParseError> {
987        if label_names.len() != sample.label_values.len() {
988            return Err(ParseError::InvalidMetric(format!(
989                "Cannot create labelset from family with {} labels and sample with {}",
990                label_names.len(),
991                sample.label_values.len()
992            )));
993        }
994
995        Ok(Self {
996            label_names,
997            label_values: &sample.label_values,
998        })
999    }
1000
1001    pub fn matches_sample<ValueType>(&self, sample: &Sample<ValueType>) -> bool {
1002        self.matches_values(&sample.label_values)
1003    }
1004
1005    pub fn matches_values(&self, label_values: &[String]) -> bool {
1006        self.label_values == label_values
1007    }
1008
1009    pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
1010        return self.label_names.iter().zip(self.label_values);
1011    }
1012
1013    pub fn iter_names(&self) -> impl Iterator<Item = &String> {
1014        self.label_names.iter()
1015    }
1016
1017    pub fn iter_values(&self) -> impl Iterator<Item = &String> {
1018        self.label_values.iter()
1019    }
1020
1021    pub fn get_label_value(&self, label_name: &str) -> Option<&str> {
1022        return self
1023            .label_names
1024            .iter()
1025            .position(|s| s == label_name)
1026            .map(|i| self.label_values[i].as_str());
1027    }
1028}