chaincodec_observability/
metrics.rs1use opentelemetry::{
7 metrics::{Counter, Histogram, Meter},
8 KeyValue,
9};
10
11#[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}