1use 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#[derive(Debug, Copy, Clone, Eq, PartialEq)]
12pub enum ValueType {
13 Counter,
14 Gauge,
15}
16
17impl ValueType {
18 pub fn metric_type(self) -> MetricType {
20 match self {
21 ValueType::Counter => MetricType::COUNTER,
22 ValueType::Gauge => MetricType::GAUGE,
23 }
24 }
25}
26
27#[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}