Skip to main content

fuel_telemetry/
errors.rs

1use base64::DecodeError;
2use std::{io, path::PathBuf, string::FromUtf8Error};
3use thiserror::Error;
4
5#[derive(Error, Clone, PartialEq)]
6pub enum TelemetryError {
7    //
8    // External errors
9    //
10    #[error("Base64 error: {0}")]
11    Base64(#[from] DecodeError),
12    #[error("IO error: {0}")]
13    IO(String),
14    #[error("Nix error: {0}")]
15    Nix(String),
16    #[error("Parse error: {0}")]
17    Parse(String),
18    #[error("Reqwest error: {0}")]
19    Reqwest(String),
20    #[error("Request clone failed")]
21    ReqwestCloneFailed,
22    #[error("UTF-8 error: {0}")]
23    Utf8(String),
24
25    //
26    // General errors
27    //
28    #[error("Invalid config: {0}")]
29    InvalidConfig(String),
30    #[error("Invalid client")]
31    InvalidClient,
32    #[error("Invalid 'RUST_LOG' filter: {0}")]
33    InvalidEnvFilter(String),
34    #[error("Home directory is invalid: {0}")]
35    InvalidHomeDir(String),
36    #[error("Log directory is invalid: {0}")]
37    InvalidLogDir(String),
38    #[error("Logfile is invalid: {0}/{1}")]
39    InvalidLogFile(String, PathBuf),
40    #[error("Invalid request")]
41    InvalidRequest,
42    #[error("Temporary directory is invalid: {0}")]
43    InvalidTmpDir(String),
44    #[error("Do not use 'TelemetryLayer::new()' directly, instead use the constructor macros")]
45    InvalidUsage,
46    #[error("Home directory is unreachable")]
47    UnreachableHomeDir,
48    #[error("Crate name is unreadable")]
49    UnreadableCrateName,
50
51    //
52    // FileWatcher errors
53    //,
54    #[error("Tracing event is invalid: {0}")]
55    InvalidTracingEvent(String),
56    #[error("Tracing regex is invalid: {0}")]
57    InvalidTracingRegex(#[from] regex::Error),
58    #[error("Tracing payload is invalid: {0}")]
59    InvalidTracingPayload(String),
60
61    // Mock error for testing
62    #[error("Mock error")]
63    Mock,
64}
65
66/// Convenience impl that dereferences the error
67/// so that we can use the error with `?`
68impl From<&TelemetryError> for TelemetryError {
69    fn from(err: &TelemetryError) -> Self {
70        err.clone()
71    }
72}
73
74impl From<TelemetryError> for String {
75    fn from(err: TelemetryError) -> Self {
76        err.to_string()
77    }
78}
79
80impl std::fmt::Debug for TelemetryError {
81    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82        write!(f, "{self}")
83    }
84}
85
86//
87// The following impls are convenience impls that convert errors into our
88// `TelemetryError` variant. We do this because we want to use the `?` operator
89// and can't use `?` directly because the source errors don't implement
90// `Clone`.
91//
92
93macro_rules! impl_error_from {
94    ($from:ty, $variant:ident) => {
95        impl From<$from> for TelemetryError {
96            fn from(err: $from) -> Self {
97                Self::$variant(err.to_string())
98            }
99        }
100    };
101}
102
103impl_error_from!(io::Error, IO);
104impl_error_from!(nix::Error, Nix);
105impl_error_from!(std::num::ParseIntError, Parse);
106impl_error_from!(reqwest::Error, Reqwest);
107impl_error_from!(FromUtf8Error, Utf8);
108
109#[derive(Debug, PartialEq)]
110pub enum WatcherError {
111    Recoverable(TelemetryError),
112    Fatal(TelemetryError),
113}
114
115impl WatcherError {
116    pub fn is_fatal(&self) -> bool {
117        matches!(self, WatcherError::Fatal(_))
118    }
119}
120
121impl From<TelemetryError> for WatcherError {
122    fn from(err: TelemetryError) -> Self {
123        // Default to fatal, then be explicit about recoverable errors
124        WatcherError::Fatal(err)
125    }
126}
127
128pub fn into_fatal<E: Into<TelemetryError>>(err: E) -> WatcherError {
129    WatcherError::Fatal(err.into())
130}
131
132pub fn into_recoverable<E: Into<TelemetryError>>(err: E) -> WatcherError {
133    WatcherError::Recoverable(err.into())
134}