Skip to content
This repository has been archived by the owner on Jan 12, 2019. It is now read-only.

First pass at #[trace] macro. #16

Merged
merged 6 commits into from
Oct 29, 2018
Merged

First pass at #[trace] macro. #16

merged 6 commits into from
Oct 29, 2018

Conversation

davidbarsky
Copy link
Collaborator

@davidbarsky davidbarsky commented Sep 30, 2018

Attributes, generics, and other stuff seems to be handled mostly correctly. The main thing that's missing is inserting the function's parameters into a span and checking that a type is clone-able.

The relevant part of the cargo expand on the example crate is this:

fn main() {
    tokio_trace::Dispatcher::builder()
        .add_subscriber(SloggishSubscriber::new(2))
        .init();
    let server_span = ::Span::new(
        Some("server"),
        ::std::time::Instant::now(),
        Some(::Span::current()),
        &::Meta {
            target: None,
            level: ::Level::Trace,
            module_path: "example",
            file: "tokio-trace-macros/example/src/main.rs",
            line: 16u32,
            field_names: &["local_port"],
        },
        <[_]>::into_vec(box [Box::new(8888)]),
    );
    server_span.clone().enter(move || {
        suggest_band("Parquet Courts");
    });
}
#[deprecated]
#[warn(missing_docs)]
fn suggest_band(band: &str) -> String {
    ::Span::new(
        Some("suggest_band"),
        ::std::time::Instant::now(),
        Some(::Span::current()),
        &::Meta {
            target: None,
            level: ::Level::Trace,
            module_path: "example",
            file: "tokio-trace-macros/example/src/main.rs",
            line: 22u32,
            field_names: &["traced_function"],
        },
        <[_]>::into_vec(box [Box::new("suggest_band")]),
    )
    .enter(move || {
        {
            {
                let field_values: &[&dyn::Value] = &[&band.to_string()];
                use Subscriber;
                ::Dispatcher::current().observe_event(&::Event {
                    timestamp: ::std::time::Instant::now(),
                    parent: ::Span::current().into(),
                    follows_from: &[],
                    meta: &::Meta {
                        target: None,
                        level: Level::Info,
                        module_path: "example",
                        file: "tokio-trace-macros/example/src/main.rs",
                        line: 26u32,
                        field_names: &["band"],
                    },
                    field_values: &field_values[..],
                    message: ::std::fmt::Arguments::new_v1(
                        &["suggested a band"],
                        &match () {
                            () => [],
                        },
                    ),
                });
            }
        };
        ::fmt::format(::std::fmt::Arguments::new_v1_formatted(
            &["Have you listened to ", "?"],
            &match (&band,) {
                (arg0,) => [::std::fmt::ArgumentV1::new(arg0, ::std::fmt::Display::fmt)],
            },
            &[::std::fmt::rt::v1::Argument {
                position: ::std::fmt::rt::v1::Position::At(0usize),
                format: ::std::fmt::rt::v1::FormatSpec {
                    fill: ' ',
                    align: ::std::fmt::rt::v1::Alignment::Unknown,
                    flags: 0u32,
                    precision: ::std::fmt::rt::v1::Count::Implied,
                    width: ::std::fmt::rt::v1::Count::Implied,
                },
            }],
        ))
    })
}

@davidbarsky
Copy link
Collaborator Author

Travis is broken, I'll need to add a feature flag on the proc macro feature on stable/beta.

tokio-trace-macros/tokio-trace-macros/src/lib.rs Outdated Show resolved Hide resolved
@davidbarsky
Copy link
Collaborator Author

davidbarsky commented Oct 1, 2018

I removed the feature flag #![feature(proc_macro_diagnostic)] in tokio-trace-macros, but I'm getting an error on stable that looks like:

error[E0658]: attribute procedural macros are experimental (see issue #35896)
  --> tokio-trace-macros/example/src/main.rs:22:1
   |
3  | #[macro_use]
   | ------------ procedural macro imported here
...
22 | #[trace]
   | ^^^^^^^^

This is expected, but I wonder how I can tell Travis to only build anything under tokio-trace-macros under nightly only.

@carllerche
Copy link
Collaborator

I definitely like this idea 👍 ( haven't reviewed the PR).

@davidbarsky
Copy link
Collaborator Author

davidbarsky commented Oct 5, 2018 via email

@carllerche
Copy link
Collaborator

I'm guessing that this will have the most win w/ async/await.

@davidbarsky
Copy link
Collaborator Author

davidbarsky commented Oct 5, 2018 via email

@hawkw
Copy link
Owner

hawkw commented Oct 25, 2018

@davidbarsky Since Rust 1.30 was just released, this shouldn't break the build any longer, correct?

@davidbarsky
Copy link
Collaborator Author

davidbarsky commented Oct 25, 2018 via email

Copy link
Owner

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that Rust 1.30 is stable, I think we can start thinking about what it takes to merge this branch!

The proc-macro itself is looking good. Most of my requested changes have to do with the project structure etc.

tokio-trace-macros/tokio-trace-macros/src/lib.rs Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
tokio-trace-macros/example/Cargo.toml Outdated Show resolved Hide resolved
tokio-trace-macros/example/src/main.rs Outdated Show resolved Hide resolved
@hawkw
Copy link
Owner

hawkw commented Oct 25, 2018

@davidbarsky

There just might be some breaking changes that have occurred in Tokio Trace since.

Hmm, actually, I don't think so --- since your macro just farms out to the span! macro internally, I think all the changes that could potentially be breaking should be encapsulated behind that macro.

quote_spanned!(call_site=>
#(#attrs) *
#vis #constness #unsafety #asyncness #abi fn #ident(#params) #return_type {
span!(#ident_str, traced_function = #ident_str).enter(move || {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future work: it would be really cool if we could pass all the params to the function as fields here as well.

Since some parameters may not be valid span fields, we might consider adding an additional attribute (#[trace_ignore]?) to annotate those fields that should be skipped.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, yeah. The biggest blocker on passing all the params to into a span field was the T: Clone requirement. Now that's gone, it'll be far easier to implement.


#[proc_macro_attribute]
pub fn trace(_args: TokenStream, item: TokenStream) -> TokenStream {
let input: ItemFn = parse_macro_input!(item as ItemFn);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also for potential future work: it would be cool to allow things that aren't functions to be traced. At the very least, it would be nice to detect if we're annotating a future, and instrument it in the "right way" --- by constructing the span once and wrapping the future in a tokio_trace_futures::Instrumented future.

The naïve approach --- just putting the #[trace] macro on the implementation of Future::poll for that future --- wouldn't do the Right Thing; it would instead create a new span that's entered for every individual time that future is polled. This could potentially be a big enough gotcha that I think it's probably worthwhile to special-case this.

We'd probably want to figure out a similar approach for async fns as well...

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also for potential future work: it would be cool to allow things that aren't functions to be traced. At the very least, it would be nice to detect if we're annotating a future, and instrument it in the "right way" --- by constructing the span once and wrapping the future in a tokio_trace_futures::Instrumented future.

The naïve approach --- just putting the #[trace] macro on the implementation of Future::poll for that future --- wouldn't do the Right Thing; it would instead create a new span that's entered for every individual time that future is polled. This could potentially be a big enough gotcha that I think it's probably worthwhile to special-case this.

That's a good point, and I'd need to dig deeper into the Syn docs.

We'd probably want to figure out a similar approach for async fns as well...

It already is! See the #asyncness on line 41? That's all the work we need to do to support async functions, from a macro standpoint.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'd probably want to figure out a similar approach for async fns as well...

It already is! See the #asyncness on line 41? That's all the work we need to do to support async functions, from a macro standpoint.

Yes, but I think we'd want to make sure we do the right thing for async fns --- namely, I think we'd want to make sure that the future created by that async fn is instrumented by that span, rather than just the initial call to the async fn that returns the future. This may require some testing.

@hawkw
Copy link
Owner

hawkw commented Oct 29, 2018

@davidbarsky looks like all the blocking changes I requested were resolved, thanks!

Mind opening new issues for the follow-up work (#16 (comment) and #16 (comment))?

@davidbarsky
Copy link
Collaborator Author

davidbarsky commented Oct 29, 2018 via email

@davidbarsky
Copy link
Collaborator Author

Created #53 and #54.

@hawkw
Copy link
Owner

hawkw commented Oct 29, 2018

@davidbarsky thanks for creating the followup issues! I believe merging this PR should close #9, since the additional work is now tracked by those tickets.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants