prometheus/
value.rs

1// Copyright 2014 The Prometheus Authors
2// Copyright 2019 TiKV Project Authors. Licensed under Apache-2.0.
3
4use crate::atomic64::{Atomic, Number};
5use crate::desc::{Desc, Describer};
6use crate::errors::{Error, Result};
7use crate::proto::{Counter, Gauge, LabelPair, Metric, MetricFamily, MetricType};
8
9/// `ValueType` is an enumeration of metric types that represent a simple value
10/// for [`Counter`] and [`Gauge`].
11#[derive(Debug, Copy, Clone, Eq, PartialEq)]
12pub enum ValueType {
13    Counter,
14    Gauge,
15}
16
17impl ValueType {
18    /// `metric_type` returns the corresponding proto metric type.
19    pub fn metric_type(self) -> MetricType {
20        match self {
21            ValueType::Counter => MetricType::COUNTER,
22            ValueType::Gauge => MetricType::GAUGE,
23        }
24    }
25}
26
27/// A generic metric for [`Counter`] and [`Gauge`].
28/// Its effective type is determined by `ValueType`. This is a low-level
29/// building block used by the library to back the implementations of
30/// [`Counter`] and [`Gauge`].
31#[derive(Debug)]
32pub struct Value<P: Atomic> {
33    pub desc: Desc,
34    pub val: P,
35    pub val_type: ValueType,
36    pub label_pairs: Vec<LabelPair>,
37}
38
39impl<P: Atomic> Value<P> {
40    pub fn new<D: Describer, V: AsRef<str>>(
41        describer: &D,
42        val_type: ValueType,
43        val: P::T,
44        label_values: &[V],
45    ) -> Result<Self> {
46        let desc = describer.describe()?;
47        let label_pairs = make_label_pairs(&desc, label_values)?;
48
49        Ok(Self {
50            desc,
51            val: P::new(val),
52            val_type,
53            label_pairs,
54        })
55    }
56
57    #[inline]
58    pub fn get(&self) -> P::T {
59        self.val.get()
60    }
61
62    #[inline]
63    pub fn set(&self, val: P::T) {
64        self.val.set(val);
65    }
66
67    #[inline]
68    pub fn inc_by(&self, val: P::T) {
69        self.val.inc_by(val);
70    }
71
72    #[inline]
73    pub fn inc(&self) {
74        self.inc_by(P::T::from_i64(1));
75    }
76
77    #[inline]
78    pub fn dec(&self) {
79        self.dec_by(P::T::from_i64(1));
80    }
81
82    #[inline]
83    pub fn dec_by(&self, val: P::T) {
84        self.val.dec_by(val)
85    }
86
87    pub fn metric(&self) -> Metric {
88        let mut m = Metric::from_label(self.label_pairs.clone());
89
90        let val = self.get();
91        match self.val_type {
92            ValueType::Counter => {
93                let mut counter = Counter::default();
94                counter.set_value(val.into_f64());
95                m.set_counter(counter);
96            }
97            ValueType::Gauge => {
98                let mut gauge = Gauge::default();
99                gauge.set_value(val.into_f64());
100                m.set_gauge(gauge);
101            }
102        }
103
104        m
105    }
106
107    pub fn collect(&self) -> MetricFamily {
108        let mut m = MetricFamily::default();
109        m.set_name(self.desc.fq_name.clone());
110        m.set_help(self.desc.help.clone());
111        m.set_field_type(self.val_type.metric_type());
112        m.set_metric(vec![self.metric()]);
113        m
114    }
115}
116
117pub fn make_label_pairs<V: AsRef<str>>(desc: &Desc, label_values: &[V]) -> Result<Vec<LabelPair>> {
118    if desc.variable_labels.len() != label_values.len() {
119        return Err(Error::InconsistentCardinality {
120            expect: desc.variable_labels.len(),
121            got: label_values.len(),
122        });
123    }
124
125    let total_len = desc.variable_labels.len() + desc.const_label_pairs.len();
126    if total_len == 0 {
127        return Ok(vec![]);
128    }
129
130    if desc.variable_labels.is_empty() {
131        return Ok(desc.const_label_pairs.clone());
132    }
133
134    let mut label_pairs = Vec::with_capacity(total_len);
135    for (i, n) in desc.variable_labels.iter().enumerate() {
136        let mut label_pair = LabelPair::default();
137        label_pair.set_name(n.clone());
138        label_pair.set_value(label_values[i].as_ref().to_owned());
139        label_pairs.push(label_pair);
140    }
141
142    for label_pair in &desc.const_label_pairs {
143        label_pairs.push(label_pair.clone());
144    }
145    label_pairs.sort();
146    Ok(label_pairs)
147}