Skip to content

Commit c9db496

Browse files
committed
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 ca3a51c commit c9db496

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
@@ -711,12 +711,9 @@ fn gen_block(
711711
// enter the span and then perform the rest of the body.
712712
// If `err` is in args, instrument any resulting `Err`s.
713713
if async_context {
714-
if err {
714+
let mk_fut = if err {
715715
quote_spanned!(block.span()=>
716-
let __tracing_attr_span = #span;
717-
// See comment on the default case at the end of this function
718-
// for why we do this a bit roundabout.
719-
let fut = async move {
716+
async move {
720717
match async move { #block }.await {
721718
#[allow(clippy::unit_arg)]
722719
Ok(x) => Ok(x),
@@ -725,46 +722,52 @@ fn gen_block(
725722
Err(e)
726723
}
727724
}
728-
};
729-
if tracing::level_enabled!(#level) {
730-
tracing::Instrument::instrument(
731-
fut,
732-
__tracing_attr_span
733-
)
734-
.await
735-
} else {
736-
fut.await
737725
}
738726
)
739727
} else {
740728
quote_spanned!(block.span()=>
741-
let __tracing_attr_span = #span;
742-
// See comment on the default case at the end of this function
743-
// for why we do this a bit roundabout.
744-
let fut = async move { #block };
745-
if tracing::level_enabled!(#level) {
746-
tracing::Instrument::instrument(
747-
fut,
748-
__tracing_attr_span
749-
)
750-
.await
751-
} else {
752-
fut.await
753-
}
729+
async move { #block }
754730
)
755-
}
756-
} else if err {
757-
quote_spanned!(block.span()=>
758-
// See comment on the default case at the end of this function
759-
// for why we do this a bit roundabout.
760-
let __tracing_attr_span;
761-
let __tracing_attr_guard;
731+
};
732+
733+
return quote_spanned!(block.span()=>
762734
if tracing::level_enabled!(#level) {
763-
__tracing_attr_span = #span;
764-
__tracing_attr_guard = __tracing_attr_span.enter();
735+
let __tracing_attr_span = #span;
736+
tracing::Instrument::instrument(
737+
#mk_fut,
738+
__tracing_attr_span
739+
)
740+
.await
741+
} else {
742+
#mk_fut.await
765743
}
766-
// pacify clippy::suspicious_else_formatting
767-
let _ = ();
744+
);
745+
}
746+
747+
let span = quote_spanned!(block.span()=>
748+
// These variables are left uninitialized and initialized only
749+
// if the tracing level is statically enabled at this point.
750+
// While the tracing level is also checked at span creation
751+
// time, that will still create a dummy span, and a dummy guard
752+
// and drop the dummy guard later. By lazily initializing these
753+
// variables, Rust will generate a drop flag for them and thus
754+
// only drop the guard if it was created. This creates code that
755+
// is very straightforward for LLVM to optimize out if the tracing
756+
// level is statically disabled, while not causing any performance
757+
// regression in case the level is enabled.
758+
let __tracing_attr_span;
759+
let __tracing_attr_guard;
760+
if tracing::level_enabled!(#level) {
761+
__tracing_attr_span = #span;
762+
__tracing_attr_guard = __tracing_attr_span.enter();
763+
}
764+
// pacify clippy::suspicious_else_formatting
765+
let _ = ();
766+
);
767+
768+
if err {
769+
return quote_spanned!(block.span()=>
770+
#span
768771
#[allow(clippy::redundant_closure_call)]
769772
match (move || #block)() {
770773
#[allow(clippy::unit_arg)]
@@ -774,30 +777,13 @@ fn gen_block(
774777
Err(e)
775778
}
776779
}
777-
)
778-
} else {
779-
quote_spanned!(block.span()=>
780-
// These variables are left uninitialized and initialized only
781-
// if the tracing level is statically enabled at this point.
782-
// While the tracing level is also checked at span creation
783-
// time, that will still create a dummy span, and a dummy guard
784-
// and drop the dummy guard later. By lazily initializing these
785-
// variables, Rust will generate a drop flag for them and thus
786-
// only drop the guard if it was created. This creates code that
787-
// is very straightforward for LLVM to optimize out if the tracing
788-
// level is statically disabled, while not causing any performance
789-
// regression in case the level is enabled.
790-
let __tracing_attr_span;
791-
let __tracing_attr_guard;
792-
if tracing::level_enabled!(#level) {
793-
__tracing_attr_span = #span;
794-
__tracing_attr_guard = __tracing_attr_span.enter();
795-
}
796-
// pacify clippy::suspicious_else_formatting
797-
let _ = ();
798-
#block
799-
)
780+
);
800781
}
782+
783+
quote_spanned!(block.span()=>
784+
#span
785+
#block
786+
)
801787
}
802788

803789
#[derive(Default, Debug)]

0 commit comments

Comments
 (0)