1use prometheus_client::{
22 encoding::{EncodeLabelSet, EncodeLabelValue},
23 metrics::{
24 counter::Counter,
25 family::Family,
26 histogram::{exponential_buckets, Histogram},
27 },
28 registry::{Registry, Unit},
29};
30
31#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelSet, Debug)]
32struct FailureLabels {
33 reason: Failure,
34}
35
36impl From<&libp2p_ping::Failure> for FailureLabels {
37 fn from(failure: &libp2p_ping::Failure) -> Self {
38 match failure {
39 libp2p_ping::Failure::Timeout => FailureLabels {
40 reason: Failure::Timeout,
41 },
42 libp2p_ping::Failure::Unsupported => FailureLabels {
43 reason: Failure::Unsupported,
44 },
45 libp2p_ping::Failure::Other { .. } => FailureLabels {
46 reason: Failure::Other,
47 },
48 }
49 }
50}
51
52#[derive(Clone, Hash, PartialEq, Eq, EncodeLabelValue, Debug)]
53enum Failure {
54 Timeout,
55 Unsupported,
56 Other,
57}
58
59pub(crate) struct Metrics {
60 rtt: Histogram,
61 failure: Family<FailureLabels, Counter>,
62}
63
64impl Metrics {
65 pub(crate) fn new(registry: &mut Registry) -> Self {
66 let sub_registry = registry.sub_registry_with_prefix("ping");
67
68 let rtt = Histogram::new(exponential_buckets(0.001, 2.0, 12));
69 sub_registry.register_with_unit(
70 "rtt",
71 "Round-trip time sending a 'ping' and receiving a 'pong'",
72 Unit::Seconds,
73 rtt.clone(),
74 );
75
76 let failure = Family::default();
77 sub_registry.register(
78 "failure",
79 "Failure while sending a 'ping' or receiving a 'pong'",
80 failure.clone(),
81 );
82
83 Self { rtt, failure }
84 }
85}
86
87impl super::Recorder<libp2p_ping::Event> for Metrics {
88 fn record(&self, event: &libp2p_ping::Event) {
89 match &event.result {
90 Ok(rtt) => {
91 self.rtt.observe(rtt.as_secs_f64());
92 }
93 Err(failure) => {
94 self.failure.get_or_create(&failure.into()).inc();
95 }
96 }
97 }
98}