1 //! A procedural macro attribute for instrumenting functions with [`tracing`].
3 //! [`tracing`] is a framework for instrumenting Rust programs to collect
4 //! structured, event-based diagnostic information. This crate provides the
5 //! [`#[instrument]`][instrument] procedural macro attribute.
7 //! Note that this macro is also re-exported by the main `tracing` crate.
9 //! *Compiler support: [requires `rustc` 1.42+][msrv]*
11 //! [msrv]: #supported-rust-versions
15 //! First, add this to your `Cargo.toml`:
19 //! tracing-attributes = "0.1.13"
22 //! The [`#[instrument]`][instrument] attribute can now be added to a function
23 //! to automatically create and enter `tracing` [span] when that function is
24 //! called. For example:
27 //! use tracing_attributes::instrument;
30 //! pub fn my_function(my_arg: usize) {
37 //! [`tracing`]: https://crates.io/crates/tracing
38 //! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
39 //! [instrument]: attr.instrument.html
41 //! ## Supported Rust Versions
43 //! Tracing is built against the latest stable release. The minimum supported
44 //! version is 1.42. The current Tracing version is not guaranteed to build on
45 //! Rust versions earlier than the minimum supported version.
47 //! Tracing follows the same compiler support policies as the rest of the Tokio
48 //! project. The current stable Rust compiler and the three most recent minor
49 //! versions before it will always be supported. For example, if the current
50 //! stable compiler version is 1.45, the minimum supported version will not be
51 //! increased past 1.42, three minor versions prior. Increasing the minimum
52 //! supported compiler version is not considered a semver breaking change as
53 //! long as doing so complies with this policy.
55 #![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.13")]
57 html_logo_url
= "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
58 issue_tracker_base_url
= "https://github.com/tokio-rs/tracing/issues/"
60 #![cfg_attr(docsrs, deny(broken_intra_doc_links))]
62 missing_debug_implementations
,
70 non_shorthand_field_patterns
,
71 no_mangle_generic_items
,
74 patterns_in_fns_without_body
,
76 unconditional_recursion
,
83 // TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
85 extern crate proc_macro
;
87 use std
::collections
::{HashMap, HashSet}
;
90 use proc_macro2
::TokenStream
;
91 use quote
::{quote, quote_spanned, ToTokens, TokenStreamExt as _}
;
92 use syn
::ext
::IdentExt
as _
;
93 use syn
::parse
::{Parse, ParseStream}
;
95 punctuated
::Punctuated
, spanned
::Spanned
, AttributeArgs
, Block
, Expr
, ExprCall
, FieldPat
,
96 FnArg
, Ident
, Item
, ItemFn
, Lit
, LitInt
, LitStr
, Meta
, MetaList
, MetaNameValue
, NestedMeta
,
97 Pat
, PatIdent
, PatReference
, PatStruct
, PatTuple
, PatTupleStruct
, PatType
, Path
, Signature
,
100 /// Instruments a function to create and enter a `tracing` [span] every time
101 /// the function is called.
103 /// By default, the generated span's [name] will be the name of the function,
104 /// the span's [target] will be the current module path, and the span's [level]
105 /// will be [`INFO`], although these properties can be overridden. Any arguments
106 /// to that function will be recorded as fields using [`fmt::Debug`].
108 /// # Overriding Span Attributes
110 /// To change the [name] of the generated span, add a `name` argument to the
111 /// `#[instrument]` macro, followed by an equals sign and a string literal. For
115 /// # use tracing_attributes::instrument;
117 /// // The generated span's name will be "my_span" rather than "my_function".
118 /// #[instrument(name = "my_span")]
119 /// pub fn my_function() {
120 /// // ... do something incredibly interesting and important ...
124 /// To override the [target] of the generated span, add a `target` argument to
125 /// the `#[instrument]` macro, followed by an equals sign and a string literal
126 /// for the new target. The [module path] is still recorded separately. For
130 /// pub mod my_module {
131 /// # use tracing_attributes::instrument;
132 /// // The generated span's target will be "my_crate::some_special_target",
133 /// // rather than "my_crate::my_module".
134 /// #[instrument(target = "my_crate::some_special_target")]
135 /// pub fn my_function() {
136 /// // ... all kinds of neat code in here ...
141 /// Finally, to override the [level] of the generated span, add a `level`
142 /// argument, followed by an equals sign and a string literal with the name of
143 /// the desired level. Level names are not case sensitive. For example:
146 /// # use tracing_attributes::instrument;
147 /// // The span's level will be TRACE rather than INFO.
148 /// #[instrument(level = "trace")]
149 /// pub fn my_function() {
150 /// // ... I have written a truly marvelous implementation of this function,
151 /// // which this example is too narrow to contain ...
155 /// # Skipping Fields
157 /// To skip recording one or more arguments to a function or method, pass
158 /// the argument's name inside the `skip()` argument on the `#[instrument]`
159 /// macro. This can be used when an argument to an instrumented function does
160 /// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
161 /// costly `Debug` implementation. Note that:
163 /// - multiple argument names can be passed to `skip`.
164 /// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
169 /// # use tracing_attributes::instrument;
170 /// // This type doesn't implement `fmt::Debug`!
173 /// // `arg` will be recorded, while `non_debug` will not.
174 /// #[instrument(skip(non_debug))]
175 /// fn my_function(arg: usize, non_debug: NonDebug) {
180 /// Skipping the `self` parameter:
183 /// # use tracing_attributes::instrument;
186 /// data: Vec<u8>, // Suppose this buffer is often quite long...
190 /// // Suppose we don't want to print an entire kilobyte of `data`
191 /// // every time this is called...
192 /// #[instrument(skip(self))]
193 /// pub fn my_method(&mut self, an_interesting_argument: usize) {
194 /// // ... do something (hopefully, using all that `data`!)
201 /// Additional fields (key-value pairs with arbitrary data) may be added to the
202 /// generated span using the `fields` argument on the `#[instrument]` macro. Any
203 /// Rust expression can be used as a field value in this manner. These
204 /// expressions will be evaluated at the beginning of the function's body, so
205 /// arguments to the function may be used in these expressions. Field names may
206 /// also be specified *without* values. Doing so will result in an [empty field]
207 /// whose value may be recorded later within the function body.
209 /// This supports the same [field syntax] as the `span!` and `event!` macros.
211 /// Note that overlap between the names of fields and (non-skipped) arguments
212 /// will result in a compile error.
216 /// Adding a new field based on the value of an argument:
219 /// # use tracing_attributes::instrument;
221 /// // This will record a field named "i" with the value of `i` *and* a field
222 /// // named "next" with the value of `i` + 1.
223 /// #[instrument(fields(next = i + 1))]
224 /// pub fn my_function(i: usize) {
229 /// Recording specific properties of a struct as their own fields:
233 /// # pub struct Error;
234 /// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
235 /// # pub struct Request<B> { _b: B }
236 /// # impl<B> std::fmt::Debug for Request<B> {
237 /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238 /// # f.pad("request")
241 /// # impl<B> Request<B> {
242 /// # pub fn uri(&self) -> &str { "fake" }
243 /// # pub fn method(&self) -> &str { "GET" }
246 /// # use tracing_attributes::instrument;
248 /// // This will record the request's URI and HTTP method as their own separate
250 /// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
251 /// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
252 /// // ... handle the request ...
253 /// # http::Response { _b: std::marker::PhantomData }
257 /// This can be used in conjunction with `skip` to record only some fields of a
260 /// # use tracing_attributes::instrument;
261 /// // Remember the struct with the very large `data` field from the earlier
262 /// // example? Now it also has a `name`, which we might want to include in
266 /// name: &'static str,
271 /// // This will skip the `data` field, but will include `self.name`,
272 /// // formatted using `fmt::Display`.
273 /// #[instrument(skip(self), fields(self.name = %self.name))]
274 /// pub fn my_method(&mut self, an_interesting_argument: usize) {
275 /// // ... do something (hopefully, using all that `data`!)
280 /// Adding an empty field to be recorded later:
283 /// # use tracing_attributes::instrument;
285 /// // This function does a very interesting and important mathematical calculation.
286 /// // Suppose we want to record both the inputs to the calculation *and* its result...
287 /// #[instrument(fields(result))]
288 /// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
289 /// // Rerform the calculation.
290 /// let result = input_1 + input_2;
292 /// // Record the result as part of the current span.
293 /// tracing::Span::current().record("result", &result);
295 /// // Now, the result will also be included on this event!
296 /// tracing::info!("calculation complete!");
305 /// Instrumenting a function:
308 /// # use tracing_attributes::instrument;
310 /// pub fn my_function(my_arg: usize) {
311 /// // This event will be recorded inside a span named `my_function` with the
312 /// // field `my_arg`.
313 /// tracing::info!("inside my_function!");
317 /// Setting the level for the generated span:
319 /// # use tracing_attributes::instrument;
320 /// #[instrument(level = "debug")]
321 /// pub fn my_function() {
325 /// Overriding the generated span's name:
327 /// # use tracing_attributes::instrument;
328 /// #[instrument(name = "my_name")]
329 /// pub fn my_function() {
333 /// Overriding the generated span's target:
335 /// # use tracing_attributes::instrument;
336 /// #[instrument(target = "my_target")]
337 /// pub fn my_function() {
342 /// To skip recording an argument, pass the argument's name to the `skip`:
345 /// # use tracing_attributes::instrument;
348 /// #[instrument(skip(non_debug))]
349 /// fn my_function(arg: usize, non_debug: NonDebug) {
354 /// To add an additional context to the span, pass key-value pairs to `fields`:
357 /// # use tracing_attributes::instrument;
358 /// #[instrument(fields(foo="bar", id=1, show=true))]
359 /// fn my_function(arg: usize) {
364 /// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, you can add
365 /// `err` to emit error events when the function returns `Err`:
368 /// # use tracing_attributes::instrument;
369 /// #[instrument(err)]
370 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
375 /// `async fn`s may also be instrumented:
378 /// # use tracing_attributes::instrument;
380 /// pub async fn my_function() -> Result<(), ()> {
386 /// It also works with [async-trait](https://crates.io/crates/async-trait)
387 /// (a crate that allows defining async functions in traits,
388 /// something not currently possible in Rust),
389 /// and hopefully most libraries that exhibit similar behaviors:
392 /// # use tracing::instrument;
393 /// use async_trait::async_trait;
397 /// async fn foo(&self, arg: usize);
401 /// struct FooImpl(usize);
404 /// impl Foo for FooImpl {
405 /// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
406 /// async fn foo(&self, arg: usize) {}
410 /// An interesting note on this subject is that references to the `Self`
411 /// type inside the `fields` argument are only allowed when the instrumented
412 /// function is a method aka. the function receives `self` as an argument.
413 /// For example, this *will not work* because it doesn't receive `self`:
415 /// # use tracing::instrument;
416 /// use async_trait::async_trait;
424 /// struct BarImpl(usize);
427 /// impl Bar for BarImpl {
428 /// #[instrument(fields(tmp = std::any::type_name::<Self>()))]
429 /// async fn bar() {}
432 /// Instead, you should manually rewrite any `Self` types as the type for
433 /// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`.
435 /// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
436 /// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
437 /// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
438 /// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
439 /// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
440 /// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
441 /// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
442 /// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
443 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
444 #[proc_macro_attribute]
446 args
: proc_macro
::TokenStream
,
447 item
: proc_macro
::TokenStream
,
448 ) -> proc_macro
::TokenStream
{
449 let input
: ItemFn
= syn
::parse_macro_input
!(item
as ItemFn
);
450 let args
= syn
::parse_macro_input
!(args
as InstrumentArgs
);
452 let instrumented_function_name
= input
.sig
.ident
.to_string();
454 // check for async_trait-like patterns in the block and wrap the
455 // internal function with Instrument instead of wrapping the
456 // async_trait generated wrapper
457 if let Some(internal_fun
) = get_async_trait_info(&input
.block
, input
.sig
.asyncness
.is_some()) {
458 // let's rewrite some statements!
459 let mut stmts
: Vec
<Stmt
> = input
.block
.stmts
.to_vec();
460 for stmt
in &mut stmts
{
461 if let Stmt
::Item(Item
::Fn(fun
)) = stmt
{
462 // instrument the function if we considered it as the one we truly want to trace
463 if fun
.sig
.ident
== internal_fun
.name
{
464 *stmt
= syn
::parse2(gen_body(
467 instrumented_function_name
,
476 let vis
= &input
.vis
;
477 let sig
= &input
.sig
;
478 let attrs
= &input
.attrs
;
487 gen_body(&input
, args
, instrumented_function_name
, None
).into()
493 mut args
: InstrumentArgs
,
494 instrumented_function_name
: String
,
495 async_trait_fun
: Option
<AsyncTraitInfo
>,
496 ) -> proc_macro2
::TokenStream
{
497 // these are needed ahead of time, as ItemFn contains the function body _and_
498 // isn't representable inside a quote!/quote_spanned! macro
499 // (Syn's ToTokens isn't implemented for ItemFn)
526 let warnings
= args
.warnings();
528 // generate the span's name
530 // did the user override the span's name?
533 .map(|name
| quote
!(#name))
534 .unwrap_or_else(|| quote
!(#instrumented_function_name));
536 // generate this inside a closure, so we can return early on errors.
538 // Pull out the arguments-to-be-skipped first, so we can filter results
540 let param_names
: Vec
<(Ident
, Ident
)> = params
543 .flat_map(|param
| match param
{
544 FnArg
::Typed(PatType { pat, .. }
) => param_names(*pat
),
545 FnArg
::Receiver(_
) => Box
::new(iter
::once(Ident
::new("self", param
.span()))),
547 // Little dance with new (user-exposed) names and old (internal)
548 // names of identifiers. That way, you can do the following
549 // even though async_trait rewrite "self" as "_self":
552 // impl Foo for FooImpl {
553 // #[instrument(skip(self))]
554 // async fn foo(&self, v: usize) {}
558 // if we are inside a function generated by async-trait, we
559 // should take care to rewrite "_self" as "self" for
560 // 'user convenience'
561 if async_trait_fun
.is_some() && x
== "_self" {
562 (Ident
::new("self", x
.span()), x
)
569 for skip
in &args
.skips
{
570 if !param_names
.iter().map(|(user
, _
)| user
).any(|y
| y
== skip
) {
571 return quote_spanned
! {skip
.span()=>
572 compile_error
!("attempting to skip non-existent parameter")
577 let level
= args
.level();
578 let target
= args
.target();
580 // filter out skipped fields
581 let mut quoted_fields
: Vec
<_
> = param_names
583 .filter(|(param
, _
)| {
584 if args
.skips
.contains(param
) {
588 // If any parameters have the same name as a custom field, skip
589 // and allow them to be formatted by the custom field.
590 if let Some(ref fields
) = args
.fields
{
591 fields
.0.iter
().all(|Field { ref name, .. }
| {
592 let first
= name
.first();
593 first
!= name
.last() || !first
.iter().any(|name
| name
== ¶m
)
599 .map(|(user_name
, real_name
)| quote
!(#user_name = tracing::field::debug(&#real_name)))
602 // when async-trait is in use, replace instances of "self" with "_self" inside the fields values
603 if let (Some(ref async_trait_fun
), Some(Fields(ref mut fields
))) =
604 (async_trait_fun
, &mut args
.fields
)
606 let mut replacer
= SelfReplacer
{
607 ty
: async_trait_fun
.self_type
.clone(),
609 for e
in fields
.iter_mut().filter_map(|f
| f
.value
.as_mut()) {
610 syn
::visit_mut
::visit_expr_mut(&mut replacer
, e
);
614 let custom_fields
= &args
.fields
;
616 quote
!(tracing
::span
!(
626 // Generate the instrumented function body.
627 // If the function is an `async fn`, this will wrap it in an async block,
628 // which is `instrument`ed using `tracing-futures`. Otherwise, this will
629 // enter the span and then perform the rest of the body.
630 // If `err` is in args, instrument any resulting `Err`s.
631 let body
= if asyncness
.is_some() {
633 quote_spanned
! {block
.span()=>
634 let __tracing_attr_span
= #span;
635 tracing
::Instrument
::instrument(async
move {
636 match async
move { #block }
.await
{
637 #[allow(clippy::unit_arg)]
640 tracing
::error
!(error
= %e
);
644 }, __tracing_attr_span
).await
647 quote_spanned
!(block
.span()=>
648 let __tracing_attr_span
= #span;
649 tracing
::Instrument
::instrument(
650 async
move { #block }
,
657 quote_spanned
!(block
.span()=>
658 let __tracing_attr_span
= #span;
659 let __tracing_attr_guard
= __tracing_attr_span
.enter();
660 #[allow(clippy::redundant_closure_call)]
661 match (move || #block)() {
662 #[allow(clippy::unit_arg)]
665 tracing
::error
!(error
= %e
);
671 quote_spanned
!(block
.span()=>
672 let __tracing_attr_span
= #span;
673 let __tracing_attr_guard
= __tracing_attr_span
.enter();
680 #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #return_type
689 #[derive(Default, Debug)]
690 struct InstrumentArgs
{
691 level
: Option
<Level
>,
692 name
: Option
<LitStr
>,
693 target
: Option
<LitStr
>,
694 skips
: HashSet
<Ident
>,
695 fields
: Option
<Fields
>,
697 /// Errors describing any unrecognized parse inputs that we skipped.
698 parse_warnings
: Vec
<syn
::Error
>,
701 impl InstrumentArgs
{
702 fn level(&self) -> impl ToTokens
{
703 fn is_level(lit
: &LitInt
, expected
: u64) -> bool
{
704 match lit
.base10_parse
::<u64>() {
705 Ok(value
) => value
== expected
,
711 Some(Level
::Str(ref lit
)) if lit
.value().eq_ignore_ascii_case("trace") => {
712 quote
!(tracing
::Level
::TRACE
)
714 Some(Level
::Str(ref lit
)) if lit
.value().eq_ignore_ascii_case("debug") => {
715 quote
!(tracing
::Level
::DEBUG
)
717 Some(Level
::Str(ref lit
)) if lit
.value().eq_ignore_ascii_case("info") => {
718 quote
!(tracing
::Level
::INFO
)
720 Some(Level
::Str(ref lit
)) if lit
.value().eq_ignore_ascii_case("warn") => {
721 quote
!(tracing
::Level
::WARN
)
723 Some(Level
::Str(ref lit
)) if lit
.value().eq_ignore_ascii_case("error") => {
724 quote
!(tracing
::Level
::ERROR
)
726 Some(Level
::Int(ref lit
)) if is_level(lit
, 1) => quote
!(tracing
::Level
::TRACE
),
727 Some(Level
::Int(ref lit
)) if is_level(lit
, 2) => quote
!(tracing
::Level
::DEBUG
),
728 Some(Level
::Int(ref lit
)) if is_level(lit
, 3) => quote
!(tracing
::Level
::INFO
),
729 Some(Level
::Int(ref lit
)) if is_level(lit
, 4) => quote
!(tracing
::Level
::WARN
),
730 Some(Level
::Int(ref lit
)) if is_level(lit
, 5) => quote
!(tracing
::Level
::ERROR
),
731 Some(Level
::Path(ref pat
)) => quote
!(#pat),
732 Some(lit
) => quote
! {
734 "unknown verbosity level, expected one of \"trace\", \
735 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5"
738 None
=> quote
!(tracing
::Level
::INFO
),
742 fn target(&self) -> impl ToTokens
{
743 if let Some(ref target
) = self.target
{
746 quote
!(module_path
!())
750 /// Generate "deprecation" warnings for any unrecognized attribute inputs
753 /// For backwards compatibility, we need to emit compiler warnings rather
754 /// than errors for unrecognized inputs. Generating a fake deprecation is
755 /// the only way to do this on stable Rust right now.
756 fn warnings(&self) -> impl ToTokens
{
757 let warnings
= self.parse_warnings
.iter().map(|err
| {
758 let msg
= format
!("found unrecognized input, {}", err
);
759 let msg
= LitStr
::new(&msg
, err
.span());
760 // TODO(eliza): This is a bit of a hack, but it's just about the
761 // only way to emit warnings from a proc macro on stable Rust.
762 // Eventually, when the `proc_macro::Diagnostic` API stabilizes, we
763 // should definitely use that instead.
764 quote_spanned
! {err
.span()=>
767 #[deprecated(since = "not actually deprecated", note = #msg)]
768 const TRACING_INSTRUMENT_WARNING
: () = ();
769 let _
= TRACING_INSTRUMENT_WARNING
;
779 impl Parse
for InstrumentArgs
{
780 fn parse(input
: ParseStream
<'_
>) -> syn
::Result
<Self> {
781 let mut args
= Self::default();
782 while !input
.is_empty() {
783 let lookahead
= input
.lookahead1();
784 if lookahead
.peek(kw
::name
) {
785 if args
.name
.is_some() {
786 return Err(input
.error("expected only a single `name` argument"));
788 let name
= input
.parse
::<StrArg
<kw
::name
>>()?
.value
;
789 args
.name
= Some(name
);
790 } else if lookahead
.peek(LitStr
) {
791 // XXX: apparently we support names as either named args with an
792 // sign, _or_ as unnamed string literals. That's weird, but
793 // changing it is apparently breaking.
794 if args
.name
.is_some() {
795 return Err(input
.error("expected only a single `name` argument"));
797 args
.name
= Some(input
.parse()?
);
798 } else if lookahead
.peek(kw
::target
) {
799 if args
.target
.is_some() {
800 return Err(input
.error("expected only a single `target` argument"));
802 let target
= input
.parse
::<StrArg
<kw
::target
>>()?
.value
;
803 args
.target
= Some(target
);
804 } else if lookahead
.peek(kw
::level
) {
805 if args
.level
.is_some() {
806 return Err(input
.error("expected only a single `level` argument"));
808 args
.level
= Some(input
.parse()?
);
809 } else if lookahead
.peek(kw
::skip
) {
810 if !args
.skips
.is_empty() {
811 return Err(input
.error("expected only a single `skip` argument"));
813 let Skips(skips
) = input
.parse()?
;
815 } else if lookahead
.peek(kw
::fields
) {
816 if args
.fields
.is_some() {
817 return Err(input
.error("expected only a single `fields` argument"));
819 args
.fields
= Some(input
.parse()?
);
820 } else if lookahead
.peek(kw
::err
) {
821 let _
= input
.parse
::<kw
::err
>()?
;
823 } else if lookahead
.peek(Token
![,]) {
824 let _
= input
.parse
::<Token
![,]>()?
;
826 // We found a token that we didn't expect!
827 // We want to emit warnings for these, rather than errors, so
828 // we'll add it to the list of unrecognized inputs we've seen so
829 // far and keep going.
830 args
.parse_warnings
.push(lookahead
.error());
831 // Parse the unrecognized token tree to advance the parse
832 // stream, and throw it away so we can keep parsing.
833 let _
= input
.parse
::<proc_macro2
::TokenTree
>();
842 _p
: std
::marker
::PhantomData
<T
>,
845 impl<T
: Parse
> Parse
for StrArg
<T
> {
846 fn parse(input
: ParseStream
<'_
>) -> syn
::Result
<Self> {
847 let _
= input
.parse
::<T
>()?
;
848 let _
= input
.parse
::<Token
![=]>()?
;
849 let value
= input
.parse()?
;
852 _p
: std
::marker
::PhantomData
,
857 struct Skips(HashSet
<Ident
>);
859 impl Parse
for Skips
{
860 fn parse(input
: ParseStream
<'_
>) -> syn
::Result
<Self> {
861 let _
= input
.parse
::<kw
::skip
>();
863 let _
= syn
::parenthesized
!(content
in input
);
864 let names
: Punctuated
<Ident
, Token
![,]> = content
.parse_terminated(Ident
::parse_any
)?
;
865 let mut skips
= HashSet
::new();
867 if skips
.contains(&name
) {
868 return Err(syn
::Error
::new(
870 "tried to skip the same field twice",
881 struct Fields(Punctuated
<Field
, Token
![,]>);
885 name
: Punctuated
<Ident
, Token
![.]>,
890 #[derive(Debug, Eq, PartialEq)]
897 impl Parse
for Fields
{
898 fn parse(input
: ParseStream
<'_
>) -> syn
::Result
<Self> {
899 let _
= input
.parse
::<kw
::fields
>();
901 let _
= syn
::parenthesized
!(content
in input
);
902 let fields
: Punctuated
<_
, Token
![,]> = content
.parse_terminated(Field
::parse
)?
;
907 impl ToTokens
for Fields
{
908 fn to_tokens(&self, tokens
: &mut TokenStream
) {
909 self.0.to_tokens(tokens
)
913 impl Parse
for Field
{
914 fn parse(input
: ParseStream
<'_
>) -> syn
::Result
<Self> {
915 let mut kind
= FieldKind
::Value
;
916 if input
.peek(Token
![%]) {
917 input
.parse
::<Token
![%]>()?
;
918 kind
= FieldKind
::Display
;
919 } else if input
.peek(Token
![?
]) {
920 input
.parse
::<Token
![?
]>()?
;
921 kind
= FieldKind
::Debug
;
923 let name
= Punctuated
::parse_separated_nonempty_with(input
, Ident
::parse_any
)?
;
924 let value
= if input
.peek(Token
![=]) {
925 input
.parse
::<Token
![=]>()?
;
926 if input
.peek(Token
![%]) {
927 input
.parse
::<Token
![%]>()?
;
928 kind
= FieldKind
::Display
;
929 } else if input
.peek(Token
![?
]) {
930 input
.parse
::<Token
![?
]>()?
;
931 kind
= FieldKind
::Debug
;
937 Ok(Self { name, kind, value }
)
941 impl ToTokens
for Field
{
942 fn to_tokens(&self, tokens
: &mut TokenStream
) {
943 if let Some(ref value
) = self.value
{
944 let name
= &self.name
;
945 let kind
= &self.kind
;
946 tokens
.extend(quote
! {
949 } else if self.kind
== FieldKind
::Value
{
950 // XXX(eliza): I don't like that fields without values produce
951 // empty fields rather than local variable shorthand...but,
952 // we've released a version where field names without values in
953 // `instrument` produce empty field values, so changing it now
954 // is a breaking change. agh.
955 let name
= &self.name
;
956 tokens
.extend(quote
!(#name = tracing::field::Empty))
958 self.kind
.to_tokens(tokens
);
959 self.name
.to_tokens(tokens
);
964 impl ToTokens
for FieldKind
{
965 fn to_tokens(&self, tokens
: &mut TokenStream
) {
967 FieldKind
::Debug
=> tokens
.extend(quote
! { ? }
),
968 FieldKind
::Display
=> tokens
.extend(quote
! { % }
),
981 impl Parse
for Level
{
982 fn parse(input
: ParseStream
<'_
>) -> syn
::Result
<Self> {
983 let _
= input
.parse
::<kw
::level
>()?
;
984 let _
= input
.parse
::<Token
![=]>()?
;
985 let lookahead
= input
.lookahead1();
986 if lookahead
.peek(LitStr
) {
987 Ok(Self::Str(input
.parse()?
))
988 } else if lookahead
.peek(LitInt
) {
989 Ok(Self::Int(input
.parse()?
))
990 } else if lookahead
.peek(Ident
) {
991 Ok(Self::Path(input
.parse()?
))
993 Err(lookahead
.error())
998 fn param_names(pat
: Pat
) -> Box
<dyn Iterator
<Item
= Ident
>> {
1000 Pat
::Ident(PatIdent { ident, .. }
) => Box
::new(iter
::once(ident
)),
1001 Pat
::Reference(PatReference { pat, .. }
) => param_names(*pat
),
1002 Pat
::Struct(PatStruct { fields, .. }
) => Box
::new(
1005 .flat_map(|FieldPat { pat, .. }
| param_names(*pat
)),
1007 Pat
::Tuple(PatTuple { elems, .. }
) => Box
::new(elems
.into_iter().flat_map(param_names
)),
1008 Pat
::TupleStruct(PatTupleStruct
{
1009 pat
: PatTuple { elems, .. }
,
1011 }) => Box
::new(elems
.into_iter().flat_map(param_names
)),
1013 // The above *should* cover all cases of irrefutable patterns,
1014 // but we purposefully don't do any funny business here
1015 // (such as panicking) because that would obscure rustc's
1016 // much more informative error message.
1017 _
=> Box
::new(iter
::empty()),
1022 syn
::custom_keyword
!(fields
);
1023 syn
::custom_keyword
!(skip
);
1024 syn
::custom_keyword
!(level
);
1025 syn
::custom_keyword
!(target
);
1026 syn
::custom_keyword
!(name
);
1027 syn
::custom_keyword
!(err
);
1030 // Get the AST of the inner function we need to hook, if it was generated
1032 // When we are given a function annotated by async-trait, that function
1033 // is only a placeholder that returns a pinned future containing the
1034 // user logic, and it is that pinned future that needs to be instrumented.
1035 // Were we to instrument its parent, we would only collect information
1036 // regarding the allocation of that future, and not its own span of execution.
1037 // So we inspect the block of the function to find if it matches the pattern
1038 // `async fn foo<...>(...) {...}; Box::pin(foo<...>(...))` and we return
1039 // the name `foo` if that is the case. 'gen_body' will then be able
1040 // to use that information to instrument the proper function.
1041 // (this follows the approach suggested in
1042 // https://github.com/dtolnay/async-trait/issues/45#issuecomment-571245673)
1043 fn get_async_trait_function(block
: &Block
, block_is_async
: bool
) -> Option
<&ItemFn
> {
1044 // are we in an async context? If yes, this isn't a async_trait-like pattern
1049 // list of async functions declared inside the block
1050 let mut inside_funs
= Vec
::new();
1051 // last expression declared in the block (it determines the return
1052 // value of the block, so that if we are working on a function
1053 // whose `trait` or `impl` declaration is annotated by async_trait,
1054 // this is quite likely the point where the future is pinned)
1055 let mut last_expr
= None
;
1057 // obtain the list of direct internal functions and the last
1058 // expression of the block
1059 for stmt
in &block
.stmts
{
1060 if let Stmt
::Item(Item
::Fn(fun
)) = &stmt
{
1061 // is the function declared as async? If so, this is a good
1062 // candidate, let's keep it in hand
1063 if fun
.sig
.asyncness
.is_some() {
1064 inside_funs
.push(fun
);
1066 } else if let Stmt
::Expr(e
) = &stmt
{
1067 last_expr
= Some(e
);
1071 // let's play with (too much) pattern matching
1072 // is the last expression a function call?
1073 if let Some(Expr
::Call(ExprCall
{
1079 if let Expr
::Path(path
) = outside_func
.as_ref() {
1080 // is it a call to `Box::pin()`?
1081 if "Box::pin" == path_to_string(&path
.path
) {
1082 // does it takes at least an argument? (if it doesn't,
1083 // it's not gonna compile anyway, but that's no reason
1084 // to (try to) perform an out of bounds access)
1085 if outside_args
.is_empty() {
1088 // is the argument to Box::pin a function call itself?
1089 if let Expr
::Call(ExprCall { func, args, .. }
) = &outside_args
[0] {
1090 if let Expr
::Path(inside_path
) = func
.as_ref() {
1091 // "stringify" the path of the function called
1092 let func_name
= path_to_string(&inside_path
.path
);
1093 // is this function directly defined insided the current block?
1094 for fun
in inside_funs
{
1095 if fun
.sig
.ident
== func_name
{
1096 // we must hook this function now
1108 struct AsyncTraitInfo
{
1110 self_type
: Option
<syn
::TypePath
>,
1113 // Return the informations necessary to process a function annotated with async-trait.
1114 fn get_async_trait_info(block
: &Block
, block_is_async
: bool
) -> Option
<AsyncTraitInfo
> {
1115 let fun
= get_async_trait_function(block
, block_is_async
)?
;
1117 // if "_self" is present as an argument, we store its type to be able to rewrite "Self" (the
1118 // parameter type) with the type of "_self"
1124 if let FnArg
::Typed(ty
) = arg
{
1125 if let Pat
::Ident(PatIdent { ident, .. }
) = &*ty
.pat
{
1126 if ident
== "_self" {
1127 let mut ty
= &*ty
.ty
;
1128 // extract the inner type if the argument is "&self" or "&mut self"
1129 if let syn
::Type
::Reference(syn
::TypeReference { elem, .. }
) = ty
{
1132 if let syn
::Type
::Path(tp
) = ty
{
1133 return Some(tp
.clone());
1142 let self_type
= match self_type
{
1147 Some(AsyncTraitInfo
{
1148 name
: fun
.sig
.ident
.to_string(),
1153 // Return a path as a String
1154 fn path_to_string(path
: &Path
) -> String
{
1155 use std
::fmt
::Write
;
1156 // some heuristic to prevent too many allocations
1157 let mut res
= String
::with_capacity(path
.segments
.len() * 5);
1158 for i
in 0..path
.segments
.len() {
1159 write
!(&mut res
, "{}", path
.segments
[i
].ident
)
1160 .expect("writing to a String should never fail");
1161 if i
< path
.segments
.len() - 1 {
1168 // A visitor struct replacing the "self" and "Self" tokens in user-supplied fields expressions when
1169 // the function is generated by async-trait.
1170 struct SelfReplacer
{
1171 ty
: Option
<syn
::TypePath
>,
1174 impl syn
::visit_mut
::VisitMut
for SelfReplacer
{
1175 fn visit_ident_mut(&mut self, id
: &mut Ident
) {
1177 *id
= Ident
::new("_self", id
.span())
1181 fn visit_type_mut(&mut self, ty
: &mut syn
::Type
) {
1182 if let syn
::Type
::Path(syn
::TypePath { ref mut path, .. }
) = ty
{
1183 if path_to_string(path
) == "Self" {
1184 if let Some(ref true_type
) = self.ty
{
1185 *path
= true_type
.path
.clone();