diff --git a/Cargo.toml b/Cargo.toml index a87e052de2..b72bd50618 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ + "tokio-trace-proc-macros", "tokio-trace-futures", "tokio-trace-tower", "tokio-trace-tower-http", diff --git a/tokio-trace-macros/Cargo.toml b/tokio-trace-macros/Cargo.toml index c4bd2906f0..a59d7bb894 100644 --- a/tokio-trace-macros/Cargo.toml +++ b/tokio-trace-macros/Cargo.toml @@ -1,20 +1,12 @@ [package] name = "tokio-trace-macros" version = "0.1.0" -authors = ["Eliza Weisman ", "David Barsky "] - -[lib] -proc-macro = true +authors = ["Eliza Weisman "] [dependencies] tokio-trace = "0.0.1" -syn = { version = "0.15", features = ["full", "extra-traits"] } -quote = "0.6" -proc-macro2 = { version = "0.4", features = ["nightly"] } + [dev-dependencies] -tokio-trace = "0.0.1" tokio-trace-log = { path = "../tokio-trace-log" } env_logger = "0.5" -ansi_term = "0.11" -humantime = "1.1.1" diff --git a/tokio-trace-macros/examples/factorial.rs b/tokio-trace-macros/examples/factorial.rs new file mode 100644 index 0000000000..4e7e1d5177 --- /dev/null +++ b/tokio-trace-macros/examples/factorial.rs @@ -0,0 +1,24 @@ +//! Compare to the example given in the documentation for the `std::dbg` macro. +#[macro_use] +extern crate tokio_trace; +#[macro_use] +extern crate tokio_trace_macros; +extern crate env_logger; +extern crate tokio_trace_log; + +fn factorial(n: u32) -> u32 { + if dbg!(n <= 1) { + dbg!(1) + } else { + dbg!(n * factorial(n - 1)) + } +} + +fn main() { + env_logger::Builder::new().parse("trace").init(); + let subscriber = tokio_trace_log::TraceLogger::new(); + + tokio_trace::subscriber::with_default(subscriber, || { + dbg!(factorial(4)) + }); +} diff --git a/tokio-trace-macros/src/lib.rs b/tokio-trace-macros/src/lib.rs index 905dcd78e3..592d16211d 100644 --- a/tokio-trace-macros/src/lib.rs +++ b/tokio-trace-macros/src/lib.rs @@ -1,46 +1,66 @@ -extern crate proc_macro; #[macro_use] -extern crate syn; -#[macro_use] -extern crate quote; -extern crate proc_macro2; - -use proc_macro::TokenStream; -use proc_macro2::Span; -use syn::token::{Async, Const, Unsafe}; -use syn::{Abi, Attribute, Block, Ident, ItemFn, Visibility}; - -#[proc_macro_attribute] -pub fn trace(_args: TokenStream, item: TokenStream) -> TokenStream { - let input: ItemFn = parse_macro_input!(item as ItemFn); - let call_site = Span::call_site(); +extern crate tokio_trace; - // these are needed ahead of time, as ItemFn contains the function body _and_ - // isn't representable inside a quote!/quote_spanned! macro - // (Syn's ToTokens isn't implemented for ItemFn) - let attrs: Vec = input.clone().attrs; - let vis: Visibility = input.clone().vis; - let constness: Option = input.clone().constness; - let unsafety: Option = input.clone().unsafety; - let asyncness: Option = input.clone().asyncness; - let abi: Option = input.clone().abi; +/// Alias of `dbg!` for avoiding conflicts with the `std::dbg!` macro. +#[macro_export(local_inner_macros)] +macro_rules! trace_dbg { + (level: $level:expr, $ex:expr) => { + dbg!(level: $level, $ex) + }; + (level: $level:expr, $ex:expr) => { + dbg!(target: module_path!(), level: $level, $ex) + }; + (target: $level:expr, $ex:expr) => { + dbg!(target: $target, level: tokio_trace::Level::DEBUG, $ex) + }; + ($ex:expr) => { + dbg!(level: tokio_trace::Level::DEBUG, $ex) + }; - // function body - let block: Box = input.clone().block; - // function name - let ident: Ident = input.clone().ident; - let ident_str = ident.to_string(); - - let return_type = input.clone().decl.output; - let params = input.clone().decl.inputs; +} - quote_spanned!(call_site=> - #(#attrs) * - #vis #constness #unsafety #asyncness #abi fn #ident(#params) #return_type { - span!(#ident_str, traced_function = &#ident_str).enter(move || { - #block - }) +/// Similar to the `std::dbg!` macro, but generates `tokio-trace` events rather +/// than printing to stdout. +/// +/// By default, the verbosity level for the generated events is `DEBUG`, but +/// this can be customized. +#[macro_export] +macro_rules! dbg { + (target: $target:expr, level: $level:expr, $ex:expr) => { + { + #[allow(unused_imports)] + use tokio_trace::{callsite, Id, Subscriber, Event, field::{debug, Value}}; + use tokio_trace::callsite::Callsite; + let callsite = callsite! {@ + name: concat!("event:trace_dbg(", stringify!($ex), ")"), + target: $target, + level: $level, + fields: &[stringify!($ex)] + }; + let interest = callsite.interest(); + let val = $ex; + if interest.is_never() { + val + } else { + let meta = callsite.metadata(); + let mut event = Event::new(interest, meta); + if !event.is_disabled() { + let key = meta.fields().into_iter().next() + .expect("trace_dbg event must have one field"); + event.record(&key, &debug(val)); + } + drop(event); + val + } } - ) - .into() + }; + (level: $level:expr, $ex:expr) => { + dbg!(target: module_path!(), level: $level, $ex) + }; + (target: $level:expr, $ex:expr) => { + dbg!(target: $target, level: tokio_trace::Level::DEBUG, $ex) + }; + ($ex:expr) => { + dbg!(level: tokio_trace::Level::DEBUG, $ex) + }; } diff --git a/tokio-trace-proc-macros/Cargo.toml b/tokio-trace-proc-macros/Cargo.toml new file mode 100644 index 0000000000..f802e92aec --- /dev/null +++ b/tokio-trace-proc-macros/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "tokio-trace-proc-macros" +version = "0.1.0" +authors = ["Eliza Weisman ", "David Barsky "] + +[lib] +proc-macro = true + +[dependencies] +tokio-trace = "0.0.1" +syn = { version = "0.15", features = ["full", "extra-traits"] } +quote = "0.6" +proc-macro2 = { version = "0.4", features = ["nightly"] } + +[dev-dependencies] +tokio-trace = "0.0.1" +tokio-trace-log = { path = "../tokio-trace-log" } +env_logger = "0.5" +ansi_term = "0.11" +humantime = "1.1.1" diff --git a/tokio-trace-macros/examples/basic.rs b/tokio-trace-proc-macros/examples/basic.rs similarity index 95% rename from tokio-trace-macros/examples/basic.rs rename to tokio-trace-proc-macros/examples/basic.rs index a128f67f18..fc72792e17 100644 --- a/tokio-trace-macros/examples/basic.rs +++ b/tokio-trace-proc-macros/examples/basic.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate tokio_trace; #[macro_use] -extern crate tokio_trace_macros; +extern crate tokio_trace_proc_macros; extern crate env_logger; extern crate tokio_trace_log; diff --git a/tokio-trace-proc-macros/src/lib.rs b/tokio-trace-proc-macros/src/lib.rs new file mode 100644 index 0000000000..905dcd78e3 --- /dev/null +++ b/tokio-trace-proc-macros/src/lib.rs @@ -0,0 +1,46 @@ +extern crate proc_macro; +#[macro_use] +extern crate syn; +#[macro_use] +extern crate quote; +extern crate proc_macro2; + +use proc_macro::TokenStream; +use proc_macro2::Span; +use syn::token::{Async, Const, Unsafe}; +use syn::{Abi, Attribute, Block, Ident, ItemFn, Visibility}; + +#[proc_macro_attribute] +pub fn trace(_args: TokenStream, item: TokenStream) -> TokenStream { + let input: ItemFn = parse_macro_input!(item as ItemFn); + let call_site = Span::call_site(); + + // these are needed ahead of time, as ItemFn contains the function body _and_ + // isn't representable inside a quote!/quote_spanned! macro + // (Syn's ToTokens isn't implemented for ItemFn) + let attrs: Vec = input.clone().attrs; + let vis: Visibility = input.clone().vis; + let constness: Option = input.clone().constness; + let unsafety: Option = input.clone().unsafety; + let asyncness: Option = input.clone().asyncness; + let abi: Option = input.clone().abi; + + // function body + let block: Box = input.clone().block; + // function name + let ident: Ident = input.clone().ident; + let ident_str = ident.to_string(); + + let return_type = input.clone().decl.output; + let params = input.clone().decl.inputs; + + quote_spanned!(call_site=> + #(#attrs) * + #vis #constness #unsafety #asyncness #abi fn #ident(#params) #return_type { + span!(#ident_str, traced_function = &#ident_str).enter(move || { + #block + }) + } + ) + .into() +}