Skip to main content

chaincodec_observability/
metrics.rs

1//! ChainCodec metrics definitions.
2//!
3//! All metrics use OpenTelemetry conventions.
4//! They can be exported via OTLP to Prometheus, Grafana, Datadog, etc.
5
6use opentelemetry::{
7    metrics::{Counter, Histogram, Meter},
8    KeyValue,
9};
10
11/// Central metrics handle for ChainCodec.
12#[derive(Clone)]
13pub struct ChainCodecMetrics {
14    pub events_decoded: Counter<u64>,
15    pub events_skipped: Counter<u64>,
16    pub decode_errors: Counter<u64>,
17    pub decode_latency_ms: Histogram<f64>,
18    pub batch_size: Histogram<u64>,
19    pub schema_cache_hits: Counter<u64>,
20}
21
22impl ChainCodecMetrics {
23    pub fn new(meter: &Meter) -> Self {
24        Self {
25            events_decoded: meter
26                .u64_counter("chaincodec.events_decoded")
27                .with_description("Total number of successfully decoded events")
28                .init(),
29            events_skipped: meter
30                .u64_counter("chaincodec.events_skipped")
31                .with_description("Events skipped due to missing schema or filtering")
32                .init(),
33            decode_errors: meter
34                .u64_counter("chaincodec.decode_errors")
35                .with_description("Events that failed to decode")
36                .init(),
37            decode_latency_ms: meter
38                .f64_histogram("chaincodec.decode_latency_ms")
39                .with_description("Time to decode a single event in milliseconds")
40                .init(),
41            batch_size: meter
42                .u64_histogram("chaincodec.batch_size")
43                .with_description("Number of events in a batch decode request")
44                .init(),
45            schema_cache_hits: meter
46                .u64_counter("chaincodec.schema_cache_hits")
47                .with_description("Registry fingerprint lookup cache hits")
48                .init(),
49        }
50    }
51
52    pub fn record_decoded(&self, chain: &str, schema: &str) {
53        self.events_decoded.add(
54            1,
55            &[
56                KeyValue::new("chain", chain.to_string()),
57                KeyValue::new("schema", schema.to_string()),
58            ],
59        );
60    }
61
62    pub fn record_error(&self, chain: &str, error_type: &str) {
63        self.decode_errors.add(
64            1,
65            &[
66                KeyValue::new("chain", chain.to_string()),
67                KeyValue::new("error_type", error_type.to_string()),
68            ],
69        );
70    }
71
72    pub fn record_latency(&self, ms: f64, chain: &str) {
73        self.decode_latency_ms
74            .record(ms, &[KeyValue::new("chain", chain.to_string())]);
75    }
76}