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>(
41        describer: &D,
42        val_type: ValueType,
43        val: P::T,
44        label_values: &[&str],
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::default();
89        m.set_label(from_vec!(self.label_pairs.clone()));
90
91        let val = self.get();
92        match self.val_type {
93            ValueType::Counter => {
94                let mut counter = Counter::default();
95                counter.set_value(val.into_f64());
96                m.set_counter(counter);
97            }
98            ValueType::Gauge => {
99                let mut gauge = Gauge::default();
100                gauge.set_value(val.into_f64());
101                m.set_gauge(gauge);
102            }
103        }
104
105        m
106    }
107
108    pub fn collect(&self) -> MetricFamily {
109        let mut m = MetricFamily::default();
110        m.set_name(self.desc.fq_name.clone());
111        m.set_help(self.desc.help.clone());
112        m.set_field_type(self.val_type.metric_type());
113        m.set_metric(from_vec!(vec![self.metric()]));
114        m
115    }
116}
117
118pub fn make_label_pairs(desc: &Desc, label_values: &[&str]) -> Result<Vec<LabelPair>> {
119    if desc.variable_labels.len() != label_values.len() {
120        return Err(Error::InconsistentCardinality {
121            expect: desc.variable_labels.len(),
122            got: label_values.len(),
123        });
124    }
125
126    let total_len = desc.variable_labels.len() + desc.const_label_pairs.len();
127    if total_len == 0 {
128        return Ok(vec![]);
129    }
130
131    if desc.variable_labels.is_empty() {
132        return Ok(desc.const_label_pairs.clone());
133    }
134
135    let mut label_pairs = Vec::with_capacity(total_len);
136    for (i, n) in desc.variable_labels.iter().enumerate() {
137        let mut label_pair = LabelPair::default();
138        label_pair.set_name(n.clone());
139        label_pair.set_value(label_values[i].to_owned());
140        label_pairs.push(label_pair);
141    }
142
143    for label_pair in &desc.const_label_pairs {
144        label_pairs.push(label_pair.clone());
145    }
146    label_pairs.sort();
147    Ok(label_pairs)
148}