bothan_lib/metrics/store.rs
1//! Metrics collection for store operations.
2//!
3//! This module provides the [`Metrics`] struct and related types for tracking store operation statistics
4//! such as the number of operations and their execution durations. It leverages OpenTelemetry for metrics
5//! instrumentation, supporting monitoring and observability.
6
7use opentelemetry::metrics::{Counter, Histogram};
8use opentelemetry::{KeyValue, global};
9use strum_macros::Display;
10
11/// Holds counters and histograms for store operation metrics.
12#[derive(Clone, Debug)]
13pub struct Metrics {
14 /// Counter tracking total store operations.
15 operations_total: Counter<u64>,
16
17 /// Histogram recording operation durations in microseconds.
18 operation_duration: Histogram<u64>,
19}
20
21impl Default for Metrics {
22 fn default() -> Self {
23 Self::new()
24 }
25}
26
27impl Metrics {
28 /// Creates a new [`Metrics`] instance configured for the store.
29 ///
30 /// # Examples
31 ///
32 /// ```rust
33 /// use bothan_lib::metrics::store::{Metrics, Operation, OperationStatus};
34 ///
35 /// let metrics = Metrics::new();
36 /// metrics.update_store_operation("source".to_string(), 100, Operation::GetAssetInfo, OperationStatus::Success);
37 /// ```
38 pub fn new() -> Self {
39 let meter = global::meter("store");
40
41 let operations_total = meter
42 .u64_counter("store_operations")
43 .with_description("Total number of operations executed by the store")
44 .build();
45 let operation_duration = meter
46 .u64_histogram("store_operation_duration_microseconds")
47 .with_description("Time taken to execute each store operation")
48 .with_unit("microseconds")
49 .build();
50
51 Self {
52 operations_total,
53 operation_duration,
54 }
55 }
56
57 /// Records a store operation result and duration.
58 ///
59 /// # Arguments
60 ///
61 /// * `source` - The source of the operation.
62 /// * `elapsed_time` - Duration of the operation in microseconds.
63 /// * `operation` - The type of operation performed.
64 /// * `status` - The result of the operation.
65 pub fn update_store_operation(
66 &self,
67 source: String,
68 elapsed_time: u128,
69 operation: Operation,
70 status: OperationStatus,
71 ) {
72 let labels = &[
73 KeyValue::new("source", source),
74 KeyValue::new("operation", operation.to_string()),
75 KeyValue::new("status", status.to_string()),
76 ];
77 self.operations_total.add(1, labels);
78 // `elapsed_time` is u128, but it will never exceed u64::MAX in practice
79 self.operation_duration.record(elapsed_time as u64, labels);
80 }
81}
82
83/// Possible store operations.
84#[derive(Display)]
85#[strum(serialize_all = "snake_case")]
86pub enum Operation {
87 /// Retrieve asset information from the store.
88 GetAssetInfo,
89 /// Insert a batch of asset information into the store.
90 InsertBatchAssetInfo,
91}
92
93/// Possible results for a store operation.
94#[derive(Display)]
95#[strum(serialize_all = "snake_case")]
96pub enum OperationStatus {
97 /// The operation completed successfully.
98 Success,
99 /// The operation completed but the data was stale.
100 Stale,
101 /// The requested data was not found.
102 NotFound,
103 /// The operation failed.
104 Failed,
105}