1 //! Utilities for enriching error handling with [`tracing`] diagnostic 2 //! information. 3 //! 4 //! # Overview 5 //! 6 //! [`tracing`] is a framework for instrumenting Rust programs to collect 7 //! scoped, structured, and async-aware diagnostics. This crate provides 8 //! integrations between [`tracing`] instrumentation and Rust error handling. It 9 //! enables enriching error types with diagnostic information from `tracing` 10 //! [span] contexts, formatting those contexts when errors are displayed, and 11 //! automatically generate `tracing` [events] when errors occur. 12 //! 13 //! The crate provides the following: 14 //! 15 //! * [`SpanTrace`], a captured trace of the current `tracing` [span] context 16 //! 17 //! * [`ErrorLayer`], a [subscriber layer] which enables capturing `SpanTrace`s 18 //! 19 //! **Note**: This crate is currently experimental. 20 //! 21 //! *Compiler support: [requires `rustc` 1.49+][msrv]* 22 //! 23 //! [msrv]: #supported-rust-versions 24 //! 25 //! ## Feature Flags 26 //! 27 //! - `traced-error` - Enables the [`TracedError`] type and related Traits 28 //! - [`InstrumentResult`] and [`InstrumentError`] extension traits, which 29 //! provide an [`in_current_span()`] method for bundling errors with a 30 //! [`SpanTrace`]. 31 //! - [`ExtractSpanTrace`] extension trait, for extracting `SpanTrace`s from 32 //! behind `dyn Error` trait objects. 33 //! 34 //! ## Usage 35 //! 36 //! `tracing-error` provides the [`SpanTrace`] type, which captures the current 37 //! `tracing` span context when it is constructed and allows it to be displayed 38 //! at a later time. 39 //! 40 //! For example: 41 //! 42 //! ```rust 43 //! use std::{fmt, error::Error}; 44 //! use tracing_error::SpanTrace; 45 //! 46 //! #[derive(Debug)] 47 //! pub struct MyError { 48 //! context: SpanTrace, 49 //! // ... 50 //! } 51 //! 52 //! impl fmt::Display for MyError { 53 //! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 54 //! // ... format other parts of the error ... 55 //! 56 //! self.context.fmt(f)?; 57 //! 58 //! // ... format other error context information, cause chain, etc ... 59 //! # Ok(()) 60 //! } 61 //! } 62 //! 63 //! impl Error for MyError {} 64 //! 65 //! impl MyError { 66 //! pub fn new() -> Self { 67 //! Self { 68 //! context: SpanTrace::capture(), 69 //! // ... other error information ... 70 //! } 71 //! } 72 //! } 73 //! ``` 74 //! 75 //! This crate also provides [`TracedError`], for attaching a [`SpanTrace`] to 76 //! an existing error. The easiest way to wrap errors in `TracedError` is to 77 //! either use the [`InstrumentResult`] and [`InstrumentError`] traits or the 78 //! `From`/`Into` traits. 79 //! 80 //! ```rust 81 //! # use std::error::Error; 82 //! use tracing_error::prelude::*; 83 //! 84 //! # fn fake_main() -> Result<(), Box<dyn Error>> { 85 //! std::fs::read_to_string("myfile.txt").in_current_span()?; 86 //! # Ok(()) 87 //! # } 88 //! ``` 89 //! 90 //! Once an error has been wrapped with with a [`TracedError`] the [`SpanTrace`] 91 //! can be extracted one of 3 ways: either via [`TracedError`]'s 92 //! `Display`/`Debug` implementations, or via the [`ExtractSpanTrace`] trait. 93 //! 94 //! For example, here is how one might print the errors but specialize the 95 //! printing when the error is a placeholder for a wrapping [`SpanTrace`]: 96 //! 97 //! ```rust 98 //! use std::error::Error; 99 //! use tracing_error::ExtractSpanTrace as _; 100 //! 101 //! fn print_extracted_spantraces(error: &(dyn Error + 'static)) { 102 //! let mut error = Some(error); 103 //! let mut ind = 0; 104 //! 105 //! eprintln!("Error:"); 106 //! 107 //! while let Some(err) = error { 108 //! if let Some(spantrace) = err.span_trace() { 109 //! eprintln!("found a spantrace:\n{}", spantrace); 110 //! } else { 111 //! eprintln!("{:>4}: {}", ind, err); 112 //! } 113 //! 114 //! error = err.source(); 115 //! ind += 1; 116 //! } 117 //! } 118 //! 119 //! ``` 120 //! 121 //! Whereas here, we can still display the content of the `SpanTraces` without 122 //! any special casing by simply printing all errors in our error chain. 123 //! 124 //! ```rust 125 //! use std::error::Error; 126 //! 127 //! fn print_naive_spantraces(error: &(dyn Error + 'static)) { 128 //! let mut error = Some(error); 129 //! let mut ind = 0; 130 //! 131 //! eprintln!("Error:"); 132 //! 133 //! while let Some(err) = error { 134 //! eprintln!("{:>4}: {}", ind, err); 135 //! error = err.source(); 136 //! ind += 1; 137 //! } 138 //! } 139 //! ``` 140 //! 141 //! Applications that wish to use `tracing-error`-enabled errors should 142 //! construct an [`ErrorLayer`] and add it to their [`Subscriber`] in order to 143 //! enable capturing [`SpanTrace`]s. For example: 144 //! 145 //! ```rust 146 //! use tracing_error::ErrorLayer; 147 //! use tracing_subscriber::prelude::*; 148 //! 149 //! fn main() { 150 //! let subscriber = tracing_subscriber::Registry::default() 151 //! // any number of other subscriber layers may be added before or 152 //! // after the `ErrorLayer`... 153 //! .with(ErrorLayer::default()); 154 //! 155 //! // set the subscriber as the default for the application 156 //! tracing::subscriber::set_global_default(subscriber); 157 //! } 158 //! ``` 159 //! 160 //! [`in_current_span()`]: InstrumentResult#tymethod.in_current_span 161 //! [span]: mod@tracing::span 162 //! [events]: tracing::Event 163 //! [`Subscriber`]: tracing::Subscriber 164 //! [subscriber layer]: tracing_subscriber::layer::Layer 165 //! [`tracing`]: tracing 166 //! 167 //! ## Supported Rust Versions 168 //! 169 //! Tracing is built against the latest stable release. The minimum supported 170 //! version is 1.49. The current Tracing version is not guaranteed to build on 171 //! Rust versions earlier than the minimum supported version. 172 //! 173 //! Tracing follows the same compiler support policies as the rest of the Tokio 174 //! project. The current stable Rust compiler and the three most recent minor 175 //! versions before it will always be supported. For example, if the current 176 //! stable compiler version is 1.45, the minimum supported version will not be 177 //! increased past 1.42, three minor versions prior. Increasing the minimum 178 //! supported compiler version is not considered a semver breaking change as 179 //! long as doing so complies with this policy. 180 //! 181 #![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))] 182 #![doc(html_root_url = "https://docs.rs/tracing-error/0.2.0")] 183 #![doc( 184 html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png", 185 issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/" 186 )] 187 #![warn( 188 missing_debug_implementations, 189 missing_docs, 190 rust_2018_idioms, 191 unreachable_pub, 192 bad_style, 193 const_err, 194 dead_code, 195 improper_ctypes, 196 non_shorthand_field_patterns, 197 no_mangle_generic_items, 198 overflowing_literals, 199 path_statements, 200 patterns_in_fns_without_body, 201 private_in_public, 202 unconditional_recursion, 203 unused, 204 unused_allocation, 205 unused_comparisons, 206 unused_parens, 207 while_true 208 )] 209 mod backtrace; 210 #[cfg(feature = "traced-error")] 211 mod error; 212 mod layer; 213 214 pub use self::backtrace::{SpanTrace, SpanTraceStatus}; 215 #[cfg(feature = "traced-error")] 216 pub use self::error::{ExtractSpanTrace, InstrumentError, InstrumentResult, TracedError}; 217 pub use self::layer::ErrorLayer; 218 219 #[cfg(feature = "traced-error")] 220 #[cfg_attr(docsrs, doc(cfg(feature = "traced-error")))] 221 pub mod prelude { 222 //! The `tracing-error` prelude. 223 //! 224 //! This brings into scope the `InstrumentError`, `InstrumentResult`, and `ExtractSpanTrace` 225 //! extension traits. These traits allow attaching `SpanTrace`s to errors and 226 //! subsequently retrieving them from `dyn Error` trait objects. 227 228 // apparently `as _` reexpoorts now generate `unreachable_pub` linting? which 229 // seems wrong to me... 230 #![allow(unreachable_pub)] 231 pub use crate::{ExtractSpanTrace as _, InstrumentError as _, InstrumentResult as _}; 232 } 233