Skip to main content

xet_runtime/error_printer/
mod.rs

1use std::fmt::{Debug, Display};
2
3use tracing::{debug, error, info, warn};
4
5/// A helper trait to log errors.
6/// The logging functions will track the caller's callsite.
7/// For a chain of calls A -> B -> C -> ErrorPrinter, the
8/// topmost function without #[track_caller] is deemed the callsite.
9pub trait ErrorPrinter {
10    fn log_error<M: Display>(self, message: M) -> Self;
11    fn log_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self;
12
13    fn warn_error<M: Display>(self, message: M) -> Self;
14    fn warn_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self;
15
16    fn debug_error<M: Display>(self, message: M) -> Self;
17    fn debug_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self;
18
19    fn info_error<M: Display>(self, message: M) -> Self;
20    fn info_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self;
21}
22
23impl<T, E: Debug> ErrorPrinter for Result<T, E> {
24    /// If self is an Err(e), prints out the given string to tracing::error,
25    /// appending "error: {e}" to the end of the message.
26    #[track_caller]
27    fn log_error<M: Display>(self, message: M) -> Self {
28        match &self {
29            Ok(_) => {},
30            Err(e) => {
31                let caller = get_caller();
32                error!(caller, "{message}, error: {e:?}")
33            },
34        }
35        self
36    }
37
38    /// If self is an Err(e), calls the function to get a string to log to tracing::error,
39    /// appending "error: {e}" to the end of the message.
40    #[track_caller]
41    fn log_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self {
42        match &self {
43            Ok(_) => {},
44            Err(e) => {
45                let caller = get_caller();
46                error!(caller, "{}, error: {e:?}", message_fn())
47            },
48        }
49        self
50    }
51
52    /// If self is an Err(e), prints out the given string to tracing::warn,
53    /// appending "error: {e}" to the end of the message.
54    #[track_caller]
55    fn warn_error<M: Display>(self, message: M) -> Self {
56        match &self {
57            Ok(_) => {},
58            Err(e) => {
59                let caller = get_caller();
60                warn!(caller, "{message}, error: {e:?}")
61            },
62        }
63        self
64    }
65
66    /// If self is an Err(e), calls the function to get a string to log to tracing::warn,
67    /// appending "error: {e}" to the end of the message.
68    #[track_caller]
69    fn warn_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self {
70        match &self {
71            Ok(_) => {},
72            Err(e) => {
73                let caller = get_caller();
74                warn!(caller, "{}, error: {e:?}", message_fn())
75            },
76        }
77        self
78    }
79
80    /// If self is an Err(e), prints out the given string to tracing::debug,
81    /// appending "error: {e}" to the end of the message.
82    #[track_caller]
83    fn debug_error<M: Display>(self, message: M) -> Self {
84        match &self {
85            Ok(_) => {},
86            Err(e) => {
87                let caller = get_caller();
88                debug!(caller, "{message}, error: {e:?}")
89            },
90        }
91        self
92    }
93
94    /// If self is an Err(e), calls the function to get a string to log to tracing::debug,
95    /// appending "error: {e}" to the end of the message.
96    #[track_caller]
97    fn debug_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self {
98        match &self {
99            Ok(_) => {},
100            Err(e) => {
101                let caller = get_caller();
102                debug!(caller, "{}, error: {e:?}", message_fn())
103            },
104        }
105        self
106    }
107
108    /// If self is an Err(e), prints out the given string to tracing::info,
109    /// appending "error: {e}" to the end of the message.
110    #[track_caller]
111    fn info_error<M: Display>(self, message: M) -> Self {
112        match &self {
113            Ok(_) => {},
114            Err(e) => {
115                let caller = get_caller();
116                info!(caller, "{message}, error: {e:?}")
117            },
118        }
119        self
120    }
121
122    /// If self is an Err(e), calls the function to get a string to log to tracing::info,
123    /// appending "error: {e}" to the end of the message.
124    #[track_caller]
125    fn info_error_fn<M: Display, F: FnOnce() -> M>(self, message_fn: F) -> Self {
126        match &self {
127            Ok(_) => {},
128            Err(e) => {
129                let caller = get_caller();
130                info!(caller, "{}, error: {e:?}", message_fn())
131            },
132        }
133        self
134    }
135}
136
137/// A helper trait to log when an option is None.
138/// The logging functions will track the caller's callsite.
139/// For a chain of calls A -> B -> C -> OptionPrinter, the
140/// topmost function without #[track_caller] is deemed the callsite.
141pub trait OptionPrinter {
142    fn error_none<M: Display>(self, message: M) -> Self;
143
144    fn warn_none<M: Display>(self, message: M) -> Self;
145
146    fn debug_none<M: Display>(self, message: M) -> Self;
147
148    fn info_none<M: Display>(self, message: M) -> Self;
149}
150
151impl<T> OptionPrinter for Option<T> {
152    /// If self is None, prints out the message to tracing::error.
153    #[track_caller]
154    fn error_none<M: Display>(self, message: M) -> Self {
155        match &self {
156            Some(_) => {},
157            None => {
158                let caller = get_caller();
159                error!(caller, "{message}")
160            },
161        }
162        self
163    }
164
165    /// If self is None, prints out the message to tracing::warn.
166    #[track_caller]
167    fn warn_none<M: Display>(self, message: M) -> Self {
168        match &self {
169            Some(_) => {},
170            None => {
171                let caller = get_caller();
172                warn!(caller, "{message}")
173            },
174        }
175        self
176    }
177
178    /// If self is None, prints out the message to tracing::debug.
179    #[track_caller]
180    fn debug_none<M: Display>(self, message: M) -> Self {
181        match &self {
182            Some(_) => {},
183            None => {
184                let caller = get_caller();
185                debug!(caller, "{message}")
186            },
187        }
188        self
189    }
190
191    /// If self is None, prints out the message to tracing::info.
192    #[track_caller]
193    fn info_none<M: Display>(self, message: M) -> Self {
194        match &self {
195            Some(_) => {},
196            None => {
197                let caller = get_caller();
198                info!(caller, "{message}")
199            },
200        }
201        self
202    }
203}
204
205/// gets caller information for the top of the `#[track_caller]` stack as a formatted string:
206/// "<file>:<line>"
207#[track_caller]
208fn get_caller() -> String {
209    let location = std::panic::Location::caller();
210    format!("{}:{}", location.file(), location.line())
211}