statsig_rust/
statsig_metadata.rs1use 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
13pub 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}