Skip to main content

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