]> git.proxmox.com Git - rustc.git/blob - vendor/tracing-attributes/src/lib.rs
New upstream version 1.52.0~beta.3+dfsg1
[rustc.git] / vendor / tracing-attributes / src / lib.rs
1 //! A procedural macro attribute for instrumenting functions with [`tracing`].
2 //!
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.
6 //!
7 //! Note that this macro is also re-exported by the main `tracing` crate.
8 //!
9 //! *Compiler support: [requires `rustc` 1.42+][msrv]*
10 //!
11 //! [msrv]: #supported-rust-versions
12 //!
13 //! ## Usage
14 //!
15 //! First, add this to your `Cargo.toml`:
16 //!
17 //! ```toml
18 //! [dependencies]
19 //! tracing-attributes = "0.1.13"
20 //! ```
21 //!
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:
25 //!
26 //! ```
27 //! use tracing_attributes::instrument;
28 //!
29 //! #[instrument]
30 //! pub fn my_function(my_arg: usize) {
31 //! // ...
32 //! }
33 //!
34 //! # fn main() {}
35 //! ```
36 //!
37 //! [`tracing`]: https://crates.io/crates/tracing
38 //! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
39 //! [instrument]: attr.instrument.html
40 //!
41 //! ## Supported Rust Versions
42 //!
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.
46 //!
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.
54 //!
55 #![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.13")]
56 #![doc(
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/"
59 )]
60 #![cfg_attr(docsrs, deny(broken_intra_doc_links))]
61 #![warn(
62 missing_debug_implementations,
63 missing_docs,
64 rust_2018_idioms,
65 unreachable_pub,
66 bad_style,
67 const_err,
68 dead_code,
69 improper_ctypes,
70 non_shorthand_field_patterns,
71 no_mangle_generic_items,
72 overflowing_literals,
73 path_statements,
74 patterns_in_fns_without_body,
75 private_in_public,
76 unconditional_recursion,
77 unused,
78 unused_allocation,
79 unused_comparisons,
80 unused_parens,
81 while_true
82 )]
83 // TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
84 #![allow(unused)]
85 extern crate proc_macro;
86
87 use std::collections::{HashMap, HashSet};
88 use std::iter;
89
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};
94 use syn::{
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,
98 Stmt, Token,
99 };
100 /// Instruments a function to create and enter a `tracing` [span] every time
101 /// the function is called.
102 ///
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`].
107 ///
108 /// # Overriding Span Attributes
109 ///
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
112 /// example:
113 ///
114 /// ```
115 /// # use tracing_attributes::instrument;
116 ///
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 ...
121 /// }
122 /// ```
123 ///
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
127 /// example:
128 ///
129 /// ```
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 ...
137 /// }
138 /// }
139 /// ```
140 ///
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:
144 ///
145 /// ```
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 ...
152 /// }
153 /// ```
154 ///
155 /// # Skipping Fields
156 ///
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:
162 ///
163 /// - multiple argument names can be passed to `skip`.
164 /// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
165 ///
166 /// ## Examples
167 ///
168 /// ```
169 /// # use tracing_attributes::instrument;
170 /// // This type doesn't implement `fmt::Debug`!
171 /// struct NonDebug;
172 ///
173 /// // `arg` will be recorded, while `non_debug` will not.
174 /// #[instrument(skip(non_debug))]
175 /// fn my_function(arg: usize, non_debug: NonDebug) {
176 /// // ...
177 /// }
178 /// ```
179 ///
180 /// Skipping the `self` parameter:
181 ///
182 /// ```
183 /// # use tracing_attributes::instrument;
184 /// #[derive(Debug)]
185 /// struct MyType {
186 /// data: Vec<u8>, // Suppose this buffer is often quite long...
187 /// }
188 ///
189 /// impl MyType {
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`!)
195 /// }
196 /// }
197 /// ```
198 ///
199 /// # Adding Fields
200 ///
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.
208 ///
209 /// This supports the same [field syntax] as the `span!` and `event!` macros.
210 ///
211 /// Note that overlap between the names of fields and (non-skipped) arguments
212 /// will result in a compile error.
213 ///
214 /// ## Examples
215 ///
216 /// Adding a new field based on the value of an argument:
217 ///
218 /// ```
219 /// # use tracing_attributes::instrument;
220 ///
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) {
225 /// // ...
226 /// }
227 /// ```
228 ///
229 /// Recording specific properties of a struct as their own fields:
230 ///
231 /// ```
232 /// # mod http {
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")
239 /// # }
240 /// # }
241 /// # impl<B> Request<B> {
242 /// # pub fn uri(&self) -> &str { "fake" }
243 /// # pub fn method(&self) -> &str { "GET" }
244 /// # }
245 /// # }
246 /// # use tracing_attributes::instrument;
247 ///
248 /// // This will record the request's URI and HTTP method as their own separate
249 /// // fields.
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 }
254 /// }
255 /// ```
256 ///
257 /// This can be used in conjunction with `skip` to record only some fields of a
258 /// struct:
259 /// ```
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
263 /// // our span.
264 /// #[derive(Debug)]
265 /// struct MyType {
266 /// name: &'static str,
267 /// data: Vec<u8>,
268 /// }
269 ///
270 /// impl MyType {
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`!)
276 /// }
277 /// }
278 /// ```
279 ///
280 /// Adding an empty field to be recorded later:
281 ///
282 /// ```
283 /// # use tracing_attributes::instrument;
284 ///
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;
291 ///
292 /// // Record the result as part of the current span.
293 /// tracing::Span::current().record("result", &result);
294 ///
295 /// // Now, the result will also be included on this event!
296 /// tracing::info!("calculation complete!");
297 ///
298 /// // ... etc ...
299 /// # 0
300 /// }
301 /// ```
302 ///
303 /// # Examples
304 ///
305 /// Instrumenting a function:
306 ///
307 /// ```
308 /// # use tracing_attributes::instrument;
309 /// #[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!");
314 /// // ...
315 /// }
316 /// ```
317 /// Setting the level for the generated span:
318 /// ```
319 /// # use tracing_attributes::instrument;
320 /// #[instrument(level = "debug")]
321 /// pub fn my_function() {
322 /// // ...
323 /// }
324 /// ```
325 /// Overriding the generated span's name:
326 /// ```
327 /// # use tracing_attributes::instrument;
328 /// #[instrument(name = "my_name")]
329 /// pub fn my_function() {
330 /// // ...
331 /// }
332 /// ```
333 /// Overriding the generated span's target:
334 /// ```
335 /// # use tracing_attributes::instrument;
336 /// #[instrument(target = "my_target")]
337 /// pub fn my_function() {
338 /// // ...
339 /// }
340 /// ```
341 ///
342 /// To skip recording an argument, pass the argument's name to the `skip`:
343 ///
344 /// ```
345 /// # use tracing_attributes::instrument;
346 /// struct NonDebug;
347 ///
348 /// #[instrument(skip(non_debug))]
349 /// fn my_function(arg: usize, non_debug: NonDebug) {
350 /// // ...
351 /// }
352 /// ```
353 ///
354 /// To add an additional context to the span, pass key-value pairs to `fields`:
355 ///
356 /// ```
357 /// # use tracing_attributes::instrument;
358 /// #[instrument(fields(foo="bar", id=1, show=true))]
359 /// fn my_function(arg: usize) {
360 /// // ...
361 /// }
362 /// ```
363 ///
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`:
366 ///
367 /// ```
368 /// # use tracing_attributes::instrument;
369 /// #[instrument(err)]
370 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
371 /// Ok(())
372 /// }
373 /// ```
374 ///
375 /// `async fn`s may also be instrumented:
376 ///
377 /// ```
378 /// # use tracing_attributes::instrument;
379 /// #[instrument]
380 /// pub async fn my_function() -> Result<(), ()> {
381 /// // ...
382 /// # Ok(())
383 /// }
384 /// ```
385 ///
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:
390 ///
391 /// ```
392 /// # use tracing::instrument;
393 /// use async_trait::async_trait;
394 ///
395 /// #[async_trait]
396 /// pub trait Foo {
397 /// async fn foo(&self, arg: usize);
398 /// }
399 ///
400 /// #[derive(Debug)]
401 /// struct FooImpl(usize);
402 ///
403 /// #[async_trait]
404 /// impl Foo for FooImpl {
405 /// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
406 /// async fn foo(&self, arg: usize) {}
407 /// }
408 /// ```
409 ///
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`:
414 /// ```compile_fail
415 /// # use tracing::instrument;
416 /// use async_trait::async_trait;
417 ///
418 /// #[async_trait]
419 /// pub trait Bar {
420 /// async fn bar();
421 /// }
422 ///
423 /// #[derive(Debug)]
424 /// struct BarImpl(usize);
425 ///
426 /// #[async_trait]
427 /// impl Bar for BarImpl {
428 /// #[instrument(fields(tmp = std::any::type_name::<Self>()))]
429 /// async fn bar() {}
430 /// }
431 /// ```
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>()))]`.
434 ///
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]
445 pub fn instrument(
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);
451
452 let instrumented_function_name = input.sig.ident.to_string();
453
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(
465 fun,
466 args,
467 instrumented_function_name,
468 Some(internal_fun),
469 ))
470 .unwrap();
471 break;
472 }
473 }
474 }
475
476 let vis = &input.vis;
477 let sig = &input.sig;
478 let attrs = &input.attrs;
479 quote!(
480 #(#attrs) *
481 #vis #sig {
482 #(#stmts) *
483 }
484 )
485 .into()
486 } else {
487 gen_body(&input, args, instrumented_function_name, None).into()
488 }
489 }
490
491 fn gen_body(
492 input: &ItemFn,
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)
500 let ItemFn {
501 attrs,
502 vis,
503 block,
504 sig,
505 ..
506 } = input;
507
508 let Signature {
509 output: return_type,
510 inputs: params,
511 unsafety,
512 asyncness,
513 constness,
514 abi,
515 ident,
516 generics:
517 syn::Generics {
518 params: gen_params,
519 where_clause,
520 ..
521 },
522 ..
523 } = sig;
524
525 let err = args.err;
526 let warnings = args.warnings();
527
528 // generate the span's name
529 let span_name = args
530 // did the user override the span's name?
531 .name
532 .as_ref()
533 .map(|name| quote!(#name))
534 .unwrap_or_else(|| quote!(#instrumented_function_name));
535
536 // generate this inside a closure, so we can return early on errors.
537 let span = (|| {
538 // Pull out the arguments-to-be-skipped first, so we can filter results
539 // below.
540 let param_names: Vec<(Ident, Ident)> = params
541 .clone()
542 .into_iter()
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()))),
546 })
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":
550 // ```
551 // #[async_trait]
552 // impl Foo for FooImpl {
553 // #[instrument(skip(self))]
554 // async fn foo(&self, v: usize) {}
555 // }
556 // ```
557 .map(|x| {
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)
563 } else {
564 (x.clone(), x)
565 }
566 })
567 .collect();
568
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")
573 };
574 }
575 }
576
577 let level = args.level();
578 let target = args.target();
579
580 // filter out skipped fields
581 let mut quoted_fields: Vec<_> = param_names
582 .into_iter()
583 .filter(|(param, _)| {
584 if args.skips.contains(param) {
585 return false;
586 }
587
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 == &param)
594 })
595 } else {
596 true
597 }
598 })
599 .map(|(user_name, real_name)| quote!(#user_name = tracing::field::debug(&#real_name)))
600 .collect();
601
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)
605 {
606 let mut replacer = SelfReplacer {
607 ty: async_trait_fun.self_type.clone(),
608 };
609 for e in fields.iter_mut().filter_map(|f| f.value.as_mut()) {
610 syn::visit_mut::visit_expr_mut(&mut replacer, e);
611 }
612 }
613
614 let custom_fields = &args.fields;
615
616 quote!(tracing::span!(
617 target: #target,
618 #level,
619 #span_name,
620 #(#quoted_fields,)*
621 #custom_fields
622
623 ))
624 })();
625
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() {
632 if err {
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)]
638 Ok(x) => Ok(x),
639 Err(e) => {
640 tracing::error!(error = %e);
641 Err(e)
642 }
643 }
644 }, __tracing_attr_span).await
645 }
646 } else {
647 quote_spanned!(block.span()=>
648 let __tracing_attr_span = #span;
649 tracing::Instrument::instrument(
650 async move { #block },
651 __tracing_attr_span
652 )
653 .await
654 )
655 }
656 } else if err {
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)]
663 Ok(x) => Ok(x),
664 Err(e) => {
665 tracing::error!(error = %e);
666 Err(e)
667 }
668 }
669 )
670 } else {
671 quote_spanned!(block.span()=>
672 let __tracing_attr_span = #span;
673 let __tracing_attr_guard = __tracing_attr_span.enter();
674 #block
675 )
676 };
677
678 quote!(
679 #(#attrs) *
680 #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #return_type
681 #where_clause
682 {
683 #warnings
684 #body
685 }
686 )
687 }
688
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>,
696 err: bool,
697 /// Errors describing any unrecognized parse inputs that we skipped.
698 parse_warnings: Vec<syn::Error>,
699 }
700
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,
706 Err(_) => false,
707 }
708 }
709
710 match &self.level {
711 Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("trace") => {
712 quote!(tracing::Level::TRACE)
713 }
714 Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("debug") => {
715 quote!(tracing::Level::DEBUG)
716 }
717 Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("info") => {
718 quote!(tracing::Level::INFO)
719 }
720 Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("warn") => {
721 quote!(tracing::Level::WARN)
722 }
723 Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("error") => {
724 quote!(tracing::Level::ERROR)
725 }
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! {
733 compile_error!(
734 "unknown verbosity level, expected one of \"trace\", \
735 \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5"
736 )
737 },
738 None => quote!(tracing::Level::INFO),
739 }
740 }
741
742 fn target(&self) -> impl ToTokens {
743 if let Some(ref target) = self.target {
744 quote!(#target)
745 } else {
746 quote!(module_path!())
747 }
748 }
749
750 /// Generate "deprecation" warnings for any unrecognized attribute inputs
751 /// that we skipped.
752 ///
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()=>
765 #[warn(deprecated)]
766 {
767 #[deprecated(since = "not actually deprecated", note = #msg)]
768 const TRACING_INSTRUMENT_WARNING: () = ();
769 let _ = TRACING_INSTRUMENT_WARNING;
770 }
771 }
772 });
773 quote! {
774 { #(#warnings)* }
775 }
776 }
777 }
778
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"));
787 }
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"));
796 }
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"));
801 }
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"));
807 }
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"));
812 }
813 let Skips(skips) = input.parse()?;
814 args.skips = skips;
815 } else if lookahead.peek(kw::fields) {
816 if args.fields.is_some() {
817 return Err(input.error("expected only a single `fields` argument"));
818 }
819 args.fields = Some(input.parse()?);
820 } else if lookahead.peek(kw::err) {
821 let _ = input.parse::<kw::err>()?;
822 args.err = true;
823 } else if lookahead.peek(Token![,]) {
824 let _ = input.parse::<Token![,]>()?;
825 } else {
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>();
834 }
835 }
836 Ok(args)
837 }
838 }
839
840 struct StrArg<T> {
841 value: LitStr,
842 _p: std::marker::PhantomData<T>,
843 }
844
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()?;
850 Ok(Self {
851 value,
852 _p: std::marker::PhantomData,
853 })
854 }
855 }
856
857 struct Skips(HashSet<Ident>);
858
859 impl Parse for Skips {
860 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
861 let _ = input.parse::<kw::skip>();
862 let content;
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();
866 for name in names {
867 if skips.contains(&name) {
868 return Err(syn::Error::new(
869 name.span(),
870 "tried to skip the same field twice",
871 ));
872 } else {
873 skips.insert(name);
874 }
875 }
876 Ok(Self(skips))
877 }
878 }
879
880 #[derive(Debug)]
881 struct Fields(Punctuated<Field, Token![,]>);
882
883 #[derive(Debug)]
884 struct Field {
885 name: Punctuated<Ident, Token![.]>,
886 value: Option<Expr>,
887 kind: FieldKind,
888 }
889
890 #[derive(Debug, Eq, PartialEq)]
891 enum FieldKind {
892 Debug,
893 Display,
894 Value,
895 }
896
897 impl Parse for Fields {
898 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
899 let _ = input.parse::<kw::fields>();
900 let content;
901 let _ = syn::parenthesized!(content in input);
902 let fields: Punctuated<_, Token![,]> = content.parse_terminated(Field::parse)?;
903 Ok(Self(fields))
904 }
905 }
906
907 impl ToTokens for Fields {
908 fn to_tokens(&self, tokens: &mut TokenStream) {
909 self.0.to_tokens(tokens)
910 }
911 }
912
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;
922 };
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;
932 };
933 Some(input.parse()?)
934 } else {
935 None
936 };
937 Ok(Self { name, kind, value })
938 }
939 }
940
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! {
947 #name = #kind#value
948 })
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))
957 } else {
958 self.kind.to_tokens(tokens);
959 self.name.to_tokens(tokens);
960 }
961 }
962 }
963
964 impl ToTokens for FieldKind {
965 fn to_tokens(&self, tokens: &mut TokenStream) {
966 match self {
967 FieldKind::Debug => tokens.extend(quote! { ? }),
968 FieldKind::Display => tokens.extend(quote! { % }),
969 _ => {}
970 }
971 }
972 }
973
974 #[derive(Debug)]
975 enum Level {
976 Str(LitStr),
977 Int(LitInt),
978 Path(Path),
979 }
980
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()?))
992 } else {
993 Err(lookahead.error())
994 }
995 }
996 }
997
998 fn param_names(pat: Pat) -> Box<dyn Iterator<Item = Ident>> {
999 match pat {
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(
1003 fields
1004 .into_iter()
1005 .flat_map(|FieldPat { pat, .. }| param_names(*pat)),
1006 ),
1007 Pat::Tuple(PatTuple { elems, .. }) => Box::new(elems.into_iter().flat_map(param_names)),
1008 Pat::TupleStruct(PatTupleStruct {
1009 pat: PatTuple { elems, .. },
1010 ..
1011 }) => Box::new(elems.into_iter().flat_map(param_names)),
1012
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()),
1018 }
1019 }
1020
1021 mod kw {
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);
1028 }
1029
1030 // Get the AST of the inner function we need to hook, if it was generated
1031 // by async-trait.
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
1045 if block_is_async {
1046 return None;
1047 }
1048
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;
1056
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);
1065 }
1066 } else if let Stmt::Expr(e) = &stmt {
1067 last_expr = Some(e);
1068 }
1069 }
1070
1071 // let's play with (too much) pattern matching
1072 // is the last expression a function call?
1073 if let Some(Expr::Call(ExprCall {
1074 func: outside_func,
1075 args: outside_args,
1076 ..
1077 })) = last_expr
1078 {
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() {
1086 return None;
1087 }
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
1097 return Some(fun);
1098 }
1099 }
1100 }
1101 }
1102 }
1103 }
1104 }
1105 None
1106 }
1107
1108 struct AsyncTraitInfo {
1109 name: String,
1110 self_type: Option<syn::TypePath>,
1111 }
1112
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)?;
1116
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"
1119 let self_type = fun
1120 .sig
1121 .inputs
1122 .iter()
1123 .map(|arg| {
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 {
1130 ty = &*elem;
1131 }
1132 if let syn::Type::Path(tp) = ty {
1133 return Some(tp.clone());
1134 }
1135 }
1136 }
1137 }
1138
1139 None
1140 })
1141 .next();
1142 let self_type = match self_type {
1143 Some(x) => x,
1144 None => None,
1145 };
1146
1147 Some(AsyncTraitInfo {
1148 name: fun.sig.ident.to_string(),
1149 self_type,
1150 })
1151 }
1152
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 {
1162 res.push_str("::");
1163 }
1164 }
1165 res
1166 }
1167
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>,
1172 }
1173
1174 impl syn::visit_mut::VisitMut for SelfReplacer {
1175 fn visit_ident_mut(&mut self, id: &mut Ident) {
1176 if id == "self" {
1177 *id = Ident::new("_self", id.span())
1178 }
1179 }
1180
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();
1186 }
1187 }
1188 }
1189 }
1190 }