Skip to main content

statsig_rust/networking/
network_error.rs

1use serde::Serialize;
2use std::fmt;
3
4use crate::logging_utils::sanitize_secret_key;
5
6type RequestUrl = String;
7
8#[derive(PartialEq, Debug, Clone, Serialize)]
9pub enum NetworkError {
10    ShutdownError(RequestUrl),
11    DisableNetworkOn(RequestUrl),
12    SerializationError(RequestUrl, String),
13
14    RequestFailed(RequestUrl, Option<u16>, String),
15    RetriesExhausted(RequestUrl, Option<u16>, u32, String),
16    RequestNotRetryable(RequestUrl, Option<u16>, String),
17}
18
19impl NetworkError {
20    pub fn name(&self) -> &'static str {
21        match self {
22            NetworkError::ShutdownError(_) => "ShutdownError",
23            NetworkError::DisableNetworkOn(_) => "DisableNetworkOn",
24            NetworkError::SerializationError(_, _) => "SerializationError",
25            NetworkError::RequestFailed(_, _, _) => "RequestFailed",
26            NetworkError::RetriesExhausted(_, _, _, _) => "RetriesExhausted",
27            NetworkError::RequestNotRetryable(_, _, _) => "RequestNotRetryable",
28        }
29    }
30
31    pub fn status_code(&self) -> Option<u16> {
32        match self {
33            NetworkError::RequestFailed(_, status, _)
34            | NetworkError::RetriesExhausted(_, status, _, _)
35            | NetworkError::RequestNotRetryable(_, status, _) => *status,
36            _ => None,
37        }
38    }
39}
40
41impl fmt::Display for NetworkError {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            NetworkError::ShutdownError(url) => {
45                let url = sanitize_secret_key(url);
46                write!(f, "ShutdownError: {url}")
47            }
48            NetworkError::DisableNetworkOn(url) => {
49                let url = sanitize_secret_key(url);
50                write!(f, "DisableNetworkOn: {url}")
51            }
52            NetworkError::SerializationError(url, s) => {
53                let url = sanitize_secret_key(url);
54                let s = sanitize_secret_key(s);
55                write!(f, "SerializationError: {url} {s}")
56            }
57
58            NetworkError::RequestFailed(url, status, message) => {
59                let url = sanitize_secret_key(url);
60                let message = sanitize_secret_key(message);
61                let status_display = match status {
62                    Some(code) => code.to_string(),
63                    None => "None".to_string(),
64                };
65                write!(f, "RequestFailed: {url} {status_display} {message}")
66            }
67            NetworkError::RetriesExhausted(url, status, attempts, message) => {
68                let url = sanitize_secret_key(url);
69                let message = sanitize_secret_key(message);
70                let status_display = match status {
71                    Some(code) => code.to_string(),
72                    None => "None".to_string(),
73                };
74                write!(
75                    f,
76                    "RetriesExhausted: {url} status({status_display}) attempts({attempts}) {message}"
77                )
78            }
79            NetworkError::RequestNotRetryable(url, status, message) => {
80                let url = sanitize_secret_key(url);
81                let message = sanitize_secret_key(message);
82                let status_display = match status {
83                    Some(code) => code.to_string(),
84                    None => "None".to_string(),
85                };
86                write!(
87                    f,
88                    "RequestNotRetryable: {url} status({status_display}) {message}"
89                )
90            }
91        }
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98
99    #[test]
100    fn test_sanitize_secret_key_in_error_display() {
101        let err = NetworkError::RetriesExhausted(
102            "https://statsigcdn.openai.com/v2/download_config_specs/secret-fakeO1234567890.json"
103                .to_string(),
104            None,
105            1,
106            "Invalid array length".to_string(),
107        );
108
109        let message = err.to_string();
110        assert!(message.contains("secret-fakeO*****.json"));
111        assert!(!message.contains("secret-fakeO1234567890"));
112    }
113}