Skip to main content

brokapi_runtime/
metrics.rs

1//! Runtime counters (structure only, no exporter).
2
3use std::time::Duration;
4
5/// A plain set of counters about the connector runtime.
6///
7/// It is a snapshot-style struct for the owner to fill and read. The runtime does not update it by
8/// itself and there is no exporter. All counts start at zero and only grow.
9///
10/// # Examples
11///
12/// ```
13/// use brokapi_runtime::RuntimeMetrics;
14///
15/// let mut m = RuntimeMetrics::new();
16/// m.record_rate_limit("orders");
17/// m.record_rate_limit("orders");
18/// m.record_rate_limit("global");
19/// assert_eq!(m.rate_limit_hits, 3);
20/// assert_eq!(m.rate_limit_by_bucket, vec![("orders".to_string(), 2), ("global".to_string(), 1)]);
21/// ```
22#[derive(Debug, Clone, Default, PartialEq, Eq)]
23pub struct RuntimeMetrics {
24    /// Number of resyncs recorded with [`record_resync`](Self::record_resync).
25    pub resync_count: u64,
26    /// Number of sequence gaps recorded with [`record_seq_gap`](Self::record_seq_gap).
27    pub seq_gaps: u64,
28    /// Number of orders that entered the `Unknown` state. The owner counts them, no method here does.
29    pub unknown_orders: u64,
30    /// Milliseconds spent resolving `Unknown` orders. The owner decides how to sum it, the runtime
31    /// does not fill it.
32    pub unknown_resolved_ms: u64,
33    /// Number of calls refused by the rate limiter.
34    pub rate_limit_hits: u64,
35    /// The same refusals split by bucket name, in order of first appearance.
36    pub rate_limit_by_bucket: Vec<(String, u64)>,
37    /// Events replaced by newer ones in `Conflate` buffers, added with [`record_conflated`](Self::record_conflated).
38    pub buffer_conflated: u64,
39    /// Events thrown away by `DropNewest` buffers, added with [`record_dropped`](Self::record_dropped).
40    pub buffer_dropped: u64,
41    /// Overflows of `Lossless` buffers, counted with [`record_overflow`](Self::record_overflow).
42    pub buffer_overflow: u64,
43    /// Median time from parsing an event to handing it to the consumer. Not filled by the runtime.
44    pub egress_latency_p50_ms: Duration,
45    /// 99th percentile of the same time. Not filled by the runtime.
46    pub egress_latency_p99_ms: Duration,
47}
48
49impl RuntimeMetrics {
50    /// Creates a zeroed set. Same as [`Default::default`].
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    /// Adds one to [`resync_count`](Self::resync_count).
56    pub fn record_resync(&mut self) {
57        self.resync_count += 1;
58    }
59
60    /// Adds one to [`seq_gaps`](Self::seq_gaps).
61    pub fn record_seq_gap(&mut self) {
62        self.seq_gaps += 1;
63    }
64
65    /// Counts one rate-limit refusal, in total and for `bucket`.
66    pub fn record_rate_limit(&mut self, bucket: &str) {
67        self.rate_limit_hits += 1;
68        if let Some(entry) = self
69            .rate_limit_by_bucket
70            .iter_mut()
71            .find(|(b, _)| b == bucket)
72        {
73            entry.1 += 1;
74        } else {
75            self.rate_limit_by_bucket.push((bucket.to_string(), 1));
76        }
77    }
78
79    /// Adds `n` to [`buffer_conflated`](Self::buffer_conflated).
80    pub fn record_conflated(&mut self, n: u64) {
81        self.buffer_conflated += n;
82    }
83
84    /// Adds `n` to [`buffer_dropped`](Self::buffer_dropped).
85    pub fn record_dropped(&mut self, n: u64) {
86        self.buffer_dropped += n;
87    }
88
89    /// Adds one to [`buffer_overflow`](Self::buffer_overflow).
90    pub fn record_overflow(&mut self) {
91        self.buffer_overflow += 1;
92    }
93}