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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use std::collections::HashMap;

use substrate_prometheus_endpoint::{
    exponential_buckets, prometheus::HistogramTimer, register, CounterVec, Histogram,
    HistogramOpts, Opts, PrometheusError, Registry, U64,
};

use crate::Protocol;

fn protocol_name(protocol: Protocol) -> &'static str {
    use Protocol::*;
    match protocol {
        Authentication => "authentication",
        BlockSync => "block_sync",
    }
}

#[derive(Clone)]
pub enum Metrics {
    Prometheus {
        send_times: HashMap<Protocol, Histogram>,
        peer_sender_queue_size: CounterVec<U64>,
    },
    Noop,
}

impl Metrics {
    pub fn new(registry: Option<Registry>) -> Result<Self, PrometheusError> {
        use Protocol::*;
        let registry = match registry {
            Some(registry) => registry,
            None => return Ok(Metrics::Noop),
        };

        let mut send_times = HashMap::new();
        for protocol in [Authentication, BlockSync] {
            send_times.insert(
                protocol,
                register(
                    Histogram::with_opts(HistogramOpts {
                        common_opts: Opts {
                            namespace: "gossip_network".to_string(),
                            subsystem: protocol_name(protocol).to_string(),
                            name: "send_duration".to_string(),
                            help: "How long did it take for substrate to send a message."
                                .to_string(),
                            const_labels: Default::default(),
                            variable_labels: Default::default(),
                        },
                        buckets: exponential_buckets(0.001, 1.26, 30)?,
                    })?,
                    &registry,
                )?,
            );
        }

        let peer_sender_queue_size = register(CounterVec::new(
            Opts::new(
                "gossip_network_peer_sender_queue",
                "Total number of messages sent and received by peer sender queues for all peers, for a given protocol",
            ),
            &["protocol", "action"],
        )?, &registry)?;

        Ok(Metrics::Prometheus {
            send_times,
            peer_sender_queue_size,
        })
    }

    pub fn noop() -> Self {
        Metrics::Noop
    }

    pub fn start_sending_in(&self, protocol: Protocol) -> Option<HistogramTimer> {
        match self {
            Metrics::Prometheus { send_times, .. } => send_times
                .get(&protocol)
                .map(|histogram| histogram.start_timer()),
            Metrics::Noop => None,
        }
    }

    pub fn report_message_pushed_to_peer_sender_queue(&self, protocol: Protocol) {
        match self {
            Metrics::Prometheus {
                peer_sender_queue_size,
                ..
            } => {
                peer_sender_queue_size
                    .with_label_values(&[protocol_name(protocol), "send"])
                    .inc();
            }
            Metrics::Noop => {}
        }
    }

    pub fn report_message_popped_from_peer_sender_queue(&self, protocol: Protocol) {
        match self {
            Metrics::Prometheus {
                peer_sender_queue_size,
                ..
            } => {
                peer_sender_queue_size
                    .with_label_values(&[protocol_name(protocol), "received"])
                    .inc();
            }
            Metrics::Noop => {}
        }
    }
}