betterstack_tracing/
error.rs

1/// Error types for the tracing-betterstack crate
2use std::fmt;
3
4/// Result type alias for Betterstack operations
5pub type Result<T> = std::result::Result<T, BetterstackError>;
6
7/// Errors that can occur when working with Betterstack
8#[derive(Debug)]
9pub enum BetterstackError {
10    /// Configuration validation error
11    ConfigError(String),
12
13    /// HTTP client or network error
14    SendError(String),
15
16    /// JSON serialization error
17    SerializationError(serde_json::Error),
18
19    /// HTTP request construction error
20    HttpError(reqwest::Error),
21}
22
23impl fmt::Display for BetterstackError {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        match self {
26            BetterstackError::ConfigError(msg) => write!(f, "Configuration error: {}", msg),
27            BetterstackError::SendError(msg) => write!(f, "Send error: {}", msg),
28            BetterstackError::SerializationError(err) => write!(f, "Serialization error: {}", err),
29            BetterstackError::HttpError(err) => write!(f, "HTTP error: {}", err),
30        }
31    }
32}
33
34impl std::error::Error for BetterstackError {
35    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
36        match self {
37            BetterstackError::SerializationError(err) => Some(err),
38            BetterstackError::HttpError(err) => Some(err),
39            _ => None,
40        }
41    }
42}
43
44impl From<serde_json::Error> for BetterstackError {
45    fn from(err: serde_json::Error) -> Self {
46        BetterstackError::SerializationError(err)
47    }
48}
49
50impl From<reqwest::Error> for BetterstackError {
51    fn from(err: reqwest::Error) -> Self {
52        BetterstackError::HttpError(err)
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59    use std::error::Error;
60
61    #[test]
62    fn test_config_error_display() {
63        let err = BetterstackError::ConfigError("invalid token".to_string());
64        assert_eq!(err.to_string(), "Configuration error: invalid token");
65    }
66
67    #[test]
68    fn test_send_error_display() {
69        let err = BetterstackError::SendError("connection failed".to_string());
70        assert_eq!(err.to_string(), "Send error: connection failed");
71    }
72
73    #[test]
74    fn test_serialization_error_conversion() {
75        let json_err = serde_json::from_str::<i32>("not a number").unwrap_err();
76        let err: BetterstackError = json_err.into();
77        assert!(matches!(err, BetterstackError::SerializationError(_)));
78    }
79
80    #[test]
81    fn test_error_source_method() {
82        // Test that source() returns correct underlying errors
83
84        // ConfigError and SendError have no source
85        let config_err = BetterstackError::ConfigError("test".to_string());
86        assert!(config_err.source().is_none());
87
88        let send_err = BetterstackError::SendError("test".to_string());
89        assert!(send_err.source().is_none());
90
91        // SerializationError has source
92        let json_err = serde_json::from_str::<i32>("not a number").unwrap_err();
93        let ser_err = BetterstackError::SerializationError(json_err);
94        assert!(ser_err.source().is_some());
95
96        // HttpError has source (we can't easily create a reqwest error, so we'll skip that part)
97        // The important part is that the source() method is implemented correctly
98    }
99
100    #[tokio::test]
101    async fn test_http_error_display() {
102        // Create an actual HTTP error by attempting to connect to an invalid address
103        // This will generate a real reqwest::Error
104        let client = reqwest::Client::builder()
105            .timeout(std::time::Duration::from_millis(100))
106            .build()
107            .unwrap();
108
109        // Try to connect to a non-routable address - this will definitely fail
110        let result = client.get("http://0.0.0.0:1").send().await;
111        assert!(result.is_err());
112
113        let reqwest_err = result.unwrap_err();
114        let err = BetterstackError::HttpError(reqwest_err);
115
116        let display_str = err.to_string();
117        assert!(display_str.contains("HTTP error"));
118    }
119
120    #[test]
121    fn test_all_error_variants_debug() {
122        // Test that all error variants implement Debug properly
123        let config_err = BetterstackError::ConfigError("config test".to_string());
124        let debug_str = format!("{:?}", config_err);
125        assert!(debug_str.contains("ConfigError"));
126        assert!(debug_str.contains("config test"));
127
128        let send_err = BetterstackError::SendError("send test".to_string());
129        let debug_str = format!("{:?}", send_err);
130        assert!(debug_str.contains("SendError"));
131        assert!(debug_str.contains("send test"));
132
133        let json_err = serde_json::from_str::<i32>("not a number").unwrap_err();
134        let ser_err = BetterstackError::SerializationError(json_err);
135        let debug_str = format!("{:?}", ser_err);
136        assert!(debug_str.contains("SerializationError"));
137    }
138}