statsig_rust/sdk_diagnostics/
marker.rs

1use chrono::Utc;
2use serde::{Deserialize, Serialize};
3use std::collections::HashMap;
4
5use crate::evaluation::evaluation_details::EvaluationDetails;
6
7#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
8pub enum KeyType {
9    #[serde(rename = "initialize")]
10    Initialize,
11    #[serde(rename = "overall")]
12    Overall,
13    #[serde(rename = "download_config_specs")]
14    DownloadConfigSpecs,
15    #[serde(rename = "get_id_list")]
16    GetIDList,
17    #[serde(rename = "get_id_list_sources")]
18    GetIDListSources,
19}
20
21#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
22pub enum StepType {
23    #[serde(rename = "process")]
24    Process,
25    #[serde(rename = "network_request")]
26    NetworkRequest,
27}
28
29#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
30pub enum ActionType {
31    #[serde(rename = "start")]
32    Start,
33    #[serde(rename = "end")]
34    End,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
38#[serde(rename_all = "camelCase")]
39pub struct Marker {
40    action: ActionType,
41
42    timestamp: u64,
43
44    key: KeyType,
45
46    #[serde(skip_serializing_if = "Option::is_none")]
47    attempt: Option<u16>,
48
49    #[serde(skip_serializing_if = "Option::is_none")]
50    config_name: Option<String>,
51
52    #[serde(skip_serializing_if = "Option::is_none")]
53    error: Option<HashMap<String, String>>,
54
55    #[serde(skip_serializing_if = "Option::is_none")]
56    id_list_count: Option<u32>,
57
58    #[serde(rename = "markerID")]
59    #[serde(skip_serializing_if = "Option::is_none")]
60    marker_id: Option<String>,
61
62    #[serde(skip_serializing_if = "Option::is_none")]
63    message: Option<String>,
64
65    #[serde(skip_serializing_if = "Option::is_none")]
66    sdk_region: Option<String>,
67
68    #[serde(skip_serializing_if = "Option::is_none")]
69    status_code: Option<u16>,
70
71    #[serde(skip_serializing_if = "Option::is_none")]
72    step: Option<StepType>,
73
74    #[serde(skip_serializing_if = "Option::is_none")]
75    success: Option<bool>,
76
77    #[serde(skip_serializing_if = "Option::is_none")]
78    url: Option<String>,
79
80    #[serde(skip_serializing_if = "Option::is_none")]
81    evaluation_details: Option<EvaluationDetails>,
82}
83
84impl Marker {
85    #[must_use]
86    pub fn new(key: KeyType, action: ActionType, step: Option<StepType>) -> Self {
87        Self {
88            key,
89            action,
90            step,
91            success: None,
92            timestamp: Utc::now().timestamp_millis() as u64,
93            status_code: None,
94            url: None,
95            id_list_count: None,
96            sdk_region: None,
97            marker_id: None,
98            attempt: None,
99            config_name: None,
100            message: None,
101            error: None,
102            evaluation_details: None,
103        }
104    }
105
106    #[must_use]
107    pub fn with_is_success(mut self, success: bool) -> Self {
108        self.success = Some(success);
109        self
110    }
111
112    #[must_use]
113    pub fn with_status_code(mut self, status_code: u16) -> Self {
114        self.status_code = Some(status_code);
115        self
116    }
117
118    #[must_use]
119    pub fn with_attempt(mut self, attempt: u16) -> Self {
120        self.attempt = Some(attempt);
121        self
122    }
123
124    #[must_use]
125    pub fn with_message(mut self, message: String) -> Self {
126        self.message = Some(message);
127        self
128    }
129
130    #[must_use]
131    pub fn with_eval_details(mut self, details: EvaluationDetails) -> Self {
132        self.evaluation_details = Some(details);
133        self
134    }
135
136    // TODO add more as needed
137}
138
139// #[cfg(test)]
140// mod tests {
141//     use super::*;
142
143//     #[test]
144//     fn test_marker_new() {
145//         let timestamp: u64 = 1_640_995_200_000;
146//         let marker = Marker::new(
147//             KeyType::Initialize,
148//             ActionType::Start,
149//             Some(StepType::Process),
150//             timestamp,
151//         );
152
153//         assert_eq!(marker.key, KeyType::Initialize);
154//         assert_eq!(marker.action, ActionType::Start);
155//         assert_eq!(marker.step, Some(StepType::Process));
156//         assert_eq!(marker.success, None);
157//         assert_eq!(marker.status_code, None);
158//         assert_eq!(marker.timestamp, timestamp);
159//     }
160
161//     #[test]
162//     fn test_marker_serialization() {
163//         let timestamp: u64 = 1_640_995_200_000;
164//         let marker = Marker::new(
165//             KeyType::Initialize,
166//             ActionType::Start,
167//             Some(StepType::NetworkRequest),
168//             timestamp,
169//         )
170//         .with_is_success(true)
171//         .with_status_code(200)
172//         .with_attempt(1);
173
174//         let serialized = serde_json::to_string(&marker).expect("Failed to serialize Marker");
175//         let expected_json = r#"{"action":"start","attempt":1,"key":"initialize","statusCode":200,"step":"network_request","success":true,"timestamp":1640995200000}"#;
176
177//         assert_eq!(serialized, expected_json);
178//     }
179// }