use crate::atomic64::{Atomic, Number};
use crate::desc::{Desc, Describer};
use crate::errors::{Error, Result};
use crate::proto::{Counter, Gauge, LabelPair, Metric, MetricFamily, MetricType};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ValueType {
Counter,
Gauge,
}
impl ValueType {
pub fn metric_type(self) -> MetricType {
match self {
ValueType::Counter => MetricType::COUNTER,
ValueType::Gauge => MetricType::GAUGE,
}
}
}
#[derive(Debug)]
pub struct Value<P: Atomic> {
pub desc: Desc,
pub val: P,
pub val_type: ValueType,
pub label_pairs: Vec<LabelPair>,
}
impl<P: Atomic> Value<P> {
pub fn new<D: Describer>(
describer: &D,
val_type: ValueType,
val: P::T,
label_values: &[&str],
) -> Result<Self> {
let desc = describer.describe()?;
let label_pairs = make_label_pairs(&desc, label_values)?;
Ok(Self {
desc,
val: P::new(val),
val_type,
label_pairs,
})
}
#[inline]
pub fn get(&self) -> P::T {
self.val.get()
}
#[inline]
pub fn set(&self, val: P::T) {
self.val.set(val);
}
#[inline]
pub fn inc_by(&self, val: P::T) {
self.val.inc_by(val);
}
#[inline]
pub fn inc(&self) {
self.inc_by(P::T::from_i64(1));
}
#[inline]
pub fn dec(&self) {
self.dec_by(P::T::from_i64(1));
}
#[inline]
pub fn dec_by(&self, val: P::T) {
self.val.dec_by(val)
}
pub fn metric(&self) -> Metric {
let mut m = Metric::default();
m.set_label(from_vec!(self.label_pairs.clone()));
let val = self.get();
match self.val_type {
ValueType::Counter => {
let mut counter = Counter::default();
counter.set_value(val.into_f64());
m.set_counter(counter);
}
ValueType::Gauge => {
let mut gauge = Gauge::default();
gauge.set_value(val.into_f64());
m.set_gauge(gauge);
}
}
m
}
pub fn collect(&self) -> MetricFamily {
let mut m = MetricFamily::default();
m.set_name(self.desc.fq_name.clone());
m.set_help(self.desc.help.clone());
m.set_field_type(self.val_type.metric_type());
m.set_metric(from_vec!(vec![self.metric()]));
m
}
}
pub fn make_label_pairs(desc: &Desc, label_values: &[&str]) -> Result<Vec<LabelPair>> {
if desc.variable_labels.len() != label_values.len() {
return Err(Error::InconsistentCardinality {
expect: desc.variable_labels.len(),
got: label_values.len(),
});
}
let total_len = desc.variable_labels.len() + desc.const_label_pairs.len();
if total_len == 0 {
return Ok(vec![]);
}
if desc.variable_labels.is_empty() {
return Ok(desc.const_label_pairs.clone());
}
let mut label_pairs = Vec::with_capacity(total_len);
for (i, n) in desc.variable_labels.iter().enumerate() {
let mut label_pair = LabelPair::default();
label_pair.set_name(n.clone());
label_pair.set_value(label_values[i].to_owned());
label_pairs.push(label_pair);
}
for label_pair in &desc.const_label_pairs {
label_pairs.push(label_pair.clone());
}
label_pairs.sort();
Ok(label_pairs)
}