statsig_rust/networking/
network_error.rs1use 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}