Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove experimental parts of tracing-error #547

Merged
merged 12 commits into from
Jan 29, 2020
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ async fn write(stream: &mut TcpStream) -> io::Result<usize> {
Under the hood, the `#[instrument]` macro performs same the explicit span
attachment that `Future::instrument` does.

Note: the [`#[tracing::instrument]`](https://github.com/tokio-rs/tracing/issues/399)` macro does work correctly with the [async-trait](https://github.com/dtolnay/async-trait) crate. This bug is tracked in [#399](https://github.com/tokio-rs/tracing/issues/399).
Note: the [`#[tracing::instrument]`](https://github.com/tokio-rs/tracing/issues/399)` macro does not work correctly with the [async-trait](https://github.com/dtolnay/async-trait) crate. This bug is tracked in [#399](https://github.com/tokio-rs/tracing/issues/399).

## Getting Help

Expand Down
26 changes: 16 additions & 10 deletions examples/examples/error.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
#![deny(rust_2018_idioms)]
use std::error::Error;
use std::fmt;
use tracing::debug;
use tracing_error::{ErrorLayer, TraceError};
use tracing_subscriber::{fmt::Layer as FmtLayer, registry::Registry, Layer, prelude::*};
use std::fmt::{self, Write as _};
use tracing_error::{ErrorLayer, SpanTrace};
use tracing_subscriber::{fmt::Layer as FmtLayer, prelude::*, registry::Registry};

#[tracing::instrument]
fn do_something(foo: &str) -> Result<&'static str, impl Error + Send + Sync + 'static> {
match do_another_thing(42, false) {
Ok(i) => Ok(i),
Err(e) => Err(FooError::new("something broke, lol", e).in_context()),
Err(e) => Err(FooError::new("something broke, lol", e)),
}
}
#[derive(Debug)]
struct FooError {
message: &'static str,
source: Box<dyn Error + Send + Sync + 'static>,
context: SpanTrace,
}

impl FooError {
Expand All @@ -26,6 +26,7 @@ impl FooError {
Self {
message,
source: source.into(),
context: SpanTrace::capture(),
}
}
}
Expand All @@ -38,7 +39,9 @@ impl Error for FooError {

impl fmt::Display for FooError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad(self.message)
f.pad(self.message)?;
f.write_char('\n')?;
write!(f, "{}", self.context)
yaahc marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -47,17 +50,20 @@ fn do_another_thing(
answer: usize,
will_succeed: bool,
) -> Result<&'static str, impl Error + Send + Sync + 'static> {
Err(std::io::Error::new(std::io::ErrorKind::Other, "something else broke!").in_context())
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"something else broke!",
))
}

#[tracing::instrument]
fn main() {
let subscriber = Registry::default()
.with(ErrorLayer::default())
.with(FmtLayer::default());
.with(FmtLayer::default())
.with(ErrorLayer::default());
yaahc marked this conversation as resolved.
Show resolved Hide resolved
tracing::subscriber::set_global_default(subscriber).expect("Could not set global default");
match do_something("hello world") {
Ok(result) => println!("did something successfully: {}", result),
Err(e) => eprintln!("error: {}", e.span_backtrace()),
Err(e) => eprintln!("error: {}", e),
};
}
74 changes: 74 additions & 0 deletions tracing-error/src/backtrace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::layer::WithContext;
use std::fmt;
use tracing::{Metadata, Span};

#[derive(Clone)]
pub struct SpanTrace {
span: Span,
}

// === impl SpanTrace ===

impl SpanTrace {
pub fn capture() -> Self {
SpanTrace {
span: Span::current(),
}
}

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);
}
});
}
}

macro_rules! try_bool {
($e:expr, $dest:ident) => {{
let ret = $e.unwrap_or_else(|e| $dest = Some(e));
if $dest.is_some() {
return false;
}
ret
}};
}

impl fmt::Display for SpanTrace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut err = None;
let mut span = 0;

writeln!(f, "span backtrace:")?;
yaahc marked this conversation as resolved.
Show resolved Hide resolved
self.with_spans(|metadata, fields| {
try_bool!(
writeln!(f, "{:>4}: {}::{}", span, metadata.target(), metadata.name()),
yaahc marked this conversation as resolved.
Show resolved Hide resolved
err
);
if !fields.is_empty() {
try_bool!(writeln!(f, " with {}", fields), err);
yaahc marked this conversation as resolved.
Show resolved Hide resolved
}
if let Some((file, line)) = metadata
.file()
.and_then(|file| metadata.line().map(|line| (file, line)))
{
try_bool!(writeln!(f, " at {}:{}", file, line), err);
yaahc marked this conversation as resolved.
Show resolved Hide resolved
}

span += 1;
yaahc marked this conversation as resolved.
Show resolved Hide resolved
true
});

match err {
Some(e) => Err(e),
_ => Ok(()),
}
}
yaahc marked this conversation as resolved.
Show resolved Hide resolved
}

impl fmt::Debug for SpanTrace {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
}
}
43 changes: 0 additions & 43 deletions tracing-error/src/ctx.rs

This file was deleted.

26 changes: 0 additions & 26 deletions tracing-error/src/fmt.rs

This file was deleted.

37 changes: 22 additions & 15 deletions tracing-error/src/layer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use super::fmt::{DefaultFields, FormatFields};
use super::{Context, ContextSpan};
use std::any::TypeId;
use std::marker::PhantomData;
use tracing::{span, Subscriber, Metadata, Dispatch};
use tracing::{span, Dispatch, Metadata, Subscriber};
use tracing_subscriber::fmt::format::{DefaultFields, FormatFields};
use tracing_subscriber::{
fmt::FormattedFields,
layer::{self, Layer},
Expand All @@ -19,7 +18,9 @@ pub struct ErrorLayer<S, F = DefaultFields> {
// 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));
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
Expand All @@ -34,9 +35,10 @@ where
return;
}
let mut fields = String::new();
self.format.format_fields(&mut fields, attrs);
span.extensions_mut()
.insert(FormattedFields::<F>::new(fields));
if self.format.format_fields(&mut fields, attrs).is_ok() {
yaahc marked this conversation as resolved.
Show resolved Hide resolved
span.extensions_mut()
.insert(FormattedFields::<F>::new(fields));
}
}

unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
Expand All @@ -63,7 +65,11 @@ where
}
}

fn get_context(dispatch: &Dispatch, id: &span::Id, f: &mut dyn FnMut(&'static Metadata<'static>, &str) -> bool) {
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!");
Expand All @@ -72,24 +78,25 @@ where
.expect("registry should have a span for the current ID");
let parents = span.parents();
for span in std::iter::once(span).chain(parents) {
let cont = if let Some(fields) = span
.extensions()
.get::<FormattedFields<F>>()
{
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
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) {
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)
}
}
Expand Down
78 changes: 2 additions & 76 deletions tracing-error/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,79 +1,5 @@
mod ctx;
pub mod fmt;
mod backtrace;
mod layer;
use std::error::Error;
use tracing::{dispatcher, Metadata};

pub use self::ctx::*;
pub use self::backtrace::SpanTrace;
pub use self::layer::ErrorLayer;

pub struct ContextError {
inner: Box<dyn Error + Send + Sync>,
context: Context,
}

impl ContextError {
pub fn from_error(error: Box<dyn Error + Send + Sync + 'static>) -> Self {
ContextError {
inner: error,
context: Context::current(),
}
}

pub fn context(&self) -> &Context {
&self.context
}

pub fn span_backtrace(&self) -> fmt::SpanBacktrace<&Self> {
fmt::SpanBacktrace::new(self)
}
}

pub trait TraceError: Error {
fn in_context(self) -> ContextError
where
Self: Sized + Send + Sync + 'static,
{
ContextError::from_error(Box::new(self))
}

fn context(&self) -> Option<&Context>
where
Self: Sized + 'static,
{
let cx = (self as &dyn Error)
.downcast_ref::<ContextError>()?
.context();
Some(cx)
}

fn span_backtrace(&self) -> fmt::SpanBacktrace<&(dyn Error + 'static)>
where
Self: Sized + 'static,
{
fmt::SpanBacktrace::new(self as &dyn Error)
}
}
yaahc marked this conversation as resolved.
Show resolved Hide resolved

impl<T> TraceError for T where T: Error {}

impl std::fmt::Display for ContextError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.inner.fmt(f)
}
}

impl std::fmt::Debug for ContextError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ContextError")
.field("inner", &self.inner)
.field("context", &self.context)
.finish()
}
}

impl Error for ContextError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
self.inner.source()
}
}
Loading