Expand description
§err_trail
A generic logging interface for libraries and binaries. Libraries remain generic and binaries pick the logging implementation(s).
Current backends enabled by feature flags:
If no backend is selected by the binary, since all operations are inlined, they get compiled away during compilation. No overhead or downstream lock-in. Libraries can also easily enable logs for tests only.
Convenience methods are also added on Result and Option for ergonomic logging when an Err or None is encountered. No need to match or inspect. Similar to how context is handled in libraries like eros or anyhow while moving up the call stack, but for logging.
§In Action
All methods and macros work with the generic backends. Like previously mentioned, if no backend is selected they are compiled away.
§Macros
Familiar error!, warn!, info!, debug!, trace! macros exist to log in a way similar to the built in rust format! macro.
use err_trail::{error, warn, info, debug, trace};
fn main() {
error!("An error occurred: {}", "disk full");
warn!("This is a warning: {}", "high memory usage");
info!("Some info: {}", "service started");
debug!("Debugging value: {:?}", vec![1, 2, 3]);
trace!("Trace log: {}", "function entered");
}§New Result and Option methods
New methods are added to Result and Option types - error, warn, info, debug, trace. These apply logs are various log levels
use err_trail::ErrContext;
fn main() {
let value: Result<(), String> = result().error("If `Err`, this message is logged as error");
let value: Result<(), String> = result().warn("If `Err`, this message is logged as warn");
// Notice these methods can also accept closures for lazy evaluation
let value: Result<(), String> = result().error(|err: &String| format!("If `Err`, this message is logged as error: {}", err));
// If the error type implements `Display` then `()` can be passed to log the error directly if `Err`
let value: Result<(), String> = result().error(());
}
fn result() -> Result<(), String> { Ok(()) }The same methods exist for Option too.
Note: Due to some limitations of Rust’s type inferencing on closures, for closures, usually the input type needs to be specified - e.g.
: &String.
§Guide
Opinionated guide on how to log if you are new to logging or would like a refresher:
flowchart TD
Start{Is this log for debugging?}
Start -->|Yes| SessionType
Start -->|No| UnwantedState
Start -->|I'm not sure| SessionType
SessionType --> |Yes| Debug
SessionType --> |No| Trace
SessionType -->|I'm not sure| Trace
UnwantedState -->|Yes| ProcessContinue
UnwantedState -->|No| Info
ProcessContinue -->|Yes| Warning
ProcessContinue -->|No| AppContinue
AppContinue -->|Yes| Error
AppContinue -->|No| Fatal
UnwantedState{Is the log the result of an unwanted state?}
SessionType{"Is <b>any</b> true:<br/><br/>• This is temporary (I'm printf debugging now)<br/>• I am <b>reasonably certain</b> a developer will care about and won't get annoyed if hit during debugging"}
ProcessContinue{Can the operation<br/>continue with<br/>unwanted state?}
AppContinue{Can the<br/>process<br/>continue?}
classDef normal fill:#ffffff,stroke:#374151,color:#000;
classDef trace fill:#e6d9ff,stroke:#7c3aed,color:#000;
classDef debug fill:#d1fae5,stroke:#059669,color:#000;
classDef info fill:#e0f2fe,stroke:#0284c7,color:#000;
classDef warning fill:#fde68a,stroke:#d97706,color:#000;
classDef error fill:#f8b4b4,stroke:#dc2626,color:#000;
classDef fatal fill:#b91c1c,stroke:#7f1d1d,color:#fff;
class Start,SessionType,UnwantedState,ProcessContinue,AppContinue normal;
class Trace trace;
class Debug debug;
class Info info;
class Warning warning;
class Error error;
class Fatal fatal;
Trace["Trace<br/><br/>• Often verbose (e.g. large variable states or hit frequently)<br/>• Usually noise during most debug sessions"]
Debug[Debug]
Info["Info<br/><br/>• For System Operators<br/>• Human readable<br/>• Usually actionable (e.g. alerts, incidents, performance, health, stability)"]
Warning["Warning<br/><br/>• Unwanted state/error encountered, but continuing the operation.<br/>• This is the last handler in an error chain and decided to continue the operation despite the error."]
Error["Error<br/><br/>• Operation had to be aborted.<br/>• This is the last handler in an error chain and decided to abort the operation because of the error."]
Fatal[Fatal<br/><br/>• Panic or abort]Note: Returning the error to the calling is not considered a warning or an error - if anything, a trace.
§no_std
This crate supports #![no_std].
Macros§
Traits§
- ErrContext
- For logging a
ResultwhenResult::Erris encountered. - ErrLog
- None
Context - For logging a
OptionwhenOption::Noneis encountered. - NoneLog