summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tracing-attributes/src/lib.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/tracing-attributes/src/lib.rs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--third_party/rust/tracing-attributes/src/lib.rs677
1 files changed, 677 insertions, 0 deletions
diff --git a/third_party/rust/tracing-attributes/src/lib.rs b/third_party/rust/tracing-attributes/src/lib.rs
new file mode 100644
index 0000000000..f5974e4e52
--- /dev/null
+++ b/third_party/rust/tracing-attributes/src/lib.rs
@@ -0,0 +1,677 @@
+//! A procedural macro attribute for instrumenting functions with [`tracing`].
+//!
+//! [`tracing`] is a framework for instrumenting Rust programs to collect
+//! structured, event-based diagnostic information. This crate provides the
+//! [`#[instrument]`][instrument] procedural macro attribute.
+//!
+//! Note that this macro is also re-exported by the main `tracing` crate.
+//!
+//! *Compiler support: [requires `rustc` 1.49+][msrv]*
+//!
+//! [msrv]: #supported-rust-versions
+//!
+//! ## Usage
+//!
+//! First, add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! tracing-attributes = "0.1.23"
+//! ```
+//!
+//! The [`#[instrument]`][instrument] attribute can now be added to a function
+//! to automatically create and enter `tracing` [span] when that function is
+//! called. For example:
+//!
+//! ```
+//! use tracing_attributes::instrument;
+//!
+//! #[instrument]
+//! pub fn my_function(my_arg: usize) {
+//! // ...
+//! }
+//!
+//! # fn main() {}
+//! ```
+//!
+//! [`tracing`]: https://crates.io/crates/tracing
+//! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
+//! [instrument]: macro@self::instrument
+//!
+//! ## Supported Rust Versions
+//!
+//! Tracing is built against the latest stable release. The minimum supported
+//! version is 1.49. The current Tracing version is not guaranteed to build on
+//! Rust versions earlier than the minimum supported version.
+//!
+//! Tracing follows the same compiler support policies as the rest of the Tokio
+//! project. The current stable Rust compiler and the three most recent minor
+//! versions before it will always be supported. For example, if the current
+//! stable compiler version is 1.45, the minimum supported version will not be
+//! increased past 1.42, three minor versions prior. Increasing the minimum
+//! supported compiler version is not considered a semver breaking change as
+//! long as doing so complies with this policy.
+//!
+#![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.23")]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
+ issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
+)]
+#![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
+#![warn(
+ missing_debug_implementations,
+ missing_docs,
+ rust_2018_idioms,
+ unreachable_pub,
+ bad_style,
+ const_err,
+ dead_code,
+ improper_ctypes,
+ non_shorthand_field_patterns,
+ no_mangle_generic_items,
+ overflowing_literals,
+ path_statements,
+ patterns_in_fns_without_body,
+ private_in_public,
+ unconditional_recursion,
+ unused_allocation,
+ unused_comparisons,
+ unused_parens,
+ while_true
+)]
+// TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
+#![allow(unused)]
+extern crate proc_macro;
+
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::parse::{Parse, ParseStream};
+use syn::{Attribute, ItemFn, Signature, Visibility};
+
+mod attr;
+mod expand;
+/// Instruments a function to create and enter a `tracing` [span] every time
+/// the function is called.
+///
+/// Unless overriden, a span with the [`INFO`] [level] will be generated.
+/// The generated span's name will be the name of the function.
+/// By default, all arguments to the function are included as fields on the
+/// span. Arguments that are `tracing` [primitive types] implementing the
+/// [`Value` trait] will be recorded as fields of that type. Types which do
+/// not implement `Value` will be recorded using [`std::fmt::Debug`].
+///
+/// [primitive types]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html#foreign-impls
+/// [`Value` trait]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html.
+///
+/// # Overriding Span Attributes
+///
+/// To change the [name] of the generated span, add a `name` argument to the
+/// `#[instrument]` macro, followed by an equals sign and a string literal. For
+/// example:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+///
+/// // The generated span's name will be "my_span" rather than "my_function".
+/// #[instrument(name = "my_span")]
+/// pub fn my_function() {
+/// // ... do something incredibly interesting and important ...
+/// }
+/// ```
+///
+/// To override the [target] of the generated span, add a `target` argument to
+/// the `#[instrument]` macro, followed by an equals sign and a string literal
+/// for the new target. The [module path] is still recorded separately. For
+/// example:
+///
+/// ```
+/// pub mod my_module {
+/// # use tracing_attributes::instrument;
+/// // The generated span's target will be "my_crate::some_special_target",
+/// // rather than "my_crate::my_module".
+/// #[instrument(target = "my_crate::some_special_target")]
+/// pub fn my_function() {
+/// // ... all kinds of neat code in here ...
+/// }
+/// }
+/// ```
+///
+/// Finally, to override the [level] of the generated span, add a `level`
+/// argument, followed by an equals sign and a string literal with the name of
+/// the desired level. Level names are not case sensitive. For example:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// // The span's level will be TRACE rather than INFO.
+/// #[instrument(level = "trace")]
+/// pub fn my_function() {
+/// // ... I have written a truly marvelous implementation of this function,
+/// // which this example is too narrow to contain ...
+/// }
+/// ```
+///
+/// # Skipping Fields
+///
+/// To skip recording one or more arguments to a function or method, pass
+/// the argument's name inside the `skip()` argument on the `#[instrument]`
+/// macro. This can be used when an argument to an instrumented function does
+/// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
+/// costly `Debug` implementation. Note that:
+///
+/// - multiple argument names can be passed to `skip`.
+/// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
+///
+/// You can also use `skip_all` to skip all arguments.
+///
+/// ## Examples
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// # use std::collections::HashMap;
+/// // This type doesn't implement `fmt::Debug`!
+/// struct NonDebug;
+///
+/// // `arg` will be recorded, while `non_debug` will not.
+/// #[instrument(skip(non_debug))]
+/// fn my_function(arg: usize, non_debug: NonDebug) {
+/// // ...
+/// }
+///
+/// // These arguments are huge
+/// #[instrument(skip_all)]
+/// fn my_big_data_function(large: Vec<u8>, also_large: HashMap<String, String>) {
+/// // ...
+/// }
+/// ```
+///
+/// Skipping the `self` parameter:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[derive(Debug)]
+/// struct MyType {
+/// data: Vec<u8>, // Suppose this buffer is often quite long...
+/// }
+///
+/// impl MyType {
+/// // Suppose we don't want to print an entire kilobyte of `data`
+/// // every time this is called...
+/// #[instrument(skip(self))]
+/// pub fn my_method(&mut self, an_interesting_argument: usize) {
+/// // ... do something (hopefully, using all that `data`!)
+/// }
+/// }
+/// ```
+///
+/// # Adding Fields
+///
+/// Additional fields (key-value pairs with arbitrary data) may be added to the
+/// generated span using the `fields` argument on the `#[instrument]` macro. Any
+/// Rust expression can be used as a field value in this manner. These
+/// expressions will be evaluated at the beginning of the function's body, so
+/// arguments to the function may be used in these expressions. Field names may
+/// also be specified *without* values. Doing so will result in an [empty field]
+/// whose value may be recorded later within the function body.
+///
+/// This supports the same [field syntax] as the `span!` and `event!` macros.
+///
+/// Note that overlap between the names of fields and (non-skipped) arguments
+/// will result in a compile error.
+///
+/// ## Examples
+///
+/// Adding a new field based on the value of an argument:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+///
+/// // This will record a field named "i" with the value of `i` *and* a field
+/// // named "next" with the value of `i` + 1.
+/// #[instrument(fields(next = i + 1))]
+/// pub fn my_function(i: usize) {
+/// // ...
+/// }
+/// ```
+///
+/// Recording specific properties of a struct as their own fields:
+///
+/// ```
+/// # mod http {
+/// # pub struct Error;
+/// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
+/// # pub struct Request<B> { _b: B }
+/// # impl<B> std::fmt::Debug for Request<B> {
+/// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+/// # f.pad("request")
+/// # }
+/// # }
+/// # impl<B> Request<B> {
+/// # pub fn uri(&self) -> &str { "fake" }
+/// # pub fn method(&self) -> &str { "GET" }
+/// # }
+/// # }
+/// # use tracing_attributes::instrument;
+///
+/// // This will record the request's URI and HTTP method as their own separate
+/// // fields.
+/// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
+/// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
+/// // ... handle the request ...
+/// # http::Response { _b: std::marker::PhantomData }
+/// }
+/// ```
+///
+/// This can be used in conjunction with `skip` or `skip_all` to record only
+/// some fields of a struct:
+/// ```
+/// # use tracing_attributes::instrument;
+/// // Remember the struct with the very large `data` field from the earlier
+/// // example? Now it also has a `name`, which we might want to include in
+/// // our span.
+/// #[derive(Debug)]
+/// struct MyType {
+/// name: &'static str,
+/// data: Vec<u8>,
+/// }
+///
+/// impl MyType {
+/// // This will skip the `data` field, but will include `self.name`,
+/// // formatted using `fmt::Display`.
+/// #[instrument(skip(self), fields(self.name = %self.name))]
+/// pub fn my_method(&mut self, an_interesting_argument: usize) {
+/// // ... do something (hopefully, using all that `data`!)
+/// }
+/// }
+/// ```
+///
+/// Adding an empty field to be recorded later:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+///
+/// // This function does a very interesting and important mathematical calculation.
+/// // Suppose we want to record both the inputs to the calculation *and* its result...
+/// #[instrument(fields(result))]
+/// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
+/// // Rerform the calculation.
+/// let result = input_1 + input_2;
+///
+/// // Record the result as part of the current span.
+/// tracing::Span::current().record("result", &result);
+///
+/// // Now, the result will also be included on this event!
+/// tracing::info!("calculation complete!");
+///
+/// // ... etc ...
+/// # 0
+/// }
+/// ```
+///
+/// # Examples
+///
+/// Instrumenting a function:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument]
+/// pub fn my_function(my_arg: usize) {
+/// // This event will be recorded inside a span named `my_function` with the
+/// // field `my_arg`.
+/// tracing::info!("inside my_function!");
+/// // ...
+/// }
+/// ```
+/// Setting the level for the generated span:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(level = "debug")]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// Overriding the generated span's name:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(name = "my_name")]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// Overriding the generated span's target:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(target = "my_target")]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// Overriding the generated span's parent:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(parent = None)]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// ```
+/// # use tracing_attributes::instrument;
+/// // A struct which owns a span handle.
+/// struct MyStruct
+/// {
+/// span: tracing::Span
+/// }
+///
+/// impl MyStruct
+/// {
+/// // Use the struct's `span` field as the parent span
+/// #[instrument(parent = &self.span, skip(self))]
+/// fn my_method(&self) {}
+/// }
+/// ```
+/// Specifying [`follows_from`] relationships:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(follows_from = causes)]
+/// pub fn my_function(causes: &[tracing::Id]) {
+/// // ...
+/// }
+/// ```
+/// Any expression of type `impl IntoIterator<Item = impl Into<Option<Id>>>`
+/// may be provided to `follows_from`; e.g.:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(follows_from = [cause])]
+/// pub fn my_function(cause: &tracing::span::EnteredSpan) {
+/// // ...
+/// }
+/// ```
+///
+///
+/// To skip recording an argument, pass the argument's name to the `skip`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// struct NonDebug;
+///
+/// #[instrument(skip(non_debug))]
+/// fn my_function(arg: usize, non_debug: NonDebug) {
+/// // ...
+/// }
+/// ```
+///
+/// To add an additional context to the span, pass key-value pairs to `fields`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(fields(foo="bar", id=1, show=true))]
+/// fn my_function(arg: usize) {
+/// // ...
+/// }
+/// ```
+///
+/// Adding the `ret` argument to `#[instrument]` will emit an event with the function's
+/// return value when the function returns:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(ret)]
+/// fn my_function() -> i32 {
+/// 42
+/// }
+/// ```
+/// The return value event will have the same level as the span generated by `#[instrument]`.
+/// By default, this will be [`INFO`], but if the level is overridden, the event will be at the same
+/// level.
+///
+/// **Note**: if the function returns a `Result<T, E>`, `ret` will record returned values if and
+/// only if the function returns [`Result::Ok`].
+///
+/// By default, returned values will be recorded using their [`std::fmt::Debug`] implementations.
+/// If a returned value implements [`std::fmt::Display`], it can be recorded using its `Display`
+/// implementation instead, by writing `ret(Display)`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(ret(Display))]
+/// fn my_function() -> i32 {
+/// 42
+/// }
+/// ```
+///
+/// If the function returns a `Result<T, E>` and `E` implements `std::fmt::Display`, you can add
+/// `err` or `err(Display)` to emit error events when the function returns `Err`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(err)]
+/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
+/// Ok(())
+/// }
+/// ```
+///
+/// By default, error values will be recorded using their `std::fmt::Display` implementations.
+/// If an error implements `std::fmt::Debug`, it can be recorded using its `Debug` implementation
+/// instead, by writing `err(Debug)`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(err(Debug))]
+/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
+/// Ok(())
+/// }
+/// ```
+///
+/// If a `target` is specified, both the `ret` and `err` arguments will emit outputs to
+/// the declared target (or the default channel if `target` is not specified).
+///
+/// The `ret` and `err` arguments can be combined in order to record an event if a
+/// function returns [`Result::Ok`] or [`Result::Err`]:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(err, ret)]
+/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
+/// Ok(())
+/// }
+/// ```
+///
+/// `async fn`s may also be instrumented:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument]
+/// pub async fn my_function() -> Result<(), ()> {
+/// // ...
+/// # Ok(())
+/// }
+/// ```
+///
+/// It also works with [async-trait](https://crates.io/crates/async-trait)
+/// (a crate that allows defining async functions in traits,
+/// something not currently possible in Rust),
+/// and hopefully most libraries that exhibit similar behaviors:
+///
+/// ```
+/// # use tracing::instrument;
+/// use async_trait::async_trait;
+///
+/// #[async_trait]
+/// pub trait Foo {
+/// async fn foo(&self, arg: usize);
+/// }
+///
+/// #[derive(Debug)]
+/// struct FooImpl(usize);
+///
+/// #[async_trait]
+/// impl Foo for FooImpl {
+/// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
+/// async fn foo(&self, arg: usize) {}
+/// }
+/// ```
+///
+/// Note than on `async-trait` <= 0.1.43, references to the `Self`
+/// type inside the `fields` argument were only allowed when the instrumented
+/// function is a method (i.e., the function receives `self` as an argument).
+/// For example, this *used to not work* because the instrument function
+/// didn't receive `self`:
+/// ```
+/// # use tracing::instrument;
+/// use async_trait::async_trait;
+///
+/// #[async_trait]
+/// pub trait Bar {
+/// async fn bar();
+/// }
+///
+/// #[derive(Debug)]
+/// struct BarImpl(usize);
+///
+/// #[async_trait]
+/// impl Bar for BarImpl {
+/// #[instrument(fields(tmp = std::any::type_name::<Self>()))]
+/// async fn bar() {}
+/// }
+/// ```
+/// Instead, you should manually rewrite any `Self` types as the type for
+/// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`
+/// (or maybe you can just bump `async-trait`).
+///
+/// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
+/// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
+/// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
+/// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
+/// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
+/// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
+/// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
+/// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
+/// [`follows_from`]: https://docs.rs/tracing/latest/tracing/struct.Span.html#method.follows_from
+/// [`tracing`]: https://github.com/tokio-rs/tracing
+/// [`fmt::Debug`]: std::fmt::Debug
+#[proc_macro_attribute]
+pub fn instrument(
+ args: proc_macro::TokenStream,
+ item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+ let args = syn::parse_macro_input!(args as attr::InstrumentArgs);
+ // Cloning a `TokenStream` is cheap since it's reference counted internally.
+ instrument_precise(args.clone(), item.clone())
+ .unwrap_or_else(|_err| instrument_speculative(args, item))
+}
+
+/// Instrument the function, without parsing the function body (instead using the raw tokens).
+fn instrument_speculative(
+ args: attr::InstrumentArgs,
+ item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+ let input = syn::parse_macro_input!(item as MaybeItemFn);
+ let instrumented_function_name = input.sig.ident.to_string();
+ expand::gen_function(
+ input.as_ref(),
+ args,
+ instrumented_function_name.as_str(),
+ None,
+ )
+ .into()
+}
+
+/// Instrument the function, by fully parsing the function body,
+/// which allows us to rewrite some statements related to async-like patterns.
+fn instrument_precise(
+ args: attr::InstrumentArgs,
+ item: proc_macro::TokenStream,
+) -> Result<proc_macro::TokenStream, syn::Error> {
+ let input = syn::parse::<ItemFn>(item)?;
+ let instrumented_function_name = input.sig.ident.to_string();
+
+ // check for async_trait-like patterns in the block, and instrument
+ // the future instead of the wrapper
+ if let Some(async_like) = expand::AsyncInfo::from_fn(&input) {
+ return async_like.gen_async(args, instrumented_function_name.as_str());
+ }
+
+ let input = MaybeItemFn::from(input);
+
+ Ok(expand::gen_function(
+ input.as_ref(),
+ args,
+ instrumented_function_name.as_str(),
+ None,
+ )
+ .into())
+}
+
+/// This is a more flexible/imprecise `ItemFn` type,
+/// which's block is just a `TokenStream` (it may contain invalid code).
+#[derive(Debug, Clone)]
+struct MaybeItemFn {
+ outer_attrs: Vec<Attribute>,
+ inner_attrs: Vec<Attribute>,
+ vis: Visibility,
+ sig: Signature,
+ block: TokenStream,
+}
+
+impl MaybeItemFn {
+ fn as_ref(&self) -> MaybeItemFnRef<'_, TokenStream> {
+ MaybeItemFnRef {
+ outer_attrs: &self.outer_attrs,
+ inner_attrs: &self.inner_attrs,
+ vis: &self.vis,
+ sig: &self.sig,
+ block: &self.block,
+ }
+ }
+}
+
+/// This parses a `TokenStream` into a `MaybeItemFn`
+/// (just like `ItemFn`, but skips parsing the body).
+impl Parse for MaybeItemFn {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let sig: Signature = input.parse()?;
+ let inner_attrs = input.call(Attribute::parse_inner)?;
+ let block: TokenStream = input.parse()?;
+ Ok(Self {
+ outer_attrs,
+ inner_attrs,
+ vis,
+ sig,
+ block,
+ })
+ }
+}
+
+impl From<ItemFn> for MaybeItemFn {
+ fn from(
+ ItemFn {
+ attrs,
+ vis,
+ sig,
+ block,
+ }: ItemFn,
+ ) -> Self {
+ let (outer_attrs, inner_attrs) = attrs
+ .into_iter()
+ .partition(|attr| attr.style == syn::AttrStyle::Outer);
+ Self {
+ outer_attrs,
+ inner_attrs,
+ vis,
+ sig,
+ block: block.to_token_stream(),
+ }
+ }
+}
+
+/// A generic reference type for `MaybeItemFn`,
+/// that takes a generic block type `B` that implements `ToTokens` (eg. `TokenStream`, `Block`).
+#[derive(Debug, Clone)]
+struct MaybeItemFnRef<'a, B: ToTokens> {
+ outer_attrs: &'a Vec<Attribute>,
+ inner_attrs: &'a Vec<Attribute>,
+ vis: &'a Visibility,
+ sig: &'a Signature,
+ block: &'a B,
+}