Skip to main content

hyperi_rustlib/metrics/dfe_groups/
schema_cache.rs

1// Project:   hyperi-rustlib
2// File:      src/metrics/dfe_groups/schema_cache.rs
3// Purpose:   DFE schema cache metrics group
4// Language:  Rust
5//
6// License:   FSL-1.1-ALv2
7// Copyright: (c) 2026 HYPERI PTY LIMITED
8
9//! Schema cache metrics for apps with dynamic schema reflection.
10
11use metrics::{Counter, Gauge};
12
13use super::super::MetricsManager;
14use super::super::manifest::{MetricDescriptor, MetricType};
15
16/// Schema cache metrics.
17///
18/// Tracks cache hit/miss rates, cached table count, and schema recovery events.
19#[derive(Clone)]
20pub struct SchemaCacheMetrics {
21    pub hits: Counter,
22    pub misses: Counter,
23    pub tables: Gauge,
24    namespace: String,
25}
26
27impl SchemaCacheMetrics {
28    #[must_use]
29    pub fn new(manager: &MetricsManager) -> Self {
30        let ns = manager.namespace();
31
32        // schema_recovery_total -- label-based, register descriptor manually
33        let recovery_key = if ns.is_empty() {
34            "schema_recovery_total".to_string()
35        } else {
36            format!("{ns}_schema_recovery_total")
37        };
38        metrics::describe_counter!(recovery_key.clone(), "Schema mismatch recovery events");
39        manager.registry().push(MetricDescriptor {
40            name: recovery_key,
41            metric_type: MetricType::Counter,
42            description: "Schema mismatch recovery events".into(),
43            unit: String::new(),
44            labels: vec!["table".into()],
45            group: "schema_cache".into(),
46            buckets: None,
47            use_cases: vec![],
48            dashboard_hint: None,
49        });
50
51        Self {
52            hits: manager.counter_with_labels(
53                "schema_cache_hits_total",
54                "Schema cache hits",
55                &[],
56                "schema_cache",
57            ),
58            misses: manager.counter_with_labels(
59                "schema_cache_misses_total",
60                "Schema cache misses (triggers fetch)",
61                &[],
62                "schema_cache",
63            ),
64            tables: manager.gauge_with_labels(
65                "schema_cache_tables",
66                "Number of cached table schemas",
67                &[],
68                "schema_cache",
69            ),
70            namespace: ns.to_string(),
71        }
72    }
73
74    #[inline]
75    pub fn record_hit(&self) {
76        self.hits.increment(1);
77    }
78
79    #[inline]
80    pub fn record_miss(&self) {
81        self.misses.increment(1);
82    }
83
84    #[inline]
85    pub fn set_tables(&self, count: usize) {
86        self.tables.set(count as f64);
87    }
88
89    /// Record a schema recovery event for a specific table.
90    #[inline]
91    pub fn record_recovery(&self, table: &str) {
92        let key = if self.namespace.is_empty() {
93            "schema_recovery_total".to_string()
94        } else {
95            format!("{}_schema_recovery_total", self.namespace)
96        };
97        metrics::counter!(key, "table" => table.to_string()).increment(1);
98    }
99}