statsig_rust/observability/
observability_client_adapter.rs1use std::{collections::HashMap, sync::Arc};
2
3use async_trait::async_trait;
4
5use crate::observability::ops_stats::OpsStatsEventObserver;
6
7use super::ops_stats::OpsStatsEvent;
8
9static HIGH_CARDINALITY_TAGS: &[&str] = &["lcut", "prev_lcut"];
10
11#[derive(Clone)]
12pub enum MetricType {
13 Increment,
14 Gauge,
15 Dist,
16}
17
18#[derive(Clone)]
19pub struct ObservabilityEvent {
20 pub metric_type: MetricType,
21 pub metric_name: String,
22 pub value: f64,
23 pub tags: Option<HashMap<String, String>>,
24}
25
26impl ObservabilityEvent {
27 pub fn new_event(
28 metric_type: MetricType,
29 metric_name: String,
30 value: f64,
31 tags: Option<HashMap<String, String>>,
32 ) -> OpsStatsEvent {
33 OpsStatsEvent::Observability(ObservabilityEvent {
34 metric_type,
35 metric_name,
36 value,
37 tags,
38 })
39 }
40}
41
42pub trait ObservabilityClient: Send + Sync + 'static + OpsStatsEventObserver {
43 fn init(&self);
44 fn increment(&self, metric_name: String, value: f64, tags: Option<HashMap<String, String>>);
45 fn gauge(&self, metric_name: String, value: f64, tags: Option<HashMap<String, String>>);
46 fn dist(&self, metric_name: String, value: f64, tags: Option<HashMap<String, String>>);
47 fn error(&self, tag: String, error: String);
48 fn should_enable_high_cardinality_for_this_tag(&self, tag: String) -> Option<bool>;
49 fn to_ops_stats_event_observer(self: Arc<Self>) -> Arc<dyn OpsStatsEventObserver>;
53}
54
55#[async_trait]
56impl<T: ObservabilityClient> OpsStatsEventObserver for T {
57 async fn handle_event(&self, event: OpsStatsEvent) {
58 match event {
59 OpsStatsEvent::Observability(data) => {
60 let tags: Option<HashMap<String, String>> = data.tags.map(|tags_unwrapped| {
61 tags_unwrapped
62 .into_iter()
63 .filter(|(key, _)| {
64 if HIGH_CARDINALITY_TAGS.contains(&key.as_str()) {
65 self.should_enable_high_cardinality_for_this_tag(key.to_string())
66 .unwrap_or_default()
67 } else {
68 true
69 }
70 })
71 .collect()
72 });
73 let metric_name = format!("statsig.sdk.{}", data.metric_name.clone());
74 match data.metric_type {
75 MetricType::Increment => self.increment(metric_name, data.value, tags),
76 MetricType::Gauge => self.gauge(metric_name, data.value, tags),
77 MetricType::Dist => self.dist(metric_name, data.value, tags),
78 };
79 }
80 OpsStatsEvent::SDKError(error) => {
81 self.error(error.tag, error.info.to_string());
82 }
83 _ => {}
84 }
85 }
86}