]> git.proxmox.com Git - rustc.git/blob - vendor/tracing-attributes/src/lib.rs
New upstream version 1.61.0+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.49+][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.20"
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.49. 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.20")]
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(rustdoc::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_allocation,
78 unused_comparisons,
79 unused_parens,
80 while_true
81 )]
82 // TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
83 #![allow(unused)]
84 extern crate proc_macro;
85
86 use proc_macro2::TokenStream;
87 use quote::ToTokens;
88 use syn::parse::{Parse, ParseStream};
89 use syn::{Attribute, Block, ItemFn, Signature, Visibility};
90
91 mod attr;
92 mod expand;
93 /// Instruments a function to create and enter a `tracing` [span] every time
94 /// the function is called.
95 ///
96 /// Unless overriden, a span with `info` level will be generated.
97 /// The generated span's name will be the name of the function.
98 /// By default, all arguments to the function are included as fields on the
99 /// span. Arguments that are `tracing` [primitive types] implementing the
100 /// [`Value` trait] will be recorded as fields of that type. Types which do
101 /// not implement `Value` will be recorded using [`std::fmt::Debug`].
102 ///
103 /// [primitive types]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html#foreign-impls
104 /// [`Value` trait]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html.
105 ///
106 /// # Overriding Span Attributes
107 ///
108 /// To change the [name] of the generated span, add a `name` argument to the
109 /// `#[instrument]` macro, followed by an equals sign and a string literal. For
110 /// example:
111 ///
112 /// ```
113 /// # use tracing_attributes::instrument;
114 ///
115 /// // The generated span's name will be "my_span" rather than "my_function".
116 /// #[instrument(name = "my_span")]
117 /// pub fn my_function() {
118 /// // ... do something incredibly interesting and important ...
119 /// }
120 /// ```
121 ///
122 /// To override the [target] of the generated span, add a `target` argument to
123 /// the `#[instrument]` macro, followed by an equals sign and a string literal
124 /// for the new target. The [module path] is still recorded separately. For
125 /// example:
126 ///
127 /// ```
128 /// pub mod my_module {
129 /// # use tracing_attributes::instrument;
130 /// // The generated span's target will be "my_crate::some_special_target",
131 /// // rather than "my_crate::my_module".
132 /// #[instrument(target = "my_crate::some_special_target")]
133 /// pub fn my_function() {
134 /// // ... all kinds of neat code in here ...
135 /// }
136 /// }
137 /// ```
138 ///
139 /// Finally, to override the [level] of the generated span, add a `level`
140 /// argument, followed by an equals sign and a string literal with the name of
141 /// the desired level. Level names are not case sensitive. For example:
142 ///
143 /// ```
144 /// # use tracing_attributes::instrument;
145 /// // The span's level will be TRACE rather than INFO.
146 /// #[instrument(level = "trace")]
147 /// pub fn my_function() {
148 /// // ... I have written a truly marvelous implementation of this function,
149 /// // which this example is too narrow to contain ...
150 /// }
151 /// ```
152 ///
153 /// # Skipping Fields
154 ///
155 /// To skip recording one or more arguments to a function or method, pass
156 /// the argument's name inside the `skip()` argument on the `#[instrument]`
157 /// macro. This can be used when an argument to an instrumented function does
158 /// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
159 /// costly `Debug` implementation. Note that:
160 ///
161 /// - multiple argument names can be passed to `skip`.
162 /// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
163 ///
164 /// You can also use `skip_all` to skip all arguments.
165 ///
166 /// ## Examples
167 ///
168 /// ```
169 /// # use tracing_attributes::instrument;
170 /// # use std::collections::HashMap;
171 /// // This type doesn't implement `fmt::Debug`!
172 /// struct NonDebug;
173 ///
174 /// // `arg` will be recorded, while `non_debug` will not.
175 /// #[instrument(skip(non_debug))]
176 /// fn my_function(arg: usize, non_debug: NonDebug) {
177 /// // ...
178 /// }
179 ///
180 /// // These arguments are huge
181 /// #[instrument(skip_all)]
182 /// fn my_big_data_function(large: Vec<u8>, also_large: HashMap<String, String>) {
183 /// // ...
184 /// }
185 /// ```
186 ///
187 /// Skipping the `self` parameter:
188 ///
189 /// ```
190 /// # use tracing_attributes::instrument;
191 /// #[derive(Debug)]
192 /// struct MyType {
193 /// data: Vec<u8>, // Suppose this buffer is often quite long...
194 /// }
195 ///
196 /// impl MyType {
197 /// // Suppose we don't want to print an entire kilobyte of `data`
198 /// // every time this is called...
199 /// #[instrument(skip(self))]
200 /// pub fn my_method(&mut self, an_interesting_argument: usize) {
201 /// // ... do something (hopefully, using all that `data`!)
202 /// }
203 /// }
204 /// ```
205 ///
206 /// # Adding Fields
207 ///
208 /// Additional fields (key-value pairs with arbitrary data) may be added to the
209 /// generated span using the `fields` argument on the `#[instrument]` macro. Any
210 /// Rust expression can be used as a field value in this manner. These
211 /// expressions will be evaluated at the beginning of the function's body, so
212 /// arguments to the function may be used in these expressions. Field names may
213 /// also be specified *without* values. Doing so will result in an [empty field]
214 /// whose value may be recorded later within the function body.
215 ///
216 /// This supports the same [field syntax] as the `span!` and `event!` macros.
217 ///
218 /// Note that overlap between the names of fields and (non-skipped) arguments
219 /// will result in a compile error.
220 ///
221 /// ## Examples
222 ///
223 /// Adding a new field based on the value of an argument:
224 ///
225 /// ```
226 /// # use tracing_attributes::instrument;
227 ///
228 /// // This will record a field named "i" with the value of `i` *and* a field
229 /// // named "next" with the value of `i` + 1.
230 /// #[instrument(fields(next = i + 1))]
231 /// pub fn my_function(i: usize) {
232 /// // ...
233 /// }
234 /// ```
235 ///
236 /// Recording specific properties of a struct as their own fields:
237 ///
238 /// ```
239 /// # mod http {
240 /// # pub struct Error;
241 /// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
242 /// # pub struct Request<B> { _b: B }
243 /// # impl<B> std::fmt::Debug for Request<B> {
244 /// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
245 /// # f.pad("request")
246 /// # }
247 /// # }
248 /// # impl<B> Request<B> {
249 /// # pub fn uri(&self) -> &str { "fake" }
250 /// # pub fn method(&self) -> &str { "GET" }
251 /// # }
252 /// # }
253 /// # use tracing_attributes::instrument;
254 ///
255 /// // This will record the request's URI and HTTP method as their own separate
256 /// // fields.
257 /// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
258 /// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
259 /// // ... handle the request ...
260 /// # http::Response { _b: std::marker::PhantomData }
261 /// }
262 /// ```
263 ///
264 /// This can be used in conjunction with `skip` or `skip_all` to record only
265 /// some fields of a struct:
266 /// ```
267 /// # use tracing_attributes::instrument;
268 /// // Remember the struct with the very large `data` field from the earlier
269 /// // example? Now it also has a `name`, which we might want to include in
270 /// // our span.
271 /// #[derive(Debug)]
272 /// struct MyType {
273 /// name: &'static str,
274 /// data: Vec<u8>,
275 /// }
276 ///
277 /// impl MyType {
278 /// // This will skip the `data` field, but will include `self.name`,
279 /// // formatted using `fmt::Display`.
280 /// #[instrument(skip(self), fields(self.name = %self.name))]
281 /// pub fn my_method(&mut self, an_interesting_argument: usize) {
282 /// // ... do something (hopefully, using all that `data`!)
283 /// }
284 /// }
285 /// ```
286 ///
287 /// Adding an empty field to be recorded later:
288 ///
289 /// ```
290 /// # use tracing_attributes::instrument;
291 ///
292 /// // This function does a very interesting and important mathematical calculation.
293 /// // Suppose we want to record both the inputs to the calculation *and* its result...
294 /// #[instrument(fields(result))]
295 /// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
296 /// // Rerform the calculation.
297 /// let result = input_1 + input_2;
298 ///
299 /// // Record the result as part of the current span.
300 /// tracing::Span::current().record("result", &result);
301 ///
302 /// // Now, the result will also be included on this event!
303 /// tracing::info!("calculation complete!");
304 ///
305 /// // ... etc ...
306 /// # 0
307 /// }
308 /// ```
309 ///
310 /// # Examples
311 ///
312 /// Instrumenting a function:
313 ///
314 /// ```
315 /// # use tracing_attributes::instrument;
316 /// #[instrument]
317 /// pub fn my_function(my_arg: usize) {
318 /// // This event will be recorded inside a span named `my_function` with the
319 /// // field `my_arg`.
320 /// tracing::info!("inside my_function!");
321 /// // ...
322 /// }
323 /// ```
324 /// Setting the level for the generated span:
325 /// ```
326 /// # use tracing_attributes::instrument;
327 /// #[instrument(level = "debug")]
328 /// pub fn my_function() {
329 /// // ...
330 /// }
331 /// ```
332 /// Overriding the generated span's name:
333 /// ```
334 /// # use tracing_attributes::instrument;
335 /// #[instrument(name = "my_name")]
336 /// pub fn my_function() {
337 /// // ...
338 /// }
339 /// ```
340 /// Overriding the generated span's target:
341 /// ```
342 /// # use tracing_attributes::instrument;
343 /// #[instrument(target = "my_target")]
344 /// pub fn my_function() {
345 /// // ...
346 /// }
347 /// ```
348 ///
349 /// To skip recording an argument, pass the argument's name to the `skip`:
350 ///
351 /// ```
352 /// # use tracing_attributes::instrument;
353 /// struct NonDebug;
354 ///
355 /// #[instrument(skip(non_debug))]
356 /// fn my_function(arg: usize, non_debug: NonDebug) {
357 /// // ...
358 /// }
359 /// ```
360 ///
361 /// To add an additional context to the span, pass key-value pairs to `fields`:
362 ///
363 /// ```
364 /// # use tracing_attributes::instrument;
365 /// #[instrument(fields(foo="bar", id=1, show=true))]
366 /// fn my_function(arg: usize) {
367 /// // ...
368 /// }
369 /// ```
370 ///
371 /// Adding the `ret` argument to `#[instrument]` will emit an event with the function's
372 /// return value when the function returns:
373 ///
374 /// ```
375 /// # use tracing_attributes::instrument;
376 /// #[instrument(ret)]
377 /// fn my_function() -> i32 {
378 /// 42
379 /// }
380 /// ```
381 /// The return value event will have the same level as the span generated by `#[instrument]`.
382 /// By default, this will be `TRACE`, but if the level is overridden, the event will be at the same
383 /// level.
384 ///
385 /// **Note**: if the function returns a `Result<T, E>`, `ret` will record returned values if and
386 /// only if the function returns [`Result::Ok`].
387 ///
388 /// By default, returned values will be recorded using their [`std::fmt::Debug`] implementations.
389 /// If a returned value implements [`std::fmt::Display`], it can be recorded using its `Display`
390 /// implementation instead, by writing `ret(Display)`:
391 ///
392 /// ```
393 /// # use tracing_attributes::instrument;
394 /// #[instrument(ret(Display))]
395 /// fn my_function() -> i32 {
396 /// 42
397 /// }
398 /// ```
399 ///
400 /// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, you can add
401 /// `err` or `err(Display)` to emit error events when the function returns `Err`:
402 ///
403 /// ```
404 /// # use tracing_attributes::instrument;
405 /// #[instrument(err)]
406 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
407 /// Ok(())
408 /// }
409 /// ```
410 ///
411 /// By default, error values will be recorded using their `std::fmt::Display` implementations.
412 /// If an error implements `std::fmt::Debug`, it can be recorded using its `Debug` implementation
413 /// instead, by writing `err(Debug)`:
414 ///
415 /// ```
416 /// # use tracing_attributes::instrument;
417 /// #[instrument(err(Debug))]
418 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
419 /// Ok(())
420 /// }
421 /// ```
422 ///
423 /// The `ret` and `err` arguments can be combined in order to record an event if a
424 /// function returns [`Result::Ok`] or [`Result::Err`]:
425 ///
426 /// ```
427 /// # use tracing_attributes::instrument;
428 /// #[instrument(err, ret)]
429 /// fn my_function(arg: usize) -> Result<(), std::io::Error> {
430 /// Ok(())
431 /// }
432 /// ```
433 ///
434 /// `async fn`s may also be instrumented:
435 ///
436 /// ```
437 /// # use tracing_attributes::instrument;
438 /// #[instrument]
439 /// pub async fn my_function() -> Result<(), ()> {
440 /// // ...
441 /// # Ok(())
442 /// }
443 /// ```
444 ///
445 /// It also works with [async-trait](https://crates.io/crates/async-trait)
446 /// (a crate that allows defining async functions in traits,
447 /// something not currently possible in Rust),
448 /// and hopefully most libraries that exhibit similar behaviors:
449 ///
450 /// ```
451 /// # use tracing::instrument;
452 /// use async_trait::async_trait;
453 ///
454 /// #[async_trait]
455 /// pub trait Foo {
456 /// async fn foo(&self, arg: usize);
457 /// }
458 ///
459 /// #[derive(Debug)]
460 /// struct FooImpl(usize);
461 ///
462 /// #[async_trait]
463 /// impl Foo for FooImpl {
464 /// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
465 /// async fn foo(&self, arg: usize) {}
466 /// }
467 /// ```
468 ///
469 /// Note than on `async-trait` <= 0.1.43, references to the `Self`
470 /// type inside the `fields` argument were only allowed when the instrumented
471 /// function is a method (i.e., the function receives `self` as an argument).
472 /// For example, this *used to not work* because the instrument function
473 /// didn't receive `self`:
474 /// ```
475 /// # use tracing::instrument;
476 /// use async_trait::async_trait;
477 ///
478 /// #[async_trait]
479 /// pub trait Bar {
480 /// async fn bar();
481 /// }
482 ///
483 /// #[derive(Debug)]
484 /// struct BarImpl(usize);
485 ///
486 /// #[async_trait]
487 /// impl Bar for BarImpl {
488 /// #[instrument(fields(tmp = std::any::type_name::<Self>()))]
489 /// async fn bar() {}
490 /// }
491 /// ```
492 /// Instead, you should manually rewrite any `Self` types as the type for
493 /// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`
494 /// (or maybe you can just bump `async-trait`).
495 ///
496 /// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
497 /// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
498 /// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
499 /// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
500 /// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
501 /// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
502 /// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
503 /// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
504 /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
505 #[proc_macro_attribute]
506 pub fn instrument(
507 args: proc_macro::TokenStream,
508 item: proc_macro::TokenStream,
509 ) -> proc_macro::TokenStream {
510 let args = syn::parse_macro_input!(args as attr::InstrumentArgs);
511 // Cloning a `TokenStream` is cheap since it's reference counted internally.
512 instrument_precise(args.clone(), item.clone())
513 .unwrap_or_else(|_err| instrument_speculative(args, item))
514 }
515
516 /// Instrument the function, without parsing the function body (instead using the raw tokens).
517 fn instrument_speculative(
518 args: attr::InstrumentArgs,
519 item: proc_macro::TokenStream,
520 ) -> proc_macro::TokenStream {
521 let input = syn::parse_macro_input!(item as MaybeItemFn);
522 let instrumented_function_name = input.sig.ident.to_string();
523 expand::gen_function(
524 input.as_ref(),
525 args,
526 instrumented_function_name.as_str(),
527 None,
528 )
529 .into()
530 }
531
532 /// Instrument the function, by fully parsing the function body,
533 /// which allows us to rewrite some statements related to async-like patterns.
534 fn instrument_precise(
535 args: attr::InstrumentArgs,
536 item: proc_macro::TokenStream,
537 ) -> Result<proc_macro::TokenStream, syn::Error> {
538 let input = syn::parse::<ItemFn>(item)?;
539 let instrumented_function_name = input.sig.ident.to_string();
540
541 // check for async_trait-like patterns in the block, and instrument
542 // the future instead of the wrapper
543 if let Some(async_like) = expand::AsyncInfo::from_fn(&input) {
544 return Ok(async_like.gen_async(args, instrumented_function_name.as_str()));
545 }
546
547 Ok(expand::gen_function(
548 (&input).into(),
549 args,
550 instrumented_function_name.as_str(),
551 None,
552 )
553 .into())
554 }
555
556 /// This is a more flexible/imprecise `ItemFn` type,
557 /// which's block is just a `TokenStream` (it may contain invalid code).
558 #[derive(Debug, Clone)]
559 struct MaybeItemFn {
560 attrs: Vec<Attribute>,
561 vis: Visibility,
562 sig: Signature,
563 block: TokenStream,
564 }
565
566 impl MaybeItemFn {
567 fn as_ref(&self) -> MaybeItemFnRef<'_, TokenStream> {
568 MaybeItemFnRef {
569 attrs: &self.attrs,
570 vis: &self.vis,
571 sig: &self.sig,
572 block: &self.block,
573 }
574 }
575 }
576
577 /// This parses a `TokenStream` into a `MaybeItemFn`
578 /// (just like `ItemFn`, but skips parsing the body).
579 impl Parse for MaybeItemFn {
580 fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
581 let attrs = input.call(syn::Attribute::parse_outer)?;
582 let vis: Visibility = input.parse()?;
583 let sig: Signature = input.parse()?;
584 let block: TokenStream = input.parse()?;
585 Ok(Self {
586 attrs,
587 vis,
588 sig,
589 block,
590 })
591 }
592 }
593
594 /// A generic reference type for `MaybeItemFn`,
595 /// that takes a generic block type `B` that implements `ToTokens` (eg. `TokenStream`, `Block`).
596 #[derive(Debug, Clone)]
597 struct MaybeItemFnRef<'a, B: ToTokens> {
598 attrs: &'a Vec<Attribute>,
599 vis: &'a Visibility,
600 sig: &'a Signature,
601 block: &'a B,
602 }
603
604 impl<'a> From<&'a ItemFn> for MaybeItemFnRef<'a, Box<Block>> {
605 fn from(val: &'a ItemFn) -> Self {
606 MaybeItemFnRef {
607 attrs: &val.attrs,
608 vis: &val.vis,
609 sig: &val.sig,
610 block: &val.block,
611 }
612 }
613 }