1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use std::collections::HashMap;

use prometheus_client::{
    encoding::{DescriptorEncoder, EncodeMetric},
    metrics::{counter::ConstCounter, gauge::ConstGauge, info::Info},
    registry::{Registry, Unit},
};

pub trait EncodeExt {
    fn encode_e(
        &self,
        encoder: &mut DescriptorEncoder,
        name: &str,
        help: &str,
    ) -> Result<(), std::fmt::Error>;

    fn encode_e_unit(
        &self,
        encoder: &mut DescriptorEncoder,
        name: &str,
        help: &str,
        unit: &Unit,
    ) -> Result<(), std::fmt::Error>;
}

impl<T> EncodeExt for T
where
    T: EncodeMetric,
{
    fn encode_e(
        &self,
        encoder: &mut DescriptorEncoder,
        name: &str,
        help: &str,
    ) -> Result<(), std::fmt::Error> {
        self.encode(encoder.encode_descriptor(name, help, None, self.metric_type())?)
    }

    fn encode_e_unit(
        &self,
        encoder: &mut DescriptorEncoder,
        name: &str,
        help: &str,
        unit: &Unit,
    ) -> Result<(), std::fmt::Error> {
        self.encode(encoder.encode_descriptor(name, help, Some(unit), self.metric_type())?)
    }
}

pub(crate) trait AsMetrics {
    fn register_as_metrics(self: Box<Self>, registry: &mut Registry);
}

pub fn encode_extra(
    encoder: &mut DescriptorEncoder,
    extra: &HashMap<String, String>,
    mut info_fields: Vec<(String, String)>,
    blacklist: &[&str],
) -> Result<(), std::fmt::Error> {
    for (key, val) in extra
        .iter()
        .filter(|(k, _)| !blacklist.contains(&&***k))
        .map(|(k, v)| (k.replace('-', "_"), v))
    {
        if let Ok(num) = val.parse::<f64>() {
            if key.ends_with("_packet") || key.ends_with("_drop") || key.ends_with("byte") {
                ConstCounter::new(num).encode_e(encoder, &key, "")?;
            } else {
                ConstGauge::new(num).encode_e(encoder, &key, "")?;
            }
            continue;
        }

        if let Ok(bool) = val.parse::<bool>() {
            ConstGauge::new(i64::from(bool)).encode_e(encoder, &key, "")?;
            continue;
        }

        info_fields.push((key, val.clone()));
    }

    Info::new(info_fields).encode_e(encoder, "", "")?;

    Ok(())
}