sentinel_proxy/proxy/
model_routing_metrics.rs1use anyhow::{Context, Result};
9use once_cell::sync::OnceCell;
10use prometheus::{register_int_counter_vec, IntCounterVec};
11use std::sync::Arc;
12
13static MODEL_ROUTING_METRICS: OnceCell<Arc<ModelRoutingMetrics>> = OnceCell::new();
15
16pub fn get_model_routing_metrics() -> Option<Arc<ModelRoutingMetrics>> {
18 MODEL_ROUTING_METRICS.get().cloned()
19}
20
21pub fn init_model_routing_metrics() -> Result<Arc<ModelRoutingMetrics>> {
24 if let Some(metrics) = MODEL_ROUTING_METRICS.get() {
25 return Ok(metrics.clone());
26 }
27
28 let metrics = Arc::new(ModelRoutingMetrics::new()?);
29 let _ = MODEL_ROUTING_METRICS.set(metrics.clone());
30 Ok(metrics)
31}
32
33pub struct ModelRoutingMetrics {
37 model_routed: IntCounterVec,
40
41 default_upstream_used: IntCounterVec,
44
45 no_model_header: IntCounterVec,
48
49 provider_override: IntCounterVec,
52}
53
54impl ModelRoutingMetrics {
55 pub fn new() -> Result<Self> {
57 let model_routed = register_int_counter_vec!(
58 "sentinel_model_routing_total",
59 "Total number of requests routed based on model name",
60 &["route", "model", "upstream"]
61 )
62 .context("Failed to register model_routing metric")?;
63
64 let default_upstream_used = register_int_counter_vec!(
65 "sentinel_model_routing_default_total",
66 "Requests falling back to default upstream (no pattern matched)",
67 &["route"]
68 )
69 .context("Failed to register model_routing_default metric")?;
70
71 let no_model_header = register_int_counter_vec!(
72 "sentinel_model_routing_no_header_total",
73 "Requests with no model header detected",
74 &["route"]
75 )
76 .context("Failed to register model_routing_no_header metric")?;
77
78 let provider_override = register_int_counter_vec!(
79 "sentinel_model_routing_provider_override_total",
80 "Requests where provider was overridden by model routing",
81 &["route", "upstream", "provider"]
82 )
83 .context("Failed to register model_routing_provider_override metric")?;
84
85 Ok(Self {
86 model_routed,
87 default_upstream_used,
88 no_model_header,
89 provider_override,
90 })
91 }
92
93 pub fn record_model_routed(&self, route: &str, model: &str, upstream: &str) {
97 self.model_routed
98 .with_label_values(&[route, model, upstream])
99 .inc();
100 }
101
102 pub fn record_default_upstream(&self, route: &str) {
106 self.default_upstream_used
107 .with_label_values(&[route])
108 .inc();
109 }
110
111 pub fn record_no_model_header(&self, route: &str) {
115 self.no_model_header.with_label_values(&[route]).inc();
116 }
117
118 pub fn record_provider_override(&self, route: &str, upstream: &str, provider: &str) {
122 self.provider_override
123 .with_label_values(&[route, upstream, provider])
124 .inc();
125 }
126}