mirror of
				https://github.com/tokio-rs/tracing.git
				synced 2025-11-04 07:23:02 +00:00 
			
		
		
		
	## Motivation As outlined in #399, right now `tracing-futures` (or more precisely, the code generated by `#[instrument]`) is not working well with async-trait. What happens is that async-trait rewrites the trait method as a non-async function, insides of which it pins the async method we want to instrument, and we end up instrumenting the wrapper instead of the async fn. This will allow people to use traits with (seemingly) async functions along with `#[instrument]`. ## Solution I decided to follow the discussion at https://github.com/dtolnay/async-trait/issues/45 and see if I could make it working. Right now I would describe its state as "works for me, and *should* work for everyone". The `instrument` macro will now: * Rewrite the block when it looks like there is async_trait involved to wrap the internal async function instead of the wrapper generated by `async-trait` * Rewrite '_self' as 'self' when using #[instrument] jointly with `async-trait` Fixes #399
		
			
				
	
	
		
			153 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			153 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
#[path = "../../tracing-futures/tests/support.rs"]
 | 
						|
// we don't use some of the test support functions, but `tracing-futures` does.
 | 
						|
#[allow(dead_code)]
 | 
						|
mod support;
 | 
						|
use support::*;
 | 
						|
 | 
						|
use tracing::subscriber::with_default;
 | 
						|
use tracing_attributes::instrument;
 | 
						|
 | 
						|
#[instrument]
 | 
						|
async fn test_async_fn(polls: usize) -> Result<(), ()> {
 | 
						|
    let future = PollN::new_ok(polls);
 | 
						|
    tracing::trace!(awaiting = true);
 | 
						|
    future.await
 | 
						|
}
 | 
						|
 | 
						|
#[test]
 | 
						|
fn async_fn_only_enters_for_polls() {
 | 
						|
    let (subscriber, handle) = subscriber::mock()
 | 
						|
        .new_span(span::mock().named("test_async_fn"))
 | 
						|
        .enter(span::mock().named("test_async_fn"))
 | 
						|
        .event(event::mock().with_fields(field::mock("awaiting").with_value(&true)))
 | 
						|
        .exit(span::mock().named("test_async_fn"))
 | 
						|
        .enter(span::mock().named("test_async_fn"))
 | 
						|
        .exit(span::mock().named("test_async_fn"))
 | 
						|
        .drop_span(span::mock().named("test_async_fn"))
 | 
						|
        .done()
 | 
						|
        .run_with_handle();
 | 
						|
    with_default(subscriber, || {
 | 
						|
        block_on_future(async { test_async_fn(2).await }).unwrap();
 | 
						|
    });
 | 
						|
    handle.assert_finished();
 | 
						|
}
 | 
						|
 | 
						|
#[test]
 | 
						|
fn async_fn_nested() {
 | 
						|
    #[instrument]
 | 
						|
    async fn test_async_fns_nested() {
 | 
						|
        test_async_fns_nested_other().await
 | 
						|
    }
 | 
						|
 | 
						|
    #[instrument]
 | 
						|
    async fn test_async_fns_nested_other() {
 | 
						|
        tracing::trace!(nested = true);
 | 
						|
    }
 | 
						|
 | 
						|
    let span = span::mock().named("test_async_fns_nested");
 | 
						|
    let span2 = span::mock().named("test_async_fns_nested_other");
 | 
						|
    let (subscriber, handle) = subscriber::mock()
 | 
						|
        .new_span(span.clone())
 | 
						|
        .enter(span.clone())
 | 
						|
        .new_span(span2.clone())
 | 
						|
        .enter(span2.clone())
 | 
						|
        .event(event::mock().with_fields(field::mock("nested").with_value(&true)))
 | 
						|
        .exit(span2.clone())
 | 
						|
        .drop_span(span2)
 | 
						|
        .exit(span.clone())
 | 
						|
        .drop_span(span)
 | 
						|
        .done()
 | 
						|
        .run_with_handle();
 | 
						|
 | 
						|
    with_default(subscriber, || {
 | 
						|
        block_on_future(async { test_async_fns_nested().await });
 | 
						|
    });
 | 
						|
 | 
						|
    handle.assert_finished();
 | 
						|
}
 | 
						|
 | 
						|
#[test]
 | 
						|
fn async_fn_with_async_trait() {
 | 
						|
    use async_trait::async_trait;
 | 
						|
 | 
						|
    // test the correctness of the metadata obtained by #[instrument]
 | 
						|
    // (function name, functions parameters) when async-trait is used
 | 
						|
    #[async_trait]
 | 
						|
    pub trait TestA {
 | 
						|
        async fn foo(&mut self, v: usize);
 | 
						|
    }
 | 
						|
 | 
						|
    // test nesting of async fns with aync-trait
 | 
						|
    #[async_trait]
 | 
						|
    pub trait TestB {
 | 
						|
        async fn bar(&self);
 | 
						|
    }
 | 
						|
 | 
						|
    // test skip(self) with async-await
 | 
						|
    #[async_trait]
 | 
						|
    pub trait TestC {
 | 
						|
        async fn baz(&self);
 | 
						|
    }
 | 
						|
 | 
						|
    #[derive(Debug)]
 | 
						|
    struct TestImpl(usize);
 | 
						|
 | 
						|
    #[async_trait]
 | 
						|
    impl TestA for TestImpl {
 | 
						|
        #[instrument]
 | 
						|
        async fn foo(&mut self, v: usize) {
 | 
						|
            self.baz().await;
 | 
						|
            self.0 = v;
 | 
						|
            self.bar().await
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    #[async_trait]
 | 
						|
    impl TestB for TestImpl {
 | 
						|
        #[instrument]
 | 
						|
        async fn bar(&self) {
 | 
						|
            tracing::trace!(val = self.0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    #[async_trait]
 | 
						|
    impl TestC for TestImpl {
 | 
						|
        #[instrument(skip(self))]
 | 
						|
        async fn baz(&self) {
 | 
						|
            tracing::trace!(val = self.0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    let span = span::mock().named("foo");
 | 
						|
    let span2 = span::mock().named("bar");
 | 
						|
    let span3 = span::mock().named("baz");
 | 
						|
    let (subscriber, handle) = subscriber::mock()
 | 
						|
        .new_span(
 | 
						|
            span.clone()
 | 
						|
                .with_field(field::mock("self"))
 | 
						|
                .with_field(field::mock("v")),
 | 
						|
        )
 | 
						|
        .enter(span.clone())
 | 
						|
        .new_span(span3.clone())
 | 
						|
        .enter(span3.clone())
 | 
						|
        .event(event::mock().with_fields(field::mock("val").with_value(&2u64)))
 | 
						|
        .exit(span3.clone())
 | 
						|
        .drop_span(span3)
 | 
						|
        .new_span(span2.clone().with_field(field::mock("self")))
 | 
						|
        .enter(span2.clone())
 | 
						|
        .event(event::mock().with_fields(field::mock("val").with_value(&5u64)))
 | 
						|
        .exit(span2.clone())
 | 
						|
        .drop_span(span2)
 | 
						|
        .exit(span.clone())
 | 
						|
        .drop_span(span)
 | 
						|
        .done()
 | 
						|
        .run_with_handle();
 | 
						|
 | 
						|
    with_default(subscriber, || {
 | 
						|
        let mut test = TestImpl(2);
 | 
						|
        block_on_future(async { test.foo(5).await });
 | 
						|
    });
 | 
						|
 | 
						|
    handle.assert_finished();
 | 
						|
}
 |