Skip to main content

statsig_rust/
statsig_metadata.rs

1use crate::log_e;
2use lazy_static::lazy_static;
3use parking_lot::RwLock;
4use serde::Serialize;
5use serde_json::{json, Value};
6use std::collections::HashMap;
7use uuid::Uuid;
8
9lazy_static! {
10    static ref STATSIG_METADATA: RwLock<StatsigMetadata> = RwLock::new(StatsigMetadata::new());
11}
12
13/// Canonical SDK release version embedded in shared-core metadata.
14pub const SDK_VERSION: &str = env!("CARGO_PKG_VERSION");
15
16const TAG: &str = stringify!(StatsigMetadata);
17
18#[derive(Serialize, Clone)]
19#[serde(rename_all = "camelCase")]
20pub struct StatsigMetadata {
21    pub sdk_type: String,
22    pub sdk_version: String,
23
24    #[serde(rename = "sessionID")]
25    pub session_id: String,
26
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub os: Option<String>,
29
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub arch: Option<String>,
32
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub language_version: Option<String>,
35
36    #[serde(skip_serializing_if = "Option::is_none")]
37    #[serde(rename = "service_name")]
38    pub service_name: Option<String>,
39}
40
41#[derive(Serialize, Clone)]
42#[serde(rename_all = "camelCase")]
43pub struct StatsigMetadataWithLogEventExtras {
44    #[serde(flatten)]
45    pub base: StatsigMetadata,
46
47    pub flushing_interval_ms: u64,
48    pub batch_size: usize,
49    pub max_pending_batches: usize,
50    pub flush_type: String,
51}
52
53impl StatsigMetadata {
54    fn new() -> Self {
55        Self {
56            sdk_version: SDK_VERSION.to_string(),
57            sdk_type: "statsig-server-core".to_string(),
58            session_id: Uuid::new_v4().to_string(),
59            os: None,
60            arch: None,
61            language_version: None,
62            service_name: None,
63        }
64    }
65
66    pub fn update_values(sdk_type: String, os: String, arch: String, language_version: String) {
67        match STATSIG_METADATA.try_write_for(std::time::Duration::from_secs(5)) {
68            Some(mut metadata) => {
69                metadata.sdk_type = sdk_type;
70                metadata.os = Some(os);
71                metadata.arch = Some(arch);
72                metadata.language_version = Some(language_version);
73            }
74            None => {
75                log_e!(
76                    TAG,
77                    "Failed to clone StatsigMetadata: Failed to lock STATSIG_METADATA"
78                );
79            }
80        }
81    }
82
83    pub fn update_service_name(service_name: Option<String>) {
84        match STATSIG_METADATA.try_write_for(std::time::Duration::from_secs(5)) {
85            Some(mut metadata) => {
86                metadata.service_name = service_name;
87            }
88            None => {
89                log_e!(
90                    TAG,
91                    "Failed to clone StatsigMetadata: Failed to lock STATSIG_METADATA"
92                );
93            }
94        }
95    }
96
97    #[must_use]
98    pub fn get_constant_request_headers(
99        sdk_key: &str,
100        service_name: Option<&str>,
101    ) -> HashMap<String, String> {
102        let meta = Self::get_metadata();
103
104        HashMap::from([
105            ("STATSIG-API-KEY".to_string(), sdk_key.to_string()),
106            ("STATSIG-SDK-TYPE".to_string(), meta.sdk_type),
107            ("STATSIG-SDK-VERSION".to_string(), meta.sdk_version),
108            ("STATSIG-SERVER-SESSION-ID".to_string(), meta.session_id),
109            (
110                "x-request-service".to_string(),
111                service_name.unwrap_or("unknown").to_string(),
112            ),
113        ])
114    }
115
116    #[must_use]
117    pub fn get_metadata() -> StatsigMetadata {
118        match STATSIG_METADATA.try_read_for(std::time::Duration::from_secs(5)) {
119            Some(metadata) => metadata.clone(),
120            None => {
121                log_e!(
122                    TAG,
123                    "Failed to clone StatsigMetadata: Failed to lock STATSIG_METADATA"
124                );
125                StatsigMetadata::new()
126            }
127        }
128    }
129
130    #[must_use]
131    pub fn get_as_json() -> Value {
132        json!(StatsigMetadata::get_metadata())
133    }
134
135    #[must_use]
136    pub fn get_with_log_event_extras(
137        flushing_interval_ms: u64,
138        batch_size: usize,
139        max_pending_batches: usize,
140        flush_type: String,
141    ) -> StatsigMetadataWithLogEventExtras {
142        StatsigMetadataWithLogEventExtras {
143            base: StatsigMetadata::get_metadata(),
144            flushing_interval_ms,
145            batch_size,
146            max_pending_batches,
147            flush_type,
148        }
149    }
150}