Skip to main content

tuwunel_core/error/
log.rs

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