summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-error/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /vendor/tracing-error/src
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/tracing-error/src')
-rw-r--r--vendor/tracing-error/src/backtrace.rs320
-rw-r--r--vendor/tracing-error/src/error.rs289
-rw-r--r--vendor/tracing-error/src/layer.rs132
-rw-r--r--vendor/tracing-error/src/lib.rs236
4 files changed, 977 insertions, 0 deletions
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 _};
+}