Skip to content

Commit 0fa74b9

Browse files
authored
attributes: skip async spans if level disabled (#1607)
## Motivation In #1600, the `instrument` code generation was changed to avoid ever constructing a `Span` struct if the level is explicitly disabled. However, for `async` functions, `#[instrument]` will currently still create the span, but simply skips constructing an `Instrument` future if the level is disabled. ## Solution This branch changes the `#[instrument]` code generation for async blocks to totally skip constructing the span if the level is disabled. I also simplfied the code generation a bit by combining the shared code between the `err` and non-`err` cases, reducing code duplication a bit. Signed-off-by: Eliza Weisman <[email protected]>
1 parent a320f01 commit 0fa74b9

File tree

1 file changed

+47
-61
lines changed

1 file changed

+47
-61
lines changed

tracing-attributes/src/lib.rs

Lines changed: 47 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -513,12 +513,9 @@ fn gen_block(
513513
// enter the span and then perform the rest of the body.
514514
// If `err` is in args, instrument any resulting `Err`s.
515515
if async_context {
516-
if err {
516+
let mk_fut = if err {
517517
quote_spanned!(block.span()=>
518-
let __tracing_attr_span = #span;
519-
// See comment on the default case at the end of this function
520-
// for why we do this a bit roundabout.
521-
let fut = async move {
518+
async move {
522519
match async move { #block }.await {
523520
#[allow(clippy::unit_arg)]
524521
Ok(x) => Ok(x),
@@ -527,46 +524,52 @@ fn gen_block(
527524
Err(e)
528525
}
529526
}
530-
};
531-
if tracing::level_enabled!(#level) {
532-
tracing::Instrument::instrument(
533-
fut,
534-
__tracing_attr_span
535-
)
536-
.await
537-
} else {
538-
fut.await
539527
}
540528
)
541529
} else {
542530
quote_spanned!(block.span()=>
543-
let __tracing_attr_span = #span;
544-
// See comment on the default case at the end of this function
545-
// for why we do this a bit roundabout.
546-
let fut = async move { #block };
547-
if tracing::level_enabled!(#level) {
548-
tracing::Instrument::instrument(
549-
fut,
550-
__tracing_attr_span
551-
)
552-
.await
553-
} else {
554-
fut.await
555-
}
531+
async move { #block }
556532
)
557-
}
558-
} else if err {
559-
quote_spanned!(block.span()=>
560-
// See comment on the default case at the end of this function
561-
// for why we do this a bit roundabout.
562-
let __tracing_attr_span;
563-
let __tracing_attr_guard;
533+
};
534+
535+
return quote_spanned!(block.span()=>
564536
if tracing::level_enabled!(#level) {
565-
__tracing_attr_span = #span;
566-
__tracing_attr_guard = __tracing_attr_span.enter();
537+
let __tracing_attr_span = #span;
538+
tracing::Instrument::instrument(
539+
#mk_fut,
540+
__tracing_attr_span
541+
)
542+
.await
543+
} else {
544+
#mk_fut.await
567545
}
568-
// pacify clippy::suspicious_else_formatting
569-
let _ = ();
546+
);
547+
}
548+
549+
let span = quote_spanned!(block.span()=>
550+
// These variables are left uninitialized and initialized only
551+
// if the tracing level is statically enabled at this point.
552+
// While the tracing level is also checked at span creation
553+
// time, that will still create a dummy span, and a dummy guard
554+
// and drop the dummy guard later. By lazily initializing these
555+
// variables, Rust will generate a drop flag for them and thus
556+
// only drop the guard if it was created. This creates code that
557+
// is very straightforward for LLVM to optimize out if the tracing
558+
// level is statically disabled, while not causing any performance
559+
// regression in case the level is enabled.
560+
let __tracing_attr_span;
561+
let __tracing_attr_guard;
562+
if tracing::level_enabled!(#level) {
563+
__tracing_attr_span = #span;
564+
__tracing_attr_guard = __tracing_attr_span.enter();
565+
}
566+
// pacify clippy::suspicious_else_formatting
567+
let _ = ();
568+
);
569+
570+
if err {
571+
return quote_spanned!(block.span()=>
572+
#span
570573
#[allow(clippy::redundant_closure_call)]
571574
match (move || #block)() {
572575
#[allow(clippy::unit_arg)]
@@ -576,30 +579,13 @@ fn gen_block(
576579
Err(e)
577580
}
578581
}
579-
)
580-
} else {
581-
quote_spanned!(block.span()=>
582-
// These variables are left uninitialized and initialized only
583-
// if the tracing level is statically enabled at this point.
584-
// While the tracing level is also checked at span creation
585-
// time, that will still create a dummy span, and a dummy guard
586-
// and drop the dummy guard later. By lazily initializing these
587-
// variables, Rust will generate a drop flag for them and thus
588-
// only drop the guard if it was created. This creates code that
589-
// is very straightforward for LLVM to optimize out if the tracing
590-
// level is statically disabled, while not causing any performance
591-
// regression in case the level is enabled.
592-
let __tracing_attr_span;
593-
let __tracing_attr_guard;
594-
if tracing::level_enabled!(#level) {
595-
__tracing_attr_span = #span;
596-
__tracing_attr_guard = __tracing_attr_span.enter();
597-
}
598-
// pacify clippy::suspicious_else_formatting
599-
let _ = ();
600-
#block
601-
)
582+
);
602583
}
584+
585+
quote_spanned!(block.span()=>
586+
#span
587+
#block
588+
)
603589
}
604590

605591
#[derive(Default, Debug)]

0 commit comments

Comments
 (0)