bothan_lib/metrics/
server.rs

1//! Metrics collection for gRPC server operations.
2//!
3//! This module provides the [`Metrics`] struct and related types for tracking gRPC server statistics
4//! such as the number of requests and their processing 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;
10use tonic::Code;
11
12use crate::metrics::utils::code_to_str;
13
14/// Holds counters and histograms for gRPC server metrics.
15#[derive(Clone, Debug)]
16pub struct Metrics {
17    /// Counter tracking total server requests.
18    requests_total: Counter<u64>,
19
20    /// Histogram recording request durations in milliseconds.
21    request_duration: Histogram<f64>,
22}
23
24impl Default for Metrics {
25    fn default() -> Self {
26        Self::new()
27    }
28}
29
30impl Metrics {
31    /// Creates a new [`Metrics`] instance configured for the gRPC server.
32    ///
33    /// # Examples
34    ///
35    /// ```rust
36    /// use bothan_lib::metrics::server::Metrics;
37    /// use bothan_lib::metrics::server::ServiceName;
38    /// use tonic::Code;
39    ///
40    /// let metrics = Metrics::new();
41    /// metrics.update_server_request(42.0, ServiceName::GetInfo, Code::Ok);
42    /// ```
43    pub fn new() -> Self {
44        let meter = global::meter("server");
45
46        let requests_total = meter
47            .u64_counter("server_requests")
48            .with_description("Total number of requests sent to the server")
49            .build();
50        let request_duration = meter
51            .f64_histogram("server_request_duration_milliseconds")
52            .with_description("Time taken to process each request sent to the server")
53            .with_unit("milliseconds")
54            .build();
55
56        Self {
57            requests_total,
58            request_duration,
59        }
60    }
61
62    /// Records a server request result and duration.
63    ///
64    /// # Arguments
65    ///
66    /// * `elapsed_time` - Duration of the request in milliseconds.
67    /// * `service_name` - The gRPC service being called.
68    /// * `grpc_code` - The gRPC status code returned.
69    pub fn update_server_request(
70        &self,
71        elapsed_time: f64,
72        service_name: ServiceName,
73        grpc_code: Code,
74    ) {
75        let labels = &[
76            KeyValue::new("service_name", service_name.to_string()),
77            KeyValue::new("status", code_to_str(grpc_code)),
78        ];
79        self.requests_total.add(1, labels);
80        self.request_duration.record(elapsed_time, labels);
81    }
82}
83
84/// Possible gRPC service endpoints for server requests.
85#[derive(Display)]
86#[strum(serialize_all = "snake_case")]
87pub enum ServiceName {
88    /// Get information from the server.
89    GetInfo,
90    /// Update the registry on the server.
91    UpdateRegistry,
92    /// Push monitoring records to the server.
93    PushMonitoringRecords,
94    /// Get price data from the server.
95    GetPrices,
96}