tuwunel_core/error/log.rs
1use std::{convert::Infallible, error::Error as StdError, fmt, iter::successors};
2
3use tracing::Level;
4
5use super::Error;
6
7/// Flatten an error's `source()` chain into one `; caused by: ` string.
8///
9/// Storage and HTTP backends wrap transport errors several layers deep;
10/// the outer Display can show "error sending request" while the actual
11/// cause (e.g. rustls `UnknownIssuer`, hyper connect failure) is only
12/// reachable via `source()`. Logging the full chain at the failure site
13/// makes these self-diagnosing without per-crate trace logging.
14#[must_use]
15pub fn error_chain(e: &dyn StdError) -> String {
16 successors(Some(e), |&e| e.source())
17 .map(ToString::to_string)
18 .collect::<Vec<_>>()
19 .join("; caused by: ")
20}
21
22/// Logs an error and recovers with a default value in an infallible result.
23///
24/// The input is converted to [`Error`] and emitted through display formatting.
25/// The returned `Ok` contains [`Default::default`] for the requested value
26/// type.
27#[inline]
28pub fn else_log<T, E>(error: E) -> Result<T, Infallible>
29where
30 T: Default,
31 Error: From<E>,
32{
33 Ok(default_log(error))
34}
35
36/// Debug-logs an error and recovers with a default value in an infallible
37/// result.
38///
39/// The input is converted to [`Error`] and emitted through the debug-aware
40/// logging path. The returned `Ok` contains [`Default::default`] for the
41/// requested value type.
42#[inline]
43pub fn else_debug_log<T, E>(error: E) -> Result<T, Infallible>
44where
45 T: Default,
46 Error: From<E>,
47{
48 Ok(default_debug_log(error))
49}
50
51/// Logs an error and returns a default value.
52///
53/// The input is converted to [`Error`] before display-formatted logging. The
54/// result is independent of the error and comes from [`Default::default`].
55#[inline]
56pub fn default_log<T, E>(error: E) -> T
57where
58 T: Default,
59 Error: From<E>,
60{
61 let error = Error::from(error);
62 inspect_log(&error);
63 T::default()
64}
65
66/// Debug-logs an error and returns a default value.
67///
68/// The input is converted to [`Error`] before using the debug-aware logging
69/// path. The result is independent of the error and comes from
70/// [`Default::default`].
71#[inline]
72pub fn default_debug_log<T, E>(error: E) -> T
73where
74 T: Default,
75 Error: From<E>,
76{
77 let error = Error::from(error);
78 inspect_debug_log(&error);
79 T::default()
80}
81
82/// Converts and logs an error while returning the converted value.
83///
84/// Display-formatted logging occurs after conversion to [`Error`]. The same
85/// converted error is returned for propagation by combinator chains.
86#[inline]
87pub fn map_log<E>(error: E) -> Error
88where
89 Error: From<E>,
90{
91 let error = Error::from(error);
92 inspect_log(&error);
93 error
94}
95
96/// Converts and debug-logs an error while returning the converted value.
97///
98/// Debug-aware logging occurs after conversion to [`Error`]. The same converted
99/// error is returned for propagation by combinator chains.
100#[inline]
101pub fn map_debug_log<E>(error: E) -> Error
102where
103 Error: From<E>,
104{
105 let error = Error::from(error);
106 inspect_debug_log(&error);
107 error
108}
109
110/// Logs an error's display representation at error level.
111///
112/// The value is borrowed and otherwise left unchanged. Level dispatch is
113/// delegated to [`inspect_log_level`].
114#[inline]
115pub fn inspect_log<E: fmt::Display>(error: &E) { inspect_log_level(error, Level::ERROR); }
116
117/// Logs an error's debug representation through the debug-aware error path.
118///
119/// The value is borrowed and otherwise left unchanged. Level dispatch is
120/// delegated to [`inspect_debug_log_level`].
121#[inline]
122pub fn inspect_debug_log<E: fmt::Debug>(error: &E) {
123 inspect_debug_log_level(error, Level::ERROR);
124}
125
126/// Logs a display-formatted error at the selected tracing level.
127///
128/// Each tracing level maps to its corresponding project logging macro. The
129/// value is borrowed and otherwise left unchanged.
130#[inline]
131pub fn inspect_log_level<E: fmt::Display>(error: &E, level: Level) {
132 use crate::{debug, error, info, trace, warn};
133
134 match level {
135 | Level::ERROR => error!("{error}"),
136 | Level::WARN => warn!("{error}"),
137 | Level::INFO => info!("{error}"),
138 | Level::DEBUG => debug!("{error}"),
139 | Level::TRACE => trace!("{error}"),
140 }
141}
142
143/// Logs a debug-formatted error at the selected debug-aware tracing level.
144///
145/// Error, warning, and information inputs use their debug-sensitive logging
146/// macros, while debug and trace use fixed levels. The value is borrowed and
147/// otherwise left unchanged.
148#[inline]
149pub fn inspect_debug_log_level<E: fmt::Debug>(error: &E, level: Level) {
150 use crate::{debug, debug_error, debug_info, debug_warn, trace};
151
152 match level {
153 | Level::ERROR => debug_error!("{error:?}"),
154 | Level::WARN => debug_warn!("{error:?}"),
155 | Level::INFO => debug_info!("{error:?}"),
156 | Level::DEBUG => debug!("{error:?}"),
157 | Level::TRACE => trace!("{error:?}"),
158 }
159}