summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tracing-attributes/src
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
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/tracing-attributes/src')
-rw-r--r--third_party/rust/tracing-attributes/src/attr.rs413
-rw-r--r--third_party/rust/tracing-attributes/src/expand.rs814
-rw-r--r--third_party/rust/tracing-attributes/src/lib.rs677
3 files changed, 1904 insertions, 0 deletions
diff --git a/third_party/rust/tracing-attributes/src/attr.rs b/third_party/rust/tracing-attributes/src/attr.rs
new file mode 100644
index 0000000000..ff875e1797
--- /dev/null
+++ b/third_party/rust/tracing-attributes/src/attr.rs
@@ -0,0 +1,413 @@
+use std::collections::HashSet;
+use syn::{punctuated::Punctuated, Expr, Ident, LitInt, LitStr, Path, Token};
+
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned, ToTokens};
+use syn::ext::IdentExt as _;
+use syn::parse::{Parse, ParseStream};
+
+#[derive(Clone, Default, Debug)]
+pub(crate) struct InstrumentArgs {
+ level: Option<Level>,
+ pub(crate) name: Option<LitStr>,
+ target: Option<LitStr>,
+ pub(crate) parent: Option<Expr>,
+ pub(crate) follows_from: Option<Expr>,
+ pub(crate) skips: HashSet<Ident>,
+ pub(crate) skip_all: bool,
+ pub(crate) fields: Option<Fields>,
+ pub(crate) err_mode: Option<FormatMode>,
+ pub(crate) ret_mode: Option<FormatMode>,
+ /// Errors describing any unrecognized parse inputs that we skipped.
+ parse_warnings: Vec<syn::Error>,
+}
+
+impl InstrumentArgs {
+ pub(crate) fn level(&self) -> impl ToTokens {
+ fn is_level(lit: &LitInt, expected: u64) -> bool {
+ match lit.base10_parse::<u64>() {
+ Ok(value) => value == expected,
+ Err(_) => false,
+ }
+ }
+
+ match &self.level {
+ Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("trace") => {
+ quote!(tracing::Level::TRACE)
+ }
+ Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("debug") => {
+ quote!(tracing::Level::DEBUG)
+ }
+ Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("info") => {
+ quote!(tracing::Level::INFO)
+ }
+ Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("warn") => {
+ quote!(tracing::Level::WARN)
+ }
+ Some(Level::Str(ref lit)) if lit.value().eq_ignore_ascii_case("error") => {
+ quote!(tracing::Level::ERROR)
+ }
+ Some(Level::Int(ref lit)) if is_level(lit, 1) => quote!(tracing::Level::TRACE),
+ Some(Level::Int(ref lit)) if is_level(lit, 2) => quote!(tracing::Level::DEBUG),
+ Some(Level::Int(ref lit)) if is_level(lit, 3) => quote!(tracing::Level::INFO),
+ Some(Level::Int(ref lit)) if is_level(lit, 4) => quote!(tracing::Level::WARN),
+ Some(Level::Int(ref lit)) if is_level(lit, 5) => quote!(tracing::Level::ERROR),
+ Some(Level::Path(ref pat)) => quote!(#pat),
+ Some(_) => quote! {
+ compile_error!(
+ "unknown verbosity level, expected one of \"trace\", \
+ \"debug\", \"info\", \"warn\", or \"error\", or a number 1-5"
+ )
+ },
+ None => quote!(tracing::Level::INFO),
+ }
+ }
+
+ pub(crate) fn target(&self) -> impl ToTokens {
+ if let Some(ref target) = self.target {
+ quote!(#target)
+ } else {
+ quote!(module_path!())
+ }
+ }
+
+ /// Generate "deprecation" warnings for any unrecognized attribute inputs
+ /// that we skipped.
+ ///
+ /// For backwards compatibility, we need to emit compiler warnings rather
+ /// than errors for unrecognized inputs. Generating a fake deprecation is
+ /// the only way to do this on stable Rust right now.
+ pub(crate) fn warnings(&self) -> impl ToTokens {
+ let warnings = self.parse_warnings.iter().map(|err| {
+ let msg = format!("found unrecognized input, {}", err);
+ let msg = LitStr::new(&msg, err.span());
+ // TODO(eliza): This is a bit of a hack, but it's just about the
+ // only way to emit warnings from a proc macro on stable Rust.
+ // Eventually, when the `proc_macro::Diagnostic` API stabilizes, we
+ // should definitely use that instead.
+ quote_spanned! {err.span()=>
+ #[warn(deprecated)]
+ {
+ #[deprecated(since = "not actually deprecated", note = #msg)]
+ const TRACING_INSTRUMENT_WARNING: () = ();
+ let _ = TRACING_INSTRUMENT_WARNING;
+ }
+ }
+ });
+ quote! {
+ { #(#warnings)* }
+ }
+ }
+}
+
+impl Parse for InstrumentArgs {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let mut args = Self::default();
+ while !input.is_empty() {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(kw::name) {
+ if args.name.is_some() {
+ return Err(input.error("expected only a single `name` argument"));
+ }
+ let name = input.parse::<StrArg<kw::name>>()?.value;
+ args.name = Some(name);
+ } else if lookahead.peek(LitStr) {
+ // XXX: apparently we support names as either named args with an
+ // sign, _or_ as unnamed string literals. That's weird, but
+ // changing it is apparently breaking.
+ if args.name.is_some() {
+ return Err(input.error("expected only a single `name` argument"));
+ }
+ args.name = Some(input.parse()?);
+ } else if lookahead.peek(kw::target) {
+ if args.target.is_some() {
+ return Err(input.error("expected only a single `target` argument"));
+ }
+ let target = input.parse::<StrArg<kw::target>>()?.value;
+ args.target = Some(target);
+ } else if lookahead.peek(kw::parent) {
+ if args.target.is_some() {
+ return Err(input.error("expected only a single `parent` argument"));
+ }
+ let parent = input.parse::<ExprArg<kw::parent>>()?;
+ args.parent = Some(parent.value);
+ } else if lookahead.peek(kw::follows_from) {
+ if args.target.is_some() {
+ return Err(input.error("expected only a single `follows_from` argument"));
+ }
+ let follows_from = input.parse::<ExprArg<kw::follows_from>>()?;
+ args.follows_from = Some(follows_from.value);
+ } else if lookahead.peek(kw::level) {
+ if args.level.is_some() {
+ return Err(input.error("expected only a single `level` argument"));
+ }
+ args.level = Some(input.parse()?);
+ } else if lookahead.peek(kw::skip) {
+ if !args.skips.is_empty() {
+ return Err(input.error("expected only a single `skip` argument"));
+ }
+ if args.skip_all {
+ return Err(input.error("expected either `skip` or `skip_all` argument"));
+ }
+ let Skips(skips) = input.parse()?;
+ args.skips = skips;
+ } else if lookahead.peek(kw::skip_all) {
+ if args.skip_all {
+ return Err(input.error("expected only a single `skip_all` argument"));
+ }
+ if !args.skips.is_empty() {
+ return Err(input.error("expected either `skip` or `skip_all` argument"));
+ }
+ let _ = input.parse::<kw::skip_all>()?;
+ args.skip_all = true;
+ } else if lookahead.peek(kw::fields) {
+ if args.fields.is_some() {
+ return Err(input.error("expected only a single `fields` argument"));
+ }
+ args.fields = Some(input.parse()?);
+ } else if lookahead.peek(kw::err) {
+ let _ = input.parse::<kw::err>();
+ let mode = FormatMode::parse(input)?;
+ args.err_mode = Some(mode);
+ } else if lookahead.peek(kw::ret) {
+ let _ = input.parse::<kw::ret>()?;
+ let mode = FormatMode::parse(input)?;
+ args.ret_mode = Some(mode);
+ } else if lookahead.peek(Token![,]) {
+ let _ = input.parse::<Token![,]>()?;
+ } else {
+ // We found a token that we didn't expect!
+ // We want to emit warnings for these, rather than errors, so
+ // we'll add it to the list of unrecognized inputs we've seen so
+ // far and keep going.
+ args.parse_warnings.push(lookahead.error());
+ // Parse the unrecognized token tree to advance the parse
+ // stream, and throw it away so we can keep parsing.
+ let _ = input.parse::<proc_macro2::TokenTree>();
+ }
+ }
+ Ok(args)
+ }
+}
+
+struct StrArg<T> {
+ value: LitStr,
+ _p: std::marker::PhantomData<T>,
+}
+
+impl<T: Parse> Parse for StrArg<T> {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<T>()?;
+ let _ = input.parse::<Token![=]>()?;
+ let value = input.parse()?;
+ Ok(Self {
+ value,
+ _p: std::marker::PhantomData,
+ })
+ }
+}
+
+struct ExprArg<T> {
+ value: Expr,
+ _p: std::marker::PhantomData<T>,
+}
+
+impl<T: Parse> Parse for ExprArg<T> {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<T>()?;
+ let _ = input.parse::<Token![=]>()?;
+ let value = input.parse()?;
+ Ok(Self {
+ value,
+ _p: std::marker::PhantomData,
+ })
+ }
+}
+
+struct Skips(HashSet<Ident>);
+
+impl Parse for Skips {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<kw::skip>();
+ let content;
+ let _ = syn::parenthesized!(content in input);
+ let names: Punctuated<Ident, Token![,]> = content.parse_terminated(Ident::parse_any)?;
+ let mut skips = HashSet::new();
+ for name in names {
+ if skips.contains(&name) {
+ return Err(syn::Error::new(
+ name.span(),
+ "tried to skip the same field twice",
+ ));
+ } else {
+ skips.insert(name);
+ }
+ }
+ Ok(Self(skips))
+ }
+}
+
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub(crate) enum FormatMode {
+ Default,
+ Display,
+ Debug,
+}
+
+impl Default for FormatMode {
+ fn default() -> Self {
+ FormatMode::Default
+ }
+}
+
+impl Parse for FormatMode {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ if !input.peek(syn::token::Paren) {
+ return Ok(FormatMode::default());
+ }
+ let content;
+ let _ = syn::parenthesized!(content in input);
+ let maybe_mode: Option<Ident> = content.parse()?;
+ maybe_mode.map_or(Ok(FormatMode::default()), |ident| {
+ match ident.to_string().as_str() {
+ "Debug" => Ok(FormatMode::Debug),
+ "Display" => Ok(FormatMode::Display),
+ _ => Err(syn::Error::new(
+ ident.span(),
+ "unknown error mode, must be Debug or Display",
+ )),
+ }
+ })
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct Fields(pub(crate) Punctuated<Field, Token![,]>);
+
+#[derive(Clone, Debug)]
+pub(crate) struct Field {
+ pub(crate) name: Punctuated<Ident, Token![.]>,
+ pub(crate) value: Option<Expr>,
+ pub(crate) kind: FieldKind,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub(crate) enum FieldKind {
+ Debug,
+ Display,
+ Value,
+}
+
+impl Parse for Fields {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<kw::fields>();
+ let content;
+ let _ = syn::parenthesized!(content in input);
+ let fields: Punctuated<_, Token![,]> = content.parse_terminated(Field::parse)?;
+ Ok(Self(fields))
+ }
+}
+
+impl ToTokens for Fields {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.0.to_tokens(tokens)
+ }
+}
+
+impl Parse for Field {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let mut kind = FieldKind::Value;
+ if input.peek(Token![%]) {
+ input.parse::<Token![%]>()?;
+ kind = FieldKind::Display;
+ } else if input.peek(Token![?]) {
+ input.parse::<Token![?]>()?;
+ kind = FieldKind::Debug;
+ };
+ let name = Punctuated::parse_separated_nonempty_with(input, Ident::parse_any)?;
+ let value = if input.peek(Token![=]) {
+ input.parse::<Token![=]>()?;
+ if input.peek(Token![%]) {
+ input.parse::<Token![%]>()?;
+ kind = FieldKind::Display;
+ } else if input.peek(Token![?]) {
+ input.parse::<Token![?]>()?;
+ kind = FieldKind::Debug;
+ };
+ Some(input.parse()?)
+ } else {
+ None
+ };
+ Ok(Self { name, value, kind })
+ }
+}
+
+impl ToTokens for Field {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if let Some(ref value) = self.value {
+ let name = &self.name;
+ let kind = &self.kind;
+ tokens.extend(quote! {
+ #name = #kind#value
+ })
+ } else if self.kind == FieldKind::Value {
+ // XXX(eliza): I don't like that fields without values produce
+ // empty fields rather than local variable shorthand...but,
+ // we've released a version where field names without values in
+ // `instrument` produce empty field values, so changing it now
+ // is a breaking change. agh.
+ let name = &self.name;
+ tokens.extend(quote!(#name = tracing::field::Empty))
+ } else {
+ self.kind.to_tokens(tokens);
+ self.name.to_tokens(tokens);
+ }
+ }
+}
+
+impl ToTokens for FieldKind {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ FieldKind::Debug => tokens.extend(quote! { ? }),
+ FieldKind::Display => tokens.extend(quote! { % }),
+ _ => {}
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+enum Level {
+ Str(LitStr),
+ Int(LitInt),
+ Path(Path),
+}
+
+impl Parse for Level {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<kw::level>()?;
+ let _ = input.parse::<Token![=]>()?;
+ let lookahead = input.lookahead1();
+ if lookahead.peek(LitStr) {
+ Ok(Self::Str(input.parse()?))
+ } else if lookahead.peek(LitInt) {
+ Ok(Self::Int(input.parse()?))
+ } else if lookahead.peek(Ident) {
+ Ok(Self::Path(input.parse()?))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
+
+mod kw {
+ syn::custom_keyword!(fields);
+ syn::custom_keyword!(skip);
+ syn::custom_keyword!(skip_all);
+ syn::custom_keyword!(level);
+ syn::custom_keyword!(target);
+ syn::custom_keyword!(parent);
+ syn::custom_keyword!(follows_from);
+ syn::custom_keyword!(name);
+ syn::custom_keyword!(err);
+ syn::custom_keyword!(ret);
+}
diff --git a/third_party/rust/tracing-attributes/src/expand.rs b/third_party/rust/tracing-attributes/src/expand.rs
new file mode 100644
index 0000000000..7005b4423e
--- /dev/null
+++ b/third_party/rust/tracing-attributes/src/expand.rs
@@ -0,0 +1,814 @@
+use std::iter;
+
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned, ToTokens};
+use syn::visit_mut::VisitMut;
+use syn::{
+ punctuated::Punctuated, spanned::Spanned, Block, Expr, ExprAsync, ExprCall, FieldPat, FnArg,
+ Ident, Item, ItemFn, Pat, PatIdent, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType,
+ Path, ReturnType, Signature, Stmt, Token, Type, TypePath,
+};
+
+use crate::{
+ attr::{Field, Fields, FormatMode, InstrumentArgs},
+ MaybeItemFn, MaybeItemFnRef,
+};
+
+/// Given an existing function, generate an instrumented version of that function
+pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
+ input: MaybeItemFnRef<'a, B>,
+ args: InstrumentArgs,
+ instrumented_function_name: &str,
+ self_type: Option<&TypePath>,
+) -> proc_macro2::TokenStream {
+ // these are needed ahead of time, as ItemFn contains the function body _and_
+ // isn't representable inside a quote!/quote_spanned! macro
+ // (Syn's ToTokens isn't implemented for ItemFn)
+ let MaybeItemFnRef {
+ outer_attrs,
+ inner_attrs,
+ vis,
+ sig,
+ block,
+ } = input;
+
+ let Signature {
+ output,
+ inputs: params,
+ unsafety,
+ asyncness,
+ constness,
+ abi,
+ ident,
+ generics:
+ syn::Generics {
+ params: gen_params,
+ where_clause,
+ ..
+ },
+ ..
+ } = sig;
+
+ let warnings = args.warnings();
+
+ let (return_type, return_span) = if let ReturnType::Type(_, return_type) = &output {
+ (erase_impl_trait(return_type), return_type.span())
+ } else {
+ // Point at function name if we don't have an explicit return type
+ (syn::parse_quote! { () }, ident.span())
+ };
+ // Install a fake return statement as the first thing in the function
+ // body, so that we eagerly infer that the return type is what we
+ // declared in the async fn signature.
+ // The `#[allow(..)]` is given because the return statement is
+ // unreachable, but does affect inference, so it needs to be written
+ // exactly that way for it to do its magic.
+ let fake_return_edge = quote_spanned! {return_span=>
+ #[allow(unreachable_code, clippy::diverging_sub_expression, clippy::let_unit_value)]
+ if false {
+ let __tracing_attr_fake_return: #return_type =
+ unreachable!("this is just for type inference, and is unreachable code");
+ return __tracing_attr_fake_return;
+ }
+ };
+ let block = quote! {
+ {
+ #fake_return_edge
+ #block
+ }
+ };
+
+ let body = gen_block(
+ &block,
+ params,
+ asyncness.is_some(),
+ args,
+ instrumented_function_name,
+ self_type,
+ );
+
+ quote!(
+ #(#outer_attrs) *
+ #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #output
+ #where_clause
+ {
+ #(#inner_attrs) *
+ #warnings
+ #body
+ }
+ )
+}
+
+/// Instrument a block
+fn gen_block<B: ToTokens>(
+ block: &B,
+ params: &Punctuated<FnArg, Token![,]>,
+ async_context: bool,
+ mut args: InstrumentArgs,
+ instrumented_function_name: &str,
+ self_type: Option<&TypePath>,
+) -> proc_macro2::TokenStream {
+ // generate the span's name
+ let span_name = args
+ // did the user override the span's name?
+ .name
+ .as_ref()
+ .map(|name| quote!(#name))
+ .unwrap_or_else(|| quote!(#instrumented_function_name));
+
+ let level = args.level();
+
+ let follows_from = args.follows_from.iter();
+ let follows_from = quote! {
+ #(for cause in #follows_from {
+ __tracing_attr_span.follows_from(cause);
+ })*
+ };
+
+ // generate this inside a closure, so we can return early on errors.
+ let span = (|| {
+ // Pull out the arguments-to-be-skipped first, so we can filter results
+ // below.
+ let param_names: Vec<(Ident, (Ident, RecordType))> = params
+ .clone()
+ .into_iter()
+ .flat_map(|param| match param {
+ FnArg::Typed(PatType { pat, ty, .. }) => {
+ param_names(*pat, RecordType::parse_from_ty(&*ty))
+ }
+ FnArg::Receiver(_) => Box::new(iter::once((
+ Ident::new("self", param.span()),
+ RecordType::Debug,
+ ))),
+ })
+ // Little dance with new (user-exposed) names and old (internal)
+ // names of identifiers. That way, we could do the following
+ // even though async_trait (<=0.1.43) rewrites "self" as "_self":
+ // ```
+ // #[async_trait]
+ // impl Foo for FooImpl {
+ // #[instrument(skip(self))]
+ // async fn foo(&self, v: usize) {}
+ // }
+ // ```
+ .map(|(x, record_type)| {
+ // if we are inside a function generated by async-trait <=0.1.43, we need to
+ // take care to rewrite "_self" as "self" for 'user convenience'
+ if self_type.is_some() && x == "_self" {
+ (Ident::new("self", x.span()), (x, record_type))
+ } else {
+ (x.clone(), (x, record_type))
+ }
+ })
+ .collect();
+
+ for skip in &args.skips {
+ if !param_names.iter().map(|(user, _)| user).any(|y| y == skip) {
+ return quote_spanned! {skip.span()=>
+ compile_error!("attempting to skip non-existent parameter")
+ };
+ }
+ }
+
+ let target = args.target();
+
+ let parent = args.parent.iter();
+
+ // filter out skipped fields
+ let quoted_fields: Vec<_> = param_names
+ .iter()
+ .filter(|(param, _)| {
+ if args.skip_all || args.skips.contains(param) {
+ return false;
+ }
+
+ // If any parameters have the same name as a custom field, skip
+ // and allow them to be formatted by the custom field.
+ if let Some(ref fields) = args.fields {
+ fields.0.iter().all(|Field { ref name, .. }| {
+ let first = name.first();
+ first != name.last() || !first.iter().any(|name| name == &param)
+ })
+ } else {
+ true
+ }
+ })
+ .map(|(user_name, (real_name, record_type))| match record_type {
+ RecordType::Value => quote!(#user_name = #real_name),
+ RecordType::Debug => quote!(#user_name = tracing::field::debug(&#real_name)),
+ })
+ .collect();
+
+ // replace every use of a variable with its original name
+ if let Some(Fields(ref mut fields)) = args.fields {
+ let mut replacer = IdentAndTypesRenamer {
+ idents: param_names.into_iter().map(|(a, (b, _))| (a, b)).collect(),
+ types: Vec::new(),
+ };
+
+ // when async-trait <=0.1.43 is in use, replace instances
+ // of the "Self" type inside the fields values
+ if let Some(self_type) = self_type {
+ replacer.types.push(("Self", self_type.clone()));
+ }
+
+ for e in fields.iter_mut().filter_map(|f| f.value.as_mut()) {
+ syn::visit_mut::visit_expr_mut(&mut replacer, e);
+ }
+ }
+
+ let custom_fields = &args.fields;
+
+ quote!(tracing::span!(
+ target: #target,
+ #(parent: #parent,)*
+ #level,
+ #span_name,
+ #(#quoted_fields,)*
+ #custom_fields
+
+ ))
+ })();
+
+ let target = args.target();
+
+ let err_event = match args.err_mode {
+ Some(FormatMode::Default) | Some(FormatMode::Display) => {
+ Some(quote!(tracing::error!(target: #target, error = %e)))
+ }
+ Some(FormatMode::Debug) => Some(quote!(tracing::error!(target: #target, error = ?e))),
+ _ => None,
+ };
+
+ let ret_event = match args.ret_mode {
+ Some(FormatMode::Display) => Some(quote!(
+ tracing::event!(target: #target, #level, return = %x)
+ )),
+ Some(FormatMode::Default) | Some(FormatMode::Debug) => Some(quote!(
+ tracing::event!(target: #target, #level, return = ?x)
+ )),
+ _ => None,
+ };
+
+ // Generate the instrumented function body.
+ // If the function is an `async fn`, this will wrap it in an async block,
+ // which is `instrument`ed using `tracing-futures`. Otherwise, this will
+ // enter the span and then perform the rest of the body.
+ // If `err` is in args, instrument any resulting `Err`s.
+ // If `ret` is in args, instrument any resulting `Ok`s when the function
+ // returns `Result`s, otherwise instrument any resulting values.
+ if async_context {
+ let mk_fut = match (err_event, ret_event) {
+ (Some(err_event), Some(ret_event)) => quote_spanned!(block.span()=>
+ async move {
+ match async move #block.await {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => {
+ #ret_event;
+ Ok(x)
+ },
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ }
+ ),
+ (Some(err_event), None) => quote_spanned!(block.span()=>
+ async move {
+ match async move #block.await {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => Ok(x),
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ }
+ ),
+ (None, Some(ret_event)) => quote_spanned!(block.span()=>
+ async move {
+ let x = async move #block.await;
+ #ret_event;
+ x
+ }
+ ),
+ (None, None) => quote_spanned!(block.span()=>
+ async move #block
+ ),
+ };
+
+ return quote!(
+ let __tracing_attr_span = #span;
+ let __tracing_instrument_future = #mk_fut;
+ if !__tracing_attr_span.is_disabled() {
+ #follows_from
+ tracing::Instrument::instrument(
+ __tracing_instrument_future,
+ __tracing_attr_span
+ )
+ .await
+ } else {
+ __tracing_instrument_future.await
+ }
+ );
+ }
+
+ let span = quote!(
+ // These variables are left uninitialized and initialized only
+ // if the tracing level is statically enabled at this point.
+ // While the tracing level is also checked at span creation
+ // time, that will still create a dummy span, and a dummy guard
+ // and drop the dummy guard later. By lazily initializing these
+ // variables, Rust will generate a drop flag for them and thus
+ // only drop the guard if it was created. This creates code that
+ // is very straightforward for LLVM to optimize out if the tracing
+ // level is statically disabled, while not causing any performance
+ // regression in case the level is enabled.
+ let __tracing_attr_span;
+ let __tracing_attr_guard;
+ if tracing::level_enabled!(#level) {
+ __tracing_attr_span = #span;
+ #follows_from
+ __tracing_attr_guard = __tracing_attr_span.enter();
+ }
+ );
+
+ match (err_event, ret_event) {
+ (Some(err_event), Some(ret_event)) => quote_spanned! {block.span()=>
+ #span
+ #[allow(clippy::redundant_closure_call)]
+ match (move || #block)() {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => {
+ #ret_event;
+ Ok(x)
+ },
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ },
+ (Some(err_event), None) => quote_spanned!(block.span()=>
+ #span
+ #[allow(clippy::redundant_closure_call)]
+ match (move || #block)() {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => Ok(x),
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ ),
+ (None, Some(ret_event)) => quote_spanned!(block.span()=>
+ #span
+ #[allow(clippy::redundant_closure_call)]
+ let x = (move || #block)();
+ #ret_event;
+ x
+ ),
+ (None, None) => quote_spanned!(block.span() =>
+ // Because `quote` produces a stream of tokens _without_ whitespace, the
+ // `if` and the block will appear directly next to each other. This
+ // generates a clippy lint about suspicious `if/else` formatting.
+ // Therefore, suppress the lint inside the generated code...
+ #[allow(clippy::suspicious_else_formatting)]
+ {
+ #span
+ // ...but turn the lint back on inside the function body.
+ #[warn(clippy::suspicious_else_formatting)]
+ #block
+ }
+ ),
+ }
+}
+
+/// Indicates whether a field should be recorded as `Value` or `Debug`.
+enum RecordType {
+ /// The field should be recorded using its `Value` implementation.
+ Value,
+ /// The field should be recorded using `tracing::field::debug()`.
+ Debug,
+}
+
+impl RecordType {
+ /// Array of primitive types which should be recorded as [RecordType::Value].
+ const TYPES_FOR_VALUE: &'static [&'static str] = &[
+ "bool",
+ "str",
+ "u8",
+ "i8",
+ "u16",
+ "i16",
+ "u32",
+ "i32",
+ "u64",
+ "i64",
+ "f32",
+ "f64",
+ "usize",
+ "isize",
+ "NonZeroU8",
+ "NonZeroI8",
+ "NonZeroU16",
+ "NonZeroI16",
+ "NonZeroU32",
+ "NonZeroI32",
+ "NonZeroU64",
+ "NonZeroI64",
+ "NonZeroUsize",
+ "NonZeroIsize",
+ "Wrapping",
+ ];
+
+ /// Parse `RecordType` from [Type] by looking up
+ /// the [RecordType::TYPES_FOR_VALUE] array.
+ fn parse_from_ty(ty: &Type) -> Self {
+ match ty {
+ Type::Path(TypePath { path, .. })
+ if path
+ .segments
+ .iter()
+ .last()
+ .map(|path_segment| {
+ let ident = path_segment.ident.to_string();
+ Self::TYPES_FOR_VALUE.iter().any(|&t| t == ident)
+ })
+ .unwrap_or(false) =>
+ {
+ RecordType::Value
+ }
+ Type::Reference(syn::TypeReference { elem, .. }) => RecordType::parse_from_ty(elem),
+ _ => RecordType::Debug,
+ }
+ }
+}
+
+fn param_names(pat: Pat, record_type: RecordType) -> Box<dyn Iterator<Item = (Ident, RecordType)>> {
+ match pat {
+ Pat::Ident(PatIdent { ident, .. }) => Box::new(iter::once((ident, record_type))),
+ Pat::Reference(PatReference { pat, .. }) => param_names(*pat, record_type),
+ // We can't get the concrete type of fields in the struct/tuple
+ // patterns by using `syn`. e.g. `fn foo(Foo { x, y }: Foo) {}`.
+ // Therefore, the struct/tuple patterns in the arguments will just
+ // always be recorded as `RecordType::Debug`.
+ Pat::Struct(PatStruct { fields, .. }) => Box::new(
+ fields
+ .into_iter()
+ .flat_map(|FieldPat { pat, .. }| param_names(*pat, RecordType::Debug)),
+ ),
+ Pat::Tuple(PatTuple { elems, .. }) => Box::new(
+ elems
+ .into_iter()
+ .flat_map(|p| param_names(p, RecordType::Debug)),
+ ),
+ Pat::TupleStruct(PatTupleStruct {
+ pat: PatTuple { elems, .. },
+ ..
+ }) => Box::new(
+ elems
+ .into_iter()
+ .flat_map(|p| param_names(p, RecordType::Debug)),
+ ),
+
+ // The above *should* cover all cases of irrefutable patterns,
+ // but we purposefully don't do any funny business here
+ // (such as panicking) because that would obscure rustc's
+ // much more informative error message.
+ _ => Box::new(iter::empty()),
+ }
+}
+
+/// The specific async code pattern that was detected
+enum AsyncKind<'a> {
+ /// Immediately-invoked async fn, as generated by `async-trait <= 0.1.43`:
+ /// `async fn foo<...>(...) {...}; Box::pin(foo<...>(...))`
+ Function(&'a ItemFn),
+ /// A function returning an async (move) block, optionally `Box::pin`-ed,
+ /// as generated by `async-trait >= 0.1.44`:
+ /// `Box::pin(async move { ... })`
+ Async {
+ async_expr: &'a ExprAsync,
+ pinned_box: bool,
+ },
+}
+
+pub(crate) struct AsyncInfo<'block> {
+ // statement that must be patched
+ source_stmt: &'block Stmt,
+ kind: AsyncKind<'block>,
+ self_type: Option<TypePath>,
+ input: &'block ItemFn,
+}
+
+impl<'block> AsyncInfo<'block> {
+ /// Get the AST of the inner function we need to hook, if it looks like a
+ /// manual future implementation.
+ ///
+ /// When we are given a function that returns a (pinned) future containing the
+ /// user logic, it is that (pinned) future that needs to be instrumented.
+ /// Were we to instrument its parent, we would only collect information
+ /// regarding the allocation of that future, and not its own span of execution.
+ ///
+ /// We inspect the block of the function to find if it matches any of the
+ /// following patterns:
+ ///
+ /// - Immediately-invoked async fn, as generated by `async-trait <= 0.1.43`:
+ /// `async fn foo<...>(...) {...}; Box::pin(foo<...>(...))`
+ ///
+ /// - A function returning an async (move) block, optionally `Box::pin`-ed,
+ /// as generated by `async-trait >= 0.1.44`:
+ /// `Box::pin(async move { ... })`
+ ///
+ /// We the return the statement that must be instrumented, along with some
+ /// other information.
+ /// 'gen_body' will then be able to use that information to instrument the
+ /// proper function/future.
+ ///
+ /// (this follows the approach suggested in
+ /// https://github.com/dtolnay/async-trait/issues/45#issuecomment-571245673)
+ pub(crate) fn from_fn(input: &'block ItemFn) -> Option<Self> {
+ // are we in an async context? If yes, this isn't a manual async-like pattern
+ if input.sig.asyncness.is_some() {
+ return None;
+ }
+
+ let block = &input.block;
+
+ // list of async functions declared inside the block
+ let inside_funs = block.stmts.iter().filter_map(|stmt| {
+ if let Stmt::Item(Item::Fn(fun)) = &stmt {
+ // If the function is async, this is a candidate
+ if fun.sig.asyncness.is_some() {
+ return Some((stmt, fun));
+ }
+ }
+ None
+ });
+
+ // last expression of the block: it determines the return value of the
+ // block, this is quite likely a `Box::pin` statement or an async block
+ let (last_expr_stmt, last_expr) = block.stmts.iter().rev().find_map(|stmt| {
+ if let Stmt::Expr(expr) = stmt {
+ Some((stmt, expr))
+ } else {
+ None
+ }
+ })?;
+
+ // is the last expression an async block?
+ if let Expr::Async(async_expr) = last_expr {
+ return Some(AsyncInfo {
+ source_stmt: last_expr_stmt,
+ kind: AsyncKind::Async {
+ async_expr,
+ pinned_box: false,
+ },
+ self_type: None,
+ input,
+ });
+ }
+
+ // is the last expression a function call?
+ let (outside_func, outside_args) = match last_expr {
+ Expr::Call(ExprCall { func, args, .. }) => (func, args),
+ _ => return None,
+ };
+
+ // is it a call to `Box::pin()`?
+ let path = match outside_func.as_ref() {
+ Expr::Path(path) => &path.path,
+ _ => return None,
+ };
+ if !path_to_string(path).ends_with("Box::pin") {
+ return None;
+ }
+
+ // Does the call take an argument? If it doesn't,
+ // it's not gonna compile anyway, but that's no reason
+ // to (try to) perform an out of bounds access
+ if outside_args.is_empty() {
+ return None;
+ }
+
+ // Is the argument to Box::pin an async block that
+ // captures its arguments?
+ if let Expr::Async(async_expr) = &outside_args[0] {
+ return Some(AsyncInfo {
+ source_stmt: last_expr_stmt,
+ kind: AsyncKind::Async {
+ async_expr,
+ pinned_box: true,
+ },
+ self_type: None,
+ input,
+ });
+ }
+
+ // Is the argument to Box::pin a function call itself?
+ let func = match &outside_args[0] {
+ Expr::Call(ExprCall { func, .. }) => func,
+ _ => return None,
+ };
+
+ // "stringify" the path of the function called
+ let func_name = match **func {
+ Expr::Path(ref func_path) => path_to_string(&func_path.path),
+ _ => return None,
+ };
+
+ // Was that function defined inside of the current block?
+ // If so, retrieve the statement where it was declared and the function itself
+ let (stmt_func_declaration, func) = inside_funs
+ .into_iter()
+ .find(|(_, fun)| fun.sig.ident == func_name)?;
+
+ // If "_self" is present as an argument, we store its type to be able to rewrite "Self" (the
+ // parameter type) with the type of "_self"
+ let mut self_type = None;
+ for arg in &func.sig.inputs {
+ if let FnArg::Typed(ty) = arg {
+ if let Pat::Ident(PatIdent { ref ident, .. }) = *ty.pat {
+ if ident == "_self" {
+ let mut ty = *ty.ty.clone();
+ // extract the inner type if the argument is "&self" or "&mut self"
+ if let Type::Reference(syn::TypeReference { elem, .. }) = ty {
+ ty = *elem;
+ }
+
+ if let Type::Path(tp) = ty {
+ self_type = Some(tp);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ Some(AsyncInfo {
+ source_stmt: stmt_func_declaration,
+ kind: AsyncKind::Function(func),
+ self_type,
+ input,
+ })
+ }
+
+ pub(crate) fn gen_async(
+ self,
+ args: InstrumentArgs,
+ instrumented_function_name: &str,
+ ) -> Result<proc_macro::TokenStream, syn::Error> {
+ // let's rewrite some statements!
+ let mut out_stmts: Vec<TokenStream> = self
+ .input
+ .block
+ .stmts
+ .iter()
+ .map(|stmt| stmt.to_token_stream())
+ .collect();
+
+ if let Some((iter, _stmt)) = self
+ .input
+ .block
+ .stmts
+ .iter()
+ .enumerate()
+ .find(|(_iter, stmt)| *stmt == self.source_stmt)
+ {
+ // instrument the future by rewriting the corresponding statement
+ out_stmts[iter] = match self.kind {
+ // `Box::pin(immediately_invoked_async_fn())`
+ AsyncKind::Function(fun) => {
+ let fun = MaybeItemFn::from(fun.clone());
+ gen_function(
+ fun.as_ref(),
+ args,
+ instrumented_function_name,
+ self.self_type.as_ref(),
+ )
+ }
+ // `async move { ... }`, optionally pinned
+ AsyncKind::Async {
+ async_expr,
+ pinned_box,
+ } => {
+ let instrumented_block = gen_block(
+ &async_expr.block,
+ &self.input.sig.inputs,
+ true,
+ args,
+ instrumented_function_name,
+ None,
+ );
+ let async_attrs = &async_expr.attrs;
+ if pinned_box {
+ quote! {
+ Box::pin(#(#async_attrs) * async move { #instrumented_block })
+ }
+ } else {
+ quote! {
+ #(#async_attrs) * async move { #instrumented_block }
+ }
+ }
+ }
+ };
+ }
+
+ let vis = &self.input.vis;
+ let sig = &self.input.sig;
+ let attrs = &self.input.attrs;
+ Ok(quote!(
+ #(#attrs) *
+ #vis #sig {
+ #(#out_stmts) *
+ }
+ )
+ .into())
+ }
+}
+
+// Return a path as a String
+fn path_to_string(path: &Path) -> String {
+ use std::fmt::Write;
+ // some heuristic to prevent too many allocations
+ let mut res = String::with_capacity(path.segments.len() * 5);
+ for i in 0..path.segments.len() {
+ write!(&mut res, "{}", path.segments[i].ident)
+ .expect("writing to a String should never fail");
+ if i < path.segments.len() - 1 {
+ res.push_str("::");
+ }
+ }
+ res
+}
+
+/// A visitor struct to replace idents and types in some piece
+/// of code (e.g. the "self" and "Self" tokens in user-supplied
+/// fields expressions when the function is generated by an old
+/// version of async-trait).
+struct IdentAndTypesRenamer<'a> {
+ types: Vec<(&'a str, TypePath)>,
+ idents: Vec<(Ident, Ident)>,
+}
+
+impl<'a> VisitMut for IdentAndTypesRenamer<'a> {
+ // we deliberately compare strings because we want to ignore the spans
+ // If we apply clippy's lint, the behavior changes
+ #[allow(clippy::cmp_owned)]
+ fn visit_ident_mut(&mut self, id: &mut Ident) {
+ for (old_ident, new_ident) in &self.idents {
+ if id.to_string() == old_ident.to_string() {
+ *id = new_ident.clone();
+ }
+ }
+ }
+
+ fn visit_type_mut(&mut self, ty: &mut Type) {
+ for (type_name, new_type) in &self.types {
+ if let Type::Path(TypePath { path, .. }) = ty {
+ if path_to_string(path) == *type_name {
+ *ty = Type::Path(new_type.clone());
+ }
+ }
+ }
+ }
+}
+
+// A visitor struct that replace an async block by its patched version
+struct AsyncTraitBlockReplacer<'a> {
+ block: &'a Block,
+ patched_block: Block,
+}
+
+impl<'a> VisitMut for AsyncTraitBlockReplacer<'a> {
+ fn visit_block_mut(&mut self, i: &mut Block) {
+ if i == self.block {
+ *i = self.patched_block.clone();
+ }
+ }
+}
+
+// Replaces any `impl Trait` with `_` so it can be used as the type in
+// a `let` statement's LHS.
+struct ImplTraitEraser;
+
+impl VisitMut for ImplTraitEraser {
+ fn visit_type_mut(&mut self, t: &mut Type) {
+ if let Type::ImplTrait(..) = t {
+ *t = syn::TypeInfer {
+ underscore_token: Token![_](t.span()),
+ }
+ .into();
+ } else {
+ syn::visit_mut::visit_type_mut(self, t);
+ }
+ }
+}
+
+fn erase_impl_trait(ty: &Type) -> Type {
+ let mut ty = ty.clone();
+ ImplTraitEraser.visit_type_mut(&mut ty);
+ ty
+}
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,
+}