diff options
Diffstat (limited to 'vendor/tracing-error')
-rw-r--r-- | vendor/tracing-error/.cargo-checksum.json | 1 | ||||
-rw-r--r-- | vendor/tracing-error/CHANGELOG.md | 57 | ||||
-rw-r--r-- | vendor/tracing-error/Cargo.toml | 41 | ||||
-rw-r--r-- | vendor/tracing-error/LICENSE | 25 | ||||
-rw-r--r-- | vendor/tracing-error/README.md | 238 | ||||
-rw-r--r-- | vendor/tracing-error/src/backtrace.rs | 320 | ||||
-rw-r--r-- | vendor/tracing-error/src/error.rs | 289 | ||||
-rw-r--r-- | vendor/tracing-error/src/layer.rs | 132 | ||||
-rw-r--r-- | vendor/tracing-error/src/lib.rs | 236 |
9 files changed, 1339 insertions, 0 deletions
diff --git a/vendor/tracing-error/.cargo-checksum.json b/vendor/tracing-error/.cargo-checksum.json new file mode 100644 index 000000000..f79bea7d4 --- /dev/null +++ b/vendor/tracing-error/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"d1beb2e1f8976a85e9e0fc89de9023f392cdc42acb313a7b59aef6b771aa2cdd","Cargo.toml":"773ef49ae3a0dee52c2a66f4850f08da89c008fe907c02f9611b8c78f9661816","LICENSE":"898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1","README.md":"e54c27168fc125d89666b5814b415035ebd34b308cca48eaaf5c621cc0f3d538","src/backtrace.rs":"c5c3f7e2357a7d399c2f3a97464a4f58795080e560944dff21957b3c0f6455c8","src/error.rs":"772ac16e77a880fbd174577abe4a3a39af35e5231d3498a535803f7324a7fa9b","src/layer.rs":"59712db62669022addedabc3fdd1969de563045cdb8b8468308519b2ee1c4049","src/lib.rs":"758101422e707178e023f9d6d5b8dfc076a8eb76b81f5de66fc031e020daa898"},"package":"d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"}
\ No newline at end of file diff --git a/vendor/tracing-error/CHANGELOG.md b/vendor/tracing-error/CHANGELOG.md new file mode 100644 index 000000000..7cd565dcf --- /dev/null +++ b/vendor/tracing-error/CHANGELOG.md @@ -0,0 +1,57 @@ +# 0.2.0 (October 23, 2021) + +This is a breaking change release in order to update the `tracing-subscriber` +dependency version to [the v0.3.x release series][v03]. + +### Changed + +- Updated `tracing-subscriber` dependency to [v0.3.0][v03] ([#1677]) + +### Fixed + +- Disabled default features of the `tracing` dependency so that proc-macro + dependencies are not enabled ([#1144]) +- Documentation fixes and improvements ([#635], [#695]) + +### Added + +- **SpanTrace**: Added `SpanTrace::new` constructor for constructing a + `SpanTrace` from a `Span` passed as an argument (rather than capturing the + current span) ([#1492]) + +Thanks to @CAD97 for contributing to this release! + +[v03]: https://github.com/tokio-rs/tracing/releases/tag/tracing-subscriber-0.3.0 +[#635]: https://github.com/tokio-rs/tracing/pull/635 +[#695]: https://github.com/tokio-rs/tracing/pull/695 +[#1144]: https://github.com/tokio-rs/tracing/pull/1144 +[#1492]: https://github.com/tokio-rs/tracing/pull/1492 +[#1677]: https://github.com/tokio-rs/tracing/pull/1677 + +# 0.1.2 (March 3, 2020) + +### Added + +- **TracedError**: `TracedError`, an error type wrapper that annotates an error + with the current span. +- **SpanTrace**:`SpanTrace::status` method and `SpanTraceStatus` type for + determing whether a `SpanTrace` was successfully captured (#614) + +### Changed + +- **SpanTrace**: Made backtrace formatting more consistent with upstream changes + to `std::backtrace` (#584) + +# 0.1.1 (February 5, 2020) + +### Fixed + +- Fixed a typo in the crate description + +### Changed + +- the maintenance badge from active to experimental + +# 0.1.0 (February 5, 2020) + +- Initial release diff --git a/vendor/tracing-error/Cargo.toml b/vendor/tracing-error/Cargo.toml new file mode 100644 index 000000000..c3ceffc6d --- /dev/null +++ b/vendor/tracing-error/Cargo.toml @@ -0,0 +1,41 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2018" +name = "tracing-error" +version = "0.2.0" +authors = ["Eliza Weisman <eliza@buoyant.io>", "Jane Lusby <jlusby@yaah.dev>", "Tokio Contributors <team@tokio.rs>"] +description = "Utilities for enriching errors with `tracing`.\n" +homepage = "https://tokio.rs" +readme = "README.md" +keywords = ["tracing", "error-handling", "exception-reporting", "backtrace"] +categories = ["development-tools::debugging", "rust-patterns"] +license = "MIT" +repository = "https://github.com/tokio-rs/tracing" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +[dependencies.tracing] +version = "0.1.12" +features = ["std"] +default-features = false + +[dependencies.tracing-subscriber] +version = "0.3" +features = ["registry", "fmt"] +default-features = false + +[features] +default = ["traced-error"] +traced-error = [] +[badges.maintenance] +status = "experimental" diff --git a/vendor/tracing-error/LICENSE b/vendor/tracing-error/LICENSE new file mode 100644 index 000000000..cdb28b4b5 --- /dev/null +++ b/vendor/tracing-error/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2019 Tokio Contributors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/tracing-error/README.md b/vendor/tracing-error/README.md new file mode 100644 index 000000000..dc69620e1 --- /dev/null +++ b/vendor/tracing-error/README.md @@ -0,0 +1,238 @@ +![Tracing — Structured, application-level diagnostics][splash] + +[splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg + +# tracing-error + +Utilities for enriching error handling with [`tracing`] diagnostic +information. + +[![Crates.io][crates-badge]][crates-url] +[![Documentation][docs-badge]][docs-url] +[![Documentation (master)][docs-master-badge]][docs-master-url] +[![MIT licensed][mit-badge]][mit-url] +[![Build Status][actions-badge]][actions-url] +[![Discord chat][discord-badge]][discord-url] +![maintenance status][maint-badge] + +[Documentation (release)][docs-url] | [Documentation (master)][docs-master-url] | [Chat][discord-url] + +[crates-badge]: https://img.shields.io/crates/v/tracing-error.svg +[crates-url]: https://crates.io/crates/tracing-error/0.2.0 +[docs-badge]: https://docs.rs/tracing-error/badge.svg +[docs-url]: https://docs.rs/tracing-error/0.2.0/tracing_error +[docs-master-badge]: https://img.shields.io/badge/docs-master-blue +[docs-master-url]: https://tracing-rs.netlify.com/tracing_error +[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg +[mit-url]: LICENSE +[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg +[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI +[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white +[discord-url]: https://discord.gg/EeF3cQw +[maint-badge]: https://img.shields.io/badge/maintenance-experimental-blue.svg + +# Overview + +[`tracing`] is a framework for instrumenting Rust programs to collect +scoped, structured, and async-aware diagnostics. This crate provides +integrations between [`tracing`] instrumentation and Rust error handling. It +enables enriching error types with diagnostic information from `tracing` +[span] contexts, formatting those contexts when errors are displayed, and +automatically generate `tracing` [events] when errors occur. + +The crate provides the following: + +* [`SpanTrace`], a captured trace of the current `tracing` [span] context + +* [`ErrorLayer`], a [subscriber layer] which enables capturing `SpanTrace`s + +**Note**: This crate is currently experimental. + +*Compiler support: [requires `rustc` 1.42+][msrv]* + +[msrv]: #supported-rust-versions + +## Usage + +`tracing-error` provides the [`SpanTrace`] type, which captures the current +`tracing` span context when it is constructed and allows it to be displayed +at a later time. + +For example: + +```rust +use std::{fmt, error::Error}; +use tracing_error::SpanTrace; + +#[derive(Debug)] +pub struct MyError { + context: SpanTrace, + // ... +} + +impl fmt::Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // ... format other parts of the error ... + + self.context.fmt(f)?; + + // ... format other error context information, cause chain, etc ... + # Ok(()) + } +} + +impl Error for MyError {} + +impl MyError { + pub fn new() -> Self { + Self { + context: SpanTrace::capture(), + // ... other error information ... + } + } +} +``` + +This crate also provides [`TracedError`], for attaching a [`SpanTrace`] to an +existing error. The easiest way to wrap errors in `TracedError` is to either +use the [`InstrumentResult`] and [`InstrumentError`] traits or the `From`/`Into` +traits. + +```rust +use tracing_error::prelude::*; + +std::fs::read_to_string("myfile.txt").in_current_span()?; +``` + +Once an error has been wrapped with with a [`TracedError`], the [`SpanTrace`] +can be extracted one of three ways: either via [`TracedError`]'s +`Display`/`Debug` implementations, or via the [`ExtractSpanTrace`] trait. + +For example, here is how one might print the errors but specialize the +printing when the error is a placeholder for a wrapping [`SpanTrace`]: + +```rust +use std::error::Error; +use tracing_error::ExtractSpanTrace as _; + +fn print_extracted_spantraces(error: &(dyn Error + 'static)) { + let mut error = Some(error); + let mut ind = 0; + + eprintln!("Error:"); + + while let Some(err) = error { + if let Some(spantrace) = err.span_trace() { + eprintln!("found a spantrace:\n{}", spantrace); + } else { + eprintln!("{:>4}: {}", ind, err); + } + + error = err.source(); + ind += 1; + } +} + +``` + +Whereas here, we can still display the content of the `SpanTraces` without +any special casing by simply printing all errors in our error chain. + +```rust +use std::error::Error; + +fn print_naive_spantraces(error: &(dyn Error + 'static)) { + let mut error = Some(error); + let mut ind = 0; + + eprintln!("Error:"); + + while let Some(err) = error { + eprintln!("{:>4}: {}", ind, err); + error = err.source(); + ind += 1; + } +} +``` + +Applications that wish to use `tracing-error`-enabled errors should +construct an [`ErrorLayer`] and add it to their [`Subscriber`] in order to +enable capturing [`SpanTrace`]s. For example: + +```rust +use tracing_error::ErrorLayer; +use tracing_subscriber::prelude::*; + +fn main() { + let subscriber = tracing_subscriber::Registry::default() + // any number of other subscriber layers may be added before or + // after the `ErrorLayer`... + .with(ErrorLayer::default()); + + // set the subscriber as the default for the application + tracing::subscriber::set_global_default(subscriber); +} +``` + +## Feature Flags + +- `traced-error` - Enables the [`TracedError`] type and related traits + - [`InstrumentResult`] and [`InstrumentError`] extension traits, which + provide an [`in_current_span()`] method for bundling errors with a + [`SpanTrace`]. + - [`ExtractSpanTrace`] extension trait, for extracting `SpanTrace`s from + behind `dyn Error` trait objects. + +## Supported Rust Versions + +Tracing is built against the latest stable release. The minimum supported +version is 1.42. The current Tracing version is not guaranteed to build on Rust +versions earlier than the minimum supported version. + +Tracing follows the same compiler support policies as the rest of the Tokio +project. The current stable Rust compiler and the three most recent minor +versions before it will always be supported. For example, if the current stable +compiler version is 1.45, the minimum supported version will not be increased +past 1.42, three minor versions prior. Increasing the minimum supported compiler +version is not considered a semver breaking change as long as doing so complies +with this policy. + +## Related Crates + +In addition to this repository, here are also several third-party crates which +are not maintained by the `tokio` project. These include: + +- [`color-spantrace`] provides a formatter for rendering SpanTrace in the style + of `color-backtrace` +- [`color-eyre`] provides a customized version of `eyre::Report` for capturing + span traces and backtraces with new errors and pretty printing them in error + reports. + +[`color-spantrace`]: https://github.com/yaahc/color-spantrace +[`color-eyre`]: https://github.com/yaahc/color-eyre + +## License + +This project is licensed under the [MIT license](LICENSE). + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Tracing by you, shall be licensed as MIT, without any additional +terms or conditions. + +[`SpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/struct.SpanTrace.html +[`ErrorLayer`]: https://docs.rs/tracing-error/*/tracing_error/struct.ErrorLayer.html +[`TracedError`]: https://docs.rs/tracing-error/*/tracing_error/struct.TracedError.html +[`InstrumentResult`]: https://docs.rs/tracing-error/*/tracing_error/trait.InstrumentResult.html +[`InstrumentError`]: https://docs.rs/tracing-error/*/tracing_error/trait.InstrumentError.html +[`ExtractSpanTrace`]: https://docs.rs/tracing-error/*/tracing_error/trait.ExtractSpanTrace.html +[`in_current_span()`]: https://docs.rs/tracing-error/*/tracing_error/trait.InstrumentResult.html#tymethod.in_current_span +[span]: https://docs.rs/tracing/latest/tracing/span/index.html +[events]: https://docs.rs/tracing/latest/tracing/struct.Event.html +[`Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html +[subscriber layer]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/trait.Layer.html +[`tracing`]: https://docs.rs/tracing +[`std::error::Error`]: https://doc.rust-lang.org/stable/std/error/trait.Error.html +[`SpanTrace`]: https://docs.rs/tracing-error/0.2.0/tracing_error/struct.SpanTrace.html +[`ErrorLayer`]: https://docs.rs/tracing-error/0.2.0/tracing_error/struct.ErrorLayer.html diff --git a/vendor/tracing-error/src/backtrace.rs b/vendor/tracing-error/src/backtrace.rs new file mode 100644 index 000000000..0a2c31d29 --- /dev/null +++ b/vendor/tracing-error/src/backtrace.rs @@ -0,0 +1,320 @@ +use crate::layer::WithContext; +use std::fmt; +use tracing::{Metadata, Span}; + +/// A captured trace of [`tracing`] spans. +/// +/// This type can be thought of as a relative of +/// [`std::backtrace::Backtrace`][`Backtrace`]. +/// However, rather than capturing the current call stack when it is +/// constructed, a `SpanTrace` instead captures the current [span] and its +/// [parents]. +/// +/// In many cases, span traces may be as useful as stack backtraces useful in +/// pinpointing where an error occurred and why, if not moreso: +/// +/// * A span trace captures only the user-defined, human-readable `tracing` +/// spans, rather than _every_ frame in the call stack, often cutting out a +/// lot of noise. +/// * Span traces include the [fields] recorded by each span in the trace, as +/// well as their names and source code location, so different invocations of +/// a function can be distinguished, +/// * In asynchronous code, backtraces for errors that occur in [futures] often +/// consist not of the stack frames that _spawned_ a future, but the stack +/// frames of the executor that is responsible for running that future. This +/// means that if an `async fn` calls another `async fn` which generates an +/// error, the calling async function will not appear in the stack trace (and +/// often, the callee won't either!). On the other hand, when the +/// [`tracing-futures`] crate is used to instrument async code, the span trace +/// will represent the logical application context a future was running in, +/// rather than the stack trace of the executor that was polling a future when +/// an error occurred. +/// +/// Finally, unlike stack [`Backtrace`]s, capturing a `SpanTrace` is fairly +/// lightweight, and the resulting struct is not large. The `SpanTrace` struct +/// is formatted lazily; instead, it simply stores a copy of the current span, +/// and allows visiting the spans in that span's trace tree by calling the +/// [`with_spans` method][`with_spans`]. +/// +/// # Formatting +/// +/// The `SpanTrace` type implements `fmt::Display`, formatting the span trace +/// similarly to how Rust formats panics. For example: +/// +/// ```text +/// 0: custom_error::do_another_thing +/// with answer=42 will_succeed=false +/// at examples/examples/custom_error.rs:42 +/// 1: custom_error::do_something +/// with foo="hello world" +/// at examples/examples/custom_error.rs:37 +/// ``` +/// +/// Additionally, if custom formatting is desired, the [`with_spans`] method can +/// be used to visit each span in the trace, formatting them in order. +/// +/// [`tracing`]: https://docs.rs/tracing +/// [`Backtrace`]: https://doc.rust-lang.org/std/backtrace/struct.Backtrace.html +/// [span]: https://docs.rs/tracing/latest/tracing/span/index.html +/// [parents]: https://docs.rs/tracing/latest/tracing/span/index.html#span-relationships +/// [fields]: https://docs.rs/tracing/latest/tracing/field/index.html +/// [futures]: https://doc.rust-lang.org/std/future/trait.Future.html +/// [`tracing-futures`]: https://docs.rs/tracing-futures/ +/// [`with_spans`]: #method.with_spans +#[derive(Clone)] +pub struct SpanTrace { + span: Span, +} + +// === impl SpanTrace === + +impl SpanTrace { + /// Create a new span trace with the given span as the innermost span. + pub fn new(span: Span) -> Self { + SpanTrace { span } + } + + /// Capture the current span trace. + /// + /// # Examples + /// ```rust + /// use tracing_error::SpanTrace; + /// + /// pub struct MyError { + /// span_trace: SpanTrace, + /// // ... + /// } + /// + /// # fn some_error_condition() -> bool { true } + /// + /// #[tracing::instrument] + /// pub fn my_function(arg: &str) -> Result<(), MyError> { + /// if some_error_condition() { + /// return Err(MyError { + /// span_trace: SpanTrace::capture(), + /// // ... + /// }); + /// } + /// + /// // ... + /// # Ok(()) + /// } + /// ``` + pub fn capture() -> Self { + SpanTrace::new(Span::current()) + } + + /// Apply a function to all captured spans in the trace until it returns + /// `false`. + /// + /// This will call the provided function with a reference to the + /// [`Metadata`] and a formatted representation of the [fields] of each span + /// captured in the trace, starting with the span that was current when the + /// trace was captured. The function may return `true` or `false` to + /// indicate whether to continue iterating over spans; if it returns + /// `false`, no additional spans will be visited. + /// + /// [fields]: https://docs.rs/tracing/latest/tracing/field/index.html + /// [`Metadata`]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html + pub fn with_spans(&self, f: impl FnMut(&'static Metadata<'static>, &str) -> bool) { + self.span.with_subscriber(|(id, s)| { + if let Some(getcx) = s.downcast_ref::<WithContext>() { + getcx.with_context(s, id, f); + } + }); + } + + /// Returns the status of this `SpanTrace`. + /// + /// The status indicates one of the following: + /// * the current subscriber does not support capturing `SpanTrace`s + /// * there was no current span, so a trace was not captured + /// * a span trace was successfully captured + pub fn status(&self) -> SpanTraceStatus { + let inner = if self.span.is_none() { + SpanTraceStatusInner::Empty + } else { + let mut status = None; + self.span.with_subscriber(|(_, s)| { + if s.downcast_ref::<WithContext>().is_some() { + status = Some(SpanTraceStatusInner::Captured); + } + }); + + status.unwrap_or(SpanTraceStatusInner::Unsupported) + }; + + SpanTraceStatus(inner) + } +} + +/// The current status of a SpanTrace, indicating whether it was captured or +/// whether it is empty for some other reason. +#[derive(Debug, PartialEq, Eq)] +pub struct SpanTraceStatus(SpanTraceStatusInner); + +impl SpanTraceStatus { + /// Formatting a SpanTrace is not supported, likely because there is no + /// ErrorLayer or the ErrorLayer is from a different version of + /// tracing_error + pub const UNSUPPORTED: SpanTraceStatus = SpanTraceStatus(SpanTraceStatusInner::Unsupported); + + /// The SpanTrace is empty, likely because it was captured outside of any + /// `span`s + pub const EMPTY: SpanTraceStatus = SpanTraceStatus(SpanTraceStatusInner::Empty); + + /// A span trace has been captured and the `SpanTrace` should print + /// reasonable information when rendered. + pub const CAPTURED: SpanTraceStatus = SpanTraceStatus(SpanTraceStatusInner::Captured); +} + +#[derive(Debug, PartialEq, Eq)] +enum SpanTraceStatusInner { + Unsupported, + Empty, + Captured, +} + +macro_rules! try_bool { + ($e:expr, $dest:ident) => {{ + let ret = $e.unwrap_or_else(|e| $dest = Err(e)); + + if $dest.is_err() { + return false; + } + + ret + }}; +} + +impl fmt::Display for SpanTrace { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut err = Ok(()); + let mut span = 0; + + self.with_spans(|metadata, fields| { + if span > 0 { + try_bool!(write!(f, "\n",), err); + } + + try_bool!( + write!(f, "{:>4}: {}::{}", span, metadata.target(), metadata.name()), + err + ); + + if !fields.is_empty() { + try_bool!(write!(f, "\n with {}", fields), err); + } + + if let Some((file, line)) = metadata + .file() + .and_then(|file| metadata.line().map(|line| (file, line))) + { + try_bool!(write!(f, "\n at {}:{}", file, line), err); + } + + span += 1; + true + }); + + err + } +} + +impl fmt::Debug for SpanTrace { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + struct DebugSpan<'a> { + metadata: &'a Metadata<'a>, + fields: &'a str, + } + + impl<'a> fmt::Debug for DebugSpan<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{{ target: {:?}, name: {:?}", + self.metadata.target(), + self.metadata.name() + )?; + + if !self.fields.is_empty() { + write!(f, ", fields: {:?}", self.fields)?; + } + + if let Some((file, line)) = self + .metadata + .file() + .and_then(|file| self.metadata.line().map(|line| (file, line))) + { + write!(f, ", file: {:?}, line: {:?}", file, line)?; + } + + write!(f, " }}")?; + + Ok(()) + } + } + + write!(f, "SpanTrace ")?; + let mut dbg = f.debug_list(); + self.with_spans(|metadata, fields| { + dbg.entry(&DebugSpan { metadata, fields }); + true + }); + dbg.finish() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ErrorLayer; + use tracing::subscriber::with_default; + use tracing::{span, Level}; + use tracing_subscriber::{prelude::*, registry::Registry}; + + #[test] + fn capture_supported() { + let subscriber = Registry::default().with(ErrorLayer::default()); + + with_default(subscriber, || { + let span = span!(Level::ERROR, "test span"); + let _guard = span.enter(); + + let span_trace = SpanTrace::capture(); + + dbg!(&span_trace); + + assert_eq!(SpanTraceStatus::CAPTURED, span_trace.status()) + }); + } + + #[test] + fn capture_empty() { + let subscriber = Registry::default().with(ErrorLayer::default()); + + with_default(subscriber, || { + let span_trace = SpanTrace::capture(); + + dbg!(&span_trace); + + assert_eq!(SpanTraceStatus::EMPTY, span_trace.status()) + }); + } + + #[test] + fn capture_unsupported() { + let subscriber = Registry::default(); + + with_default(subscriber, || { + let span = span!(Level::ERROR, "test span"); + let _guard = span.enter(); + + let span_trace = SpanTrace::capture(); + + dbg!(&span_trace); + + assert_eq!(SpanTraceStatus::UNSUPPORTED, span_trace.status()) + }); + } +} diff --git a/vendor/tracing-error/src/error.rs b/vendor/tracing-error/src/error.rs new file mode 100644 index 000000000..fea729625 --- /dev/null +++ b/vendor/tracing-error/src/error.rs @@ -0,0 +1,289 @@ +use crate::SpanTrace; +use std::error::Error; +use std::fmt::{self, Debug, Display}; + +struct Erased; + +/// A wrapper type for `Error`s that bundles a `SpanTrace` with an inner `Error` +/// type. +/// +/// This type is a good match for the error-kind pattern where you have an error +/// type with an inner enum of error variants and you would like to capture a +/// span trace that can be extracted during printing without formatting the span +/// trace as part of your display impl. +/// +/// An example of implementing an error type for a library using `TracedError` +/// might look like this +/// +/// ```rust,compile_fail +/// #[derive(Debug, thiserror::Error)] +/// enum Kind { +/// // ... +/// } +/// +/// #[derive(Debug)] +/// pub struct Error { +/// source: TracedError<Kind>, +/// backtrace: Backtrace, +/// } +/// +/// impl std::error::Error for Error { +/// fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { +/// self.source.source() +/// } +/// +/// fn backtrace(&self) -> Option<&Backtrace> { +/// Some(&self.backtrace) +/// } +/// } +/// +/// impl fmt::Display for Error { +/// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { +/// fmt::Display::fmt(&self.source, fmt) +/// } +/// } +/// +/// impl<E> From<E> for Error +/// where +/// Kind: From<E>, +/// { +/// fn from(source: E) -> Self { +/// Self { +/// source: Kind::from(source).into(), +/// backtrace: Backtrace::capture(), +/// } +/// } +/// } +/// ``` +#[cfg_attr(docsrs, doc(cfg(feature = "traced-error")))] +pub struct TracedError<E> { + inner: ErrorImpl<E>, +} + +impl<E> From<E> for TracedError<E> +where + E: Error + Send + Sync + 'static, +{ + fn from(error: E) -> Self { + // # SAFETY + // + // This function + the repr(C) on the ErrorImpl make the type erasure throughout the rest + // of this struct's methods safe. This saves a function pointer that is parameterized on the Error type + // being stored inside the ErrorImpl. This lets the object_ref function safely cast a type + // erased `ErrorImpl` back to its original type, which is needed in order to forward our + // error/display/debug impls to the internal error type from the type erased error type. + // + // The repr(C) is necessary to ensure that the struct is layed out in the order we + // specified it so that we can safely access the vtable and spantrace fields thru a type + // erased pointer to the original object. + let vtable = &ErrorVTable { + object_ref: object_ref::<E>, + }; + + Self { + inner: ErrorImpl { + vtable, + span_trace: SpanTrace::capture(), + error, + }, + } + } +} + +#[repr(C)] +struct ErrorImpl<E> { + vtable: &'static ErrorVTable, + span_trace: SpanTrace, + // NOTE: Don't use directly. Use only through vtable. Erased type may have + // different alignment. + error: E, +} + +impl ErrorImpl<Erased> { + pub(crate) fn error(&self) -> &(dyn Error + Send + Sync + 'static) { + // # SAFETY + // + // this function is used to cast a type-erased pointer to a pointer to error's + // original type. the `ErrorImpl::error` method, which calls this function, requires that + // the type this function casts to be the original erased type of the error; failure to + // uphold this is UB. since the `From` impl is parameterized over the original error type, + // the function pointer we construct here will also retain the original type. therefore, + // when this is consumed by the `error` method, it will be safe to call. + unsafe { &*(self.vtable.object_ref)(self) } + } +} + +struct ErrorVTable { + object_ref: unsafe fn(&ErrorImpl<Erased>) -> &(dyn Error + Send + Sync + 'static), +} + +// # SAFETY +// +// This function must be parameterized on the type E of the original error that is being stored +// inside of the `ErrorImpl`. When it is parameterized by the correct type, it safely +// casts the erased `ErrorImpl` pointer type back to the original pointer type. +unsafe fn object_ref<E>(e: &ErrorImpl<Erased>) -> &(dyn Error + Send + Sync + 'static) +where + E: Error + Send + Sync + 'static, +{ + // Attach E's native Error vtable onto a pointer to e.error. + &(*(e as *const ErrorImpl<Erased> as *const ErrorImpl<E>)).error +} + +impl<E> Error for TracedError<E> +where + E: std::error::Error + 'static, +{ + // # SAFETY + // + // This function is safe so long as all functions on `ErrorImpl<Erased>` uphold the invariant + // that the wrapped error is only ever accessed by the `error` method. This method uses the + // function in the vtable to safely convert the pointer type back to the original type, and + // then returns the reference to the erased error. + // + // This function is necessary for the `downcast_ref` in `ExtractSpanTrace` to work, because it + // needs a concrete type to downcast to and we cannot downcast to ErrorImpls parameterized on + // errors defined in other crates. By erasing the type here we can always cast back to the + // Erased version of the ErrorImpl pointer, and still access the internal error type safely + // through the vtable. + fn source<'a>(&'a self) -> Option<&'a (dyn Error + 'static)> { + let erased = unsafe { &*(&self.inner as *const ErrorImpl<E> as *const ErrorImpl<Erased>) }; + Some(erased) + } +} + +impl<E> Debug for TracedError<E> +where + E: std::error::Error, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Debug::fmt(&self.inner.error, f) + } +} + +impl<E> Display for TracedError<E> +where + E: std::error::Error, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + Display::fmt(&self.inner.error, f) + } +} + +impl Error for ErrorImpl<Erased> { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.error().source() + } +} + +impl Debug for ErrorImpl<Erased> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("span backtrace:\n")?; + Debug::fmt(&self.span_trace, f) + } +} + +impl Display for ErrorImpl<Erased> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("span backtrace:\n")?; + Display::fmt(&self.span_trace, f) + } +} + +/// Extension trait for instrumenting errors with `SpanTrace`s +#[cfg_attr(docsrs, doc(cfg(feature = "traced-error")))] +pub trait InstrumentError { + /// The type of the wrapped error after instrumentation + type Instrumented; + + /// Instrument an Error by bundling it with a SpanTrace + /// + /// # Examples + /// + /// ```rust + /// use tracing_error::{TracedError, InstrumentError}; + /// + /// fn wrap_error<E>(e: E) -> TracedError<E> + /// where + /// E: std::error::Error + Send + Sync + 'static + /// { + /// e.in_current_span() + /// } + /// ``` + fn in_current_span(self) -> Self::Instrumented; +} + +/// Extension trait for instrumenting errors in `Result`s with `SpanTrace`s +#[cfg_attr(docsrs, doc(cfg(feature = "traced-error")))] +pub trait InstrumentResult<T> { + /// The type of the wrapped error after instrumentation + type Instrumented; + + /// Instrument an Error by bundling it with a SpanTrace + /// + /// # Examples + /// + /// ```rust + /// # use std::{io, fs}; + /// use tracing_error::{TracedError, InstrumentResult}; + /// + /// # fn fallible_fn() -> io::Result<()> { fs::read_dir("......").map(drop) }; + /// + /// fn do_thing() -> Result<(), TracedError<io::Error>> { + /// fallible_fn().in_current_span() + /// } + /// ``` + fn in_current_span(self) -> Result<T, Self::Instrumented>; +} + +impl<T, E> InstrumentResult<T> for Result<T, E> +where + E: InstrumentError, +{ + type Instrumented = <E as InstrumentError>::Instrumented; + + fn in_current_span(self) -> Result<T, Self::Instrumented> { + self.map_err(E::in_current_span) + } +} + +/// A trait for extracting SpanTraces created by `in_current_span()` from `dyn +/// Error` trait objects +#[cfg_attr(docsrs, doc(cfg(feature = "traced-error")))] +pub trait ExtractSpanTrace { + /// Attempts to downcast to a `TracedError` and return a reference to its + /// SpanTrace + /// + /// # Examples + /// + /// ```rust + /// use tracing_error::ExtractSpanTrace; + /// use std::error::Error; + /// + /// fn print_span_trace(e: &(dyn Error + 'static)) { + /// let span_trace = e.span_trace(); + /// if let Some(span_trace) = span_trace { + /// println!("{}", span_trace); + /// } + /// } + /// ``` + fn span_trace(&self) -> Option<&SpanTrace>; +} + +impl<E> InstrumentError for E +where + TracedError<E>: From<E>, +{ + type Instrumented = TracedError<E>; + + fn in_current_span(self) -> Self::Instrumented { + TracedError::from(self) + } +} + +impl ExtractSpanTrace for dyn Error + 'static { + fn span_trace(&self) -> Option<&SpanTrace> { + self.downcast_ref::<ErrorImpl<Erased>>() + .map(|inner| &inner.span_trace) + } +} diff --git a/vendor/tracing-error/src/layer.rs b/vendor/tracing-error/src/layer.rs new file mode 100644 index 000000000..14c019258 --- /dev/null +++ b/vendor/tracing-error/src/layer.rs @@ -0,0 +1,132 @@ +use std::any::{type_name, TypeId}; +use std::fmt; +use std::marker::PhantomData; +use tracing::{span, Dispatch, Metadata, Subscriber}; +use tracing_subscriber::fmt::format::{DefaultFields, FormatFields}; +use tracing_subscriber::{ + fmt::FormattedFields, + layer::{self, Layer}, + registry::LookupSpan, +}; + +/// A subscriber [`Layer`] that enables capturing [`SpanTrace`]s. +/// +/// Optionally, this type may be constructed with a [field formatter] to use +/// when formatting the fields of each span in a trace. When no formatter is +/// provided, the [default format] is used instead. +/// +/// [`Layer`]: https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/layer/trait.Layer.html +/// [`SpanTrace`]: ../struct.SpanTrace.html +/// [field formatter]: https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/fmt/trait.FormatFields.html +/// [default format]: https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/fmt/format/struct.DefaultFields.html +pub struct ErrorLayer<S, F = DefaultFields> { + format: F, + + get_context: WithContext, + _subscriber: PhantomData<fn(S)>, +} + +// this function "remembers" the types of the subscriber and the formatter, +// so that we can downcast to something aware of them without knowing those +// types at the callsite. +pub(crate) struct WithContext( + fn(&Dispatch, &span::Id, f: &mut dyn FnMut(&'static Metadata<'static>, &str) -> bool), +); + +impl<S, F> Layer<S> for ErrorLayer<S, F> +where + S: Subscriber + for<'span> LookupSpan<'span>, + F: for<'writer> FormatFields<'writer> + 'static, +{ + /// Notifies this layer that a new span was constructed with the given + /// `Attributes` and `Id`. + fn on_new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: layer::Context<'_, S>) { + let span = ctx.span(id).expect("span must already exist!"); + if span.extensions().get::<FormattedFields<F>>().is_some() { + return; + } + let mut fields = FormattedFields::<F>::new(String::new()); + if self.format.format_fields(fields.as_writer(), attrs).is_ok() { + span.extensions_mut().insert(fields); + } + } + + unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> { + match id { + id if id == TypeId::of::<Self>() => Some(self as *const _ as *const ()), + id if id == TypeId::of::<WithContext>() => { + Some(&self.get_context as *const _ as *const ()) + } + _ => None, + } + } +} + +impl<S, F> ErrorLayer<S, F> +where + F: for<'writer> FormatFields<'writer> + 'static, + S: Subscriber + for<'span> LookupSpan<'span>, +{ + /// Returns a new `ErrorLayer` with the provided [field formatter]. + /// + /// [field formatter]: https://docs.rs/tracing-subscriber/0.2.10/tracing_subscriber/fmt/trait.FormatFields.html + pub fn new(format: F) -> Self { + Self { + format, + get_context: WithContext(Self::get_context), + _subscriber: PhantomData, + } + } + + fn get_context( + dispatch: &Dispatch, + id: &span::Id, + f: &mut dyn FnMut(&'static Metadata<'static>, &str) -> bool, + ) { + let subscriber = dispatch + .downcast_ref::<S>() + .expect("subscriber should downcast to expected type; this is a bug!"); + let span = subscriber + .span(id) + .expect("registry should have a span for the current ID"); + for span in span.scope() { + let cont = if let Some(fields) = span.extensions().get::<FormattedFields<F>>() { + f(span.metadata(), fields.fields.as_str()) + } else { + f(span.metadata(), "") + }; + if !cont { + break; + } + } + } +} + +impl WithContext { + pub(crate) fn with_context<'a>( + &self, + dispatch: &'a Dispatch, + id: &span::Id, + mut f: impl FnMut(&'static Metadata<'static>, &str) -> bool, + ) { + (self.0)(dispatch, id, &mut f) + } +} + +impl<S> Default for ErrorLayer<S> +where + S: Subscriber + for<'span> LookupSpan<'span>, +{ + fn default() -> Self { + Self::new(DefaultFields::default()) + } +} + +impl<S, F: fmt::Debug> fmt::Debug for ErrorLayer<S, F> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ErrorLayer") + .field("format", &self.format) + .field("subscriber", &format_args!("{}", type_name::<S>())) + .finish() + } +} diff --git a/vendor/tracing-error/src/lib.rs b/vendor/tracing-error/src/lib.rs new file mode 100644 index 000000000..611bc9f79 --- /dev/null +++ b/vendor/tracing-error/src/lib.rs @@ -0,0 +1,236 @@ +//! Utilities for enriching error handling with [`tracing`] diagnostic +//! information. +//! +//! # Overview +//! +//! [`tracing`] is a framework for instrumenting Rust programs to collect +//! scoped, structured, and async-aware diagnostics. This crate provides +//! integrations between [`tracing`] instrumentation and Rust error handling. It +//! enables enriching error types with diagnostic information from `tracing` +//! [span] contexts, formatting those contexts when errors are displayed, and +//! automatically generate `tracing` [events] when errors occur. +//! +//! The crate provides the following: +//! +//! * [`SpanTrace`], a captured trace of the current `tracing` [span] context +//! +//! * [`ErrorLayer`], a [subscriber layer] which enables capturing `SpanTrace`s +//! +//! **Note**: This crate is currently experimental. +//! +//! *Compiler support: [requires `rustc` 1.42+][msrv]* +//! +//! [msrv]: #supported-rust-versions +//! +//! ## Feature Flags +//! +//! - `traced-error` - Enables the [`TracedError`] type and related Traits +//! - [`InstrumentResult`] and [`InstrumentError`] extension traits, which +//! provide an [`in_current_span()`] method for bundling errors with a +//! [`SpanTrace`]. +//! - [`ExtractSpanTrace`] extension trait, for extracting `SpanTrace`s from +//! behind `dyn Error` trait objects. +//! +//! ## Usage +//! +//! `tracing-error` provides the [`SpanTrace`] type, which captures the current +//! `tracing` span context when it is constructed and allows it to be displayed +//! at a later time. +//! +//! For example: +//! +//! ```rust +//! use std::{fmt, error::Error}; +//! use tracing_error::SpanTrace; +//! +//! #[derive(Debug)] +//! pub struct MyError { +//! context: SpanTrace, +//! // ... +//! } +//! +//! impl fmt::Display for MyError { +//! fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +//! // ... format other parts of the error ... +//! +//! self.context.fmt(f)?; +//! +//! // ... format other error context information, cause chain, etc ... +//! # Ok(()) +//! } +//! } +//! +//! impl Error for MyError {} +//! +//! impl MyError { +//! pub fn new() -> Self { +//! Self { +//! context: SpanTrace::capture(), +//! // ... other error information ... +//! } +//! } +//! } +//! ``` +//! +//! This crate also provides [`TracedError`], for attaching a [`SpanTrace`] to +//! an existing error. The easiest way to wrap errors in `TracedError` is to +//! either use the [`InstrumentResult`] and [`InstrumentError`] traits or the +//! `From`/`Into` traits. +//! +//! ```rust +//! # use std::error::Error; +//! use tracing_error::prelude::*; +//! +//! # fn fake_main() -> Result<(), Box<dyn Error>> { +//! std::fs::read_to_string("myfile.txt").in_current_span()?; +//! # Ok(()) +//! # } +//! ``` +//! +//! Once an error has been wrapped with with a [`TracedError`] the [`SpanTrace`] +//! can be extracted one of 3 ways: either via [`TracedError`]'s +//! `Display`/`Debug` implementations, or via the [`ExtractSpanTrace`] trait. +//! +//! For example, here is how one might print the errors but specialize the +//! printing when the error is a placeholder for a wrapping [`SpanTrace`]: +//! +//! ```rust +//! use std::error::Error; +//! use tracing_error::ExtractSpanTrace as _; +//! +//! fn print_extracted_spantraces(error: &(dyn Error + 'static)) { +//! let mut error = Some(error); +//! let mut ind = 0; +//! +//! eprintln!("Error:"); +//! +//! while let Some(err) = error { +//! if let Some(spantrace) = err.span_trace() { +//! eprintln!("found a spantrace:\n{}", spantrace); +//! } else { +//! eprintln!("{:>4}: {}", ind, err); +//! } +//! +//! error = err.source(); +//! ind += 1; +//! } +//! } +//! +//! ``` +//! +//! Whereas here, we can still display the content of the `SpanTraces` without +//! any special casing by simply printing all errors in our error chain. +//! +//! ```rust +//! use std::error::Error; +//! +//! fn print_naive_spantraces(error: &(dyn Error + 'static)) { +//! let mut error = Some(error); +//! let mut ind = 0; +//! +//! eprintln!("Error:"); +//! +//! while let Some(err) = error { +//! eprintln!("{:>4}: {}", ind, err); +//! error = err.source(); +//! ind += 1; +//! } +//! } +//! ``` +//! +//! Applications that wish to use `tracing-error`-enabled errors should +//! construct an [`ErrorLayer`] and add it to their [`Subscriber`] in order to +//! enable capturing [`SpanTrace`]s. For example: +//! +//! ```rust +//! use tracing_error::ErrorLayer; +//! use tracing_subscriber::prelude::*; +//! +//! fn main() { +//! let subscriber = tracing_subscriber::Registry::default() +//! // any number of other subscriber layers may be added before or +//! // after the `ErrorLayer`... +//! .with(ErrorLayer::default()); +//! +//! // set the subscriber as the default for the application +//! tracing::subscriber::set_global_default(subscriber); +//! } +//! ``` +//! +//! [`SpanTrace`]: struct.SpanTrace.html +//! [`ErrorLayer`]: struct.ErrorLayer.html +//! [`TracedError`]: struct.TracedError.html +//! [`InstrumentResult`]: trait.InstrumentResult.html +//! [`InstrumentError`]: trait.InstrumentError.html +//! [`ExtractSpanTrace`]: trait.ExtractSpanTrace.html +//! [`in_current_span()`]: trait.InstrumentResult.html#tymethod.in_current_span +//! [span]: https://docs.rs/tracing/latest/tracing/span/index.html +//! [events]: https://docs.rs/tracing/latest/tracing/struct.Event.html +//! [`Subscriber`]: https://docs.rs/tracing/latest/tracing/trait.Subscriber.html +//! [subscriber layer]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/layer/trait.Layer.html +//! [`tracing`]: https://docs.rs/tracing +//! [`std::error::Error`]: https://doc.rust-lang.org/stable/std/error/trait.Error.html +//! +//! ## Supported Rust Versions +//! +//! Tracing is built against the latest stable release. The minimum supported +//! version is 1.42. The current Tracing version is not guaranteed to build on +//! Rust versions earlier than the minimum supported version. +//! +//! Tracing follows the same compiler support policies as the rest of the Tokio +//! project. The current stable Rust compiler and the three most recent minor +//! versions before it will always be supported. For example, if the current +//! stable compiler version is 1.45, the minimum supported version will not be +//! increased past 1.42, three minor versions prior. Increasing the minimum +//! supported compiler version is not considered a semver breaking change as +//! long as doing so complies with this policy. +//! +#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))] +#![doc(html_root_url = "https://docs.rs/tracing-error/0.2.0")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png", + issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/" +)] +#![warn( + missing_debug_implementations, + missing_docs, + rust_2018_idioms, + unreachable_pub, + bad_style, + const_err, + dead_code, + improper_ctypes, + non_shorthand_field_patterns, + no_mangle_generic_items, + overflowing_literals, + path_statements, + patterns_in_fns_without_body, + private_in_public, + unconditional_recursion, + unused, + unused_allocation, + unused_comparisons, + unused_parens, + while_true +)] +mod backtrace; +#[cfg(feature = "traced-error")] +mod error; +mod layer; + +pub use self::backtrace::{SpanTrace, SpanTraceStatus}; +#[cfg(feature = "traced-error")] +pub use self::error::{ExtractSpanTrace, InstrumentError, InstrumentResult, TracedError}; +pub use self::layer::ErrorLayer; + +#[cfg(feature = "traced-error")] +#[cfg_attr(docsrs, doc(cfg(feature = "traced-error")))] +pub mod prelude { + //! The `tracing-error` prelude. + //! + //! This brings into scope the `InstrumentError, `InstrumentResult`, and `ExtractSpanTrace` + //! extension traits. These traits allow attaching `SpanTrace`s to errors and + //! subsequently retrieving them from `dyn Error` trait objects. + + pub use crate::{ExtractSpanTrace as _, InstrumentError as _, InstrumentResult as _}; +} |