Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

attributes: add support for custom levels for ret and err (#2330) #2335

Merged
merged 5 commits into from
Oct 10, 2022

Conversation

nitnelave
Copy link
Contributor

Fixes #2330

The change is fairly straightforward, just adding support for customizable levels for ret and err in a fully backward-compatible way.

I made Level pub(crate) to be able to expose level_to_tokens, there may be a better way of doing it but it seemed simple enough and anyway it doesn't escape the crate.

@nitnelave nitnelave requested review from hawkw, davidbarsky and a team as code owners October 4, 2022 10:28
Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this! This branch looks like a good start. I commented on some code style suggestions, but some of them might require a larger refactoring of this code, so if you'd prefer not do make all of those changes as part of this PR, that's fine. I would like to see the test changes I requested, though.

Thanks!

@@ -6,60 +6,30 @@ use quote::{quote, quote_spanned, ToTokens};
use syn::ext::IdentExt as _;
use syn::parse::{Parse, ParseStream};

#[derive(Clone, Default, Debug)]
pub(crate) struct DisplayArgs {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is kind of a nitpick, but I feel like DisplayArgs isn't really the clearest name for this --- it sounds like it's specifically referring to fmt::Display, but the struct is also used when the event is recorded using Debug. How about calling it EventArgs, instead, since it configures an event emitted for a return value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I didn't have a great idea of how to name it. EventArgs sounds better, thanks.

Comment on lines 165 to 184
} else {
if result.mode != FormatMode::default() {
return Err(content.error("expected only a single format argument"));
}
let maybe_mode: Option<Ident> = content.parse()?;
if let Some(ident) = maybe_mode {
match ident.to_string().as_str() {
"Debug" => result.mode = FormatMode::Debug,
"Display" => result.mode = FormatMode::Display,
_ => {
return Err(syn::Error::new(
ident.span(),
"unknown error mode, must be Debug or Display",
))
}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style nit: i think we can maybe simplify the nested if chain here a little bit if we wrote something like this:

Suggested change
} else {
if result.mode != FormatMode::default() {
return Err(content.error("expected only a single format argument"));
}
let maybe_mode: Option<Ident> = content.parse()?;
if let Some(ident) = maybe_mode {
match ident.to_string().as_str() {
"Debug" => result.mode = FormatMode::Debug,
"Display" => result.mode = FormatMode::Display,
_ => {
return Err(syn::Error::new(
ident.span(),
"unknown error mode, must be Debug or Display",
))
}
}
}
}
} else if result.mode != FormatMode::default() {
return Err(content.error("expected only a single format argument"));
} else if let Some(maybe_mode) = content.parse::<Option<Ident>>?() {
match maybe_mode.to_string().as_str() {
"Debug" => result.mode = FormatMode::Debug,
"Display" => result.mode = FormatMode::Display,
_ => return Err(syn::Error::new(
ident.span(),
"unknown error mode, must be Debug or Display",
)),
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's less nested, thanks.

tracing-attributes/tests/err.rs Show resolved Hide resolved

#[test]
fn test_warn_info() {
let span = span::mock().named("ret_warn_info");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's assert that the span itself is at the WARN level here:

Suggested change
let span = span::mock().named("ret_warn_info");
let span = span::mock().named("ret_warn_info").at_level(Level::WARN);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


#[test]
fn test_dbg_warn() {
let span = span::mock().named("ret_dbg_warn");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and let's assert that the span is at the WARN level here, as well

Suggested change
let span = span::mock().named("ret_dbg_warn");
let span = span::mock().named("ret_dbg_warn").at_level(Level::WARN)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also done.

@@ -386,6 +383,50 @@ impl Parse for Level {
}
}

pub(crate) fn level_to_tokens(level: &Option<Level>, default_error: bool) -> impl ToTokens {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a big fan of how we pass in an Option<Level> and a bool that indicates whether the default should be ERROR or not...this feels a little awkward. What if, instead, we changed this so that it's a method on &Level, and changed the code that currently calls this with an &Option<Level> so that it uses Option::unwrap_or with the default value and just calls level.to_tokens() afterwards? This might require a change to how the Level type is represented internally, but it seems like it might be a bit neater...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaned up. Now level() returns a Level since it implements ToTokens. For EventArgs, we can pass the default explicitly.

Comment on lines 394 to 430
match 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 => if default_error {
quote!(tracing::Level::ERROR)
} else {
quote!(tracing::Level::INFO)
},
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isn't a big deal, especially since i know this code was already here, but i wonder if it would be a bit nicer to change this code so that determining which tracing::Level a string or integer value corresponds to occurred in a Parse implementation for Level, rather than in ToTokens?

That way, the error we emit if we got an unexpected level value could happen at parsing-time, when we have access to the span that the level tokens correspond to, rather than quote!ing a compile_error! in the ToTokens impl. That way, I believe the invalid level value would be underlined in the compiler error, which is a bit nicer especially now that we have multiple places where a level might occur in the #[instrument] arguments.

It's fine if you'd rather not address this suggestion right now, since this isn't code that's added in your PR, but it might be worth doing if you're interested. Otherwise, I'm happy to take care of it later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I moved the errors to the Parse implementation, and implemented ToTokens for Level, which leads to a much cleaner interface.

@nitnelave nitnelave force-pushed the master branch 2 times, most recently from e547d24 to 75b6c30 Compare October 9, 2022 10:49
@nitnelave
Copy link
Contributor Author

Rebased, cleaned up, ready for review.

@@ -116,7 +116,8 @@ fn gen_block<B: ToTokens>(
.map(|name| quote!(#name))
.unwrap_or_else(|| quote!(#instrumented_function_name));

let level = args.level();
let args_level = args.level();
let level = args_level.clone();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need a second copy because one gets moved out.

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, the code change looks great now, thanks for taking the time to address my suggestions! I commented on a couple minor style tweaks you may want to make, but none of them are important.

One last thing before we merge this, though: let's make sure the documentation is updated to show how to change the level of an err/ret event. The documentation for ret states that it will always have the same level as the span, here:

/// The return value event will have the same level as the span generated by `#[instrument]`.
/// By default, this will be `TRACE`, but if the level is overridden, the event will be at the same
/// level.

so let's make sure to explain how to override it. Similarly, the err docs here should also probably be updated:
/// 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)`:

tracing-attributes/src/attr.rs Outdated Show resolved Hide resolved
tracing-attributes/src/attr.rs Outdated Show resolved Hide resolved
tracing-attributes/src/attr.rs Outdated Show resolved Hide resolved
tracing-attributes/src/attr.rs Outdated Show resolved Hide resolved
tracing-attributes/src/attr.rs Show resolved Hide resolved
@hawkw
Copy link
Member

hawkw commented Oct 9, 2022

CI failure is unrelated to this change, PR #2344 should fix that.

@nitnelave
Copy link
Contributor Author

nitnelave commented Oct 10, 2022

One last thing before we merge this, though: let's make sure the documentation is updated

Yeah, actually I thought of it today and it's been bothering me all day :D What do you think of the new changes?

I also rebased on top of the new master, so the CI should work now.

Note: If you want, I can squash my commits into one for a cleaner PR. I keep them separate for now for easier review (you see what changed since your last review).

@hawkw
Copy link
Member

hawkw commented Oct 10, 2022

One last thing before we merge this, though: let's make sure the documentation is updated

Yeah, actually I thought of it today and it's been bothering me all day :D What do you think of the new changes?

Thanks, I'm about to take a look :)

Note: If you want, I can squash my commits into one for a cleaner PR. I keep them separate for now for easier review (you see what changed since your last review).

We typically merge PRs by squashing anyway, so you don't have to worry about squashing your commits pre-merge. It's generally much nicer for reviewers to see all the changes as separate commits. Thanks for asking!

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good to me! i left a couple very minor suggestions on the documentation changes.

tracing-attributes/src/lib.rs Outdated Show resolved Hide resolved
tracing-attributes/src/lib.rs Outdated Show resolved Hide resolved
nitnelave and others added 2 commits October 10, 2022 22:37
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
@nitnelave
Copy link
Contributor Author

Committed your suggestions, they were good.

@hawkw
Copy link
Member

hawkw commented Oct 10, 2022

This looks great! I'm going to merge it now.

Thanks again for working on this!

@hawkw hawkw merged commit 196e83e into tokio-rs:master Oct 10, 2022
hawkw pushed a commit that referenced this pull request Apr 21, 2023
This branch adds the ability to override the level of the events
generated by the `ret` and `err` arguments to `#[instrument]`. An
overridden level can be specified with:

```rust

```
```rust

```
and so on.

This syntax is fully backwards compatible with existing uses of the
attribute.

In addition, some refactoring was done to how levels are parsed and how
the tokens for a specified level is generated.

Fixes #2330
; Conflicts:
;	tracing-attributes/src/lib.rs
hawkw pushed a commit that referenced this pull request Apr 21, 2023
This branch adds the ability to override the level of the events
generated by the `ret` and `err` arguments to `#[instrument]`. An
overridden level can be specified with:

```rust

```
```rust

```
and so on.

This syntax is fully backwards compatible with existing uses of the
attribute.

In addition, some refactoring was done to how levels are parsed and how
the tokens for a specified level is generated.

Fixes #2330
; Conflicts:
;	tracing-attributes/src/lib.rs
hawkw added a commit that referenced this pull request Apr 24, 2023
# 0.1.24 (April 24th, 2023)

This release of `tracing-attributes` adds support for passing an
optional `level` to the `err` and `ret` arguments to `#[instrument]`,
allowing the level of the generated return-value event to be overridden.
For example,

```rust
#[instrument(err(level = "info"))]
fn my_great_function() -> Result<(), &'static str> {
    // ...
}
```

will emit an `INFO`-level event if the function returns an `Err`.

In addition, this release updates the [`syn`] dependency to v2.x.x.

### Added

- `level` argument to `err` and `ret` to override the level of the
  generated return value event (#2335)
- Improved compiler error message when `#[instrument]` is added to a
  `const fn` (#2418)

### Changed

- Updated `syn` dependency to 2.0 (#2516)

### Fixed

- Fix `clippy::unreachable` warnings in `#[instrument]`-generated code
  (#2356)
- Removed unused "visit" feature flag from `syn` dependency (#2530)

### Documented

- Documented default level for `err` (#2433)
- Improved documentation for levels in `#[instrument]` (#2350)

Thanks to @nitnelave, @jsgf, @Abhicodes-crypto, @LukeMathWalker,
@andrewpollack, @quad, @klensy, @davidpdrsn, and @dbidwell94 for
contributign to this release!

[`syn`]: https://crates.io/crates/syn
hawkw added a commit that referenced this pull request Apr 24, 2023
# 0.1.24 (April 24th, 2023)

This release of `tracing-attributes` adds support for passing an
optional `level` to the `err` and `ret` arguments to `#[instrument]`,
allowing the level of the generated return-value event to be overridden.
For example,

```rust
#[instrument(err(level = "info"))]
fn my_great_function() -> Result<(), &'static str> {
    // ...
}
```

will emit an `INFO`-level event if the function returns an `Err`.

In addition, this release updates the [`syn`] dependency to v2.x.x.

### Added

- `level` argument to `err` and `ret` to override the level of the
  generated return value event (#2335)
- Improved compiler error message when `#[instrument]` is added to a
  `const fn` (#2418)

### Changed

- Updated `syn` dependency to 2.0 (#2516)

### Fixed

- Fix `clippy::unreachable` warnings in `#[instrument]`-generated code
  (#2356)
- Removed unused "visit" feature flag from `syn` dependency (#2530)

### Documented

- Documented default level for `err` (#2433)
- Improved documentation for levels in `#[instrument]` (#2350)

Thanks to @nitnelave, @jsgf, @Abhicodes-crypto, @LukeMathWalker,
@andrewpollack, @quad, @klensy, @davidpdrsn, and @dbidwell94 for
contributign to this release!

[`syn`]: https://crates.io/crates/syn
hawkw added a commit that referenced this pull request Apr 25, 2023
# 0.1.38 (April 25th, 2023)

This `tracing` release changes the `Drop` implementation for
`Instrumented` `Future`s so that the attached `Span` is entered when
dropping the `Future`. This means that events emitted by the `Future`'s
`Drop` implementation will now be recorded within its `Span`. It also
adds `#[inline]` hints to methods called in the `event!` macro's
expansion, for an improvement in both binary size and performance.

Additionally, this release updates the `tracing-attributes` dependency
to [v0.1.24][attrs-0.1.24], which updates the [`syn`] dependency to
v2.x.x. `tracing-attributes` v0.1.24 also includes improvements to the
`#[instrument]` macro; see [the `tracing-attributes` 0.1.24 release
notes][attrs-0.1.24] for details.

### Added

- `Instrumented` futures will now enter the attached `Span` in their
  `Drop` implementation, allowing events emitted when dropping the
  future to occur within the span (#2562)
- `#[inline]` attributes for methods called by the `event!` macros,
  making generated code smaller (#2555)
- **attributes**: `level` argument to `#[instrument(err)]` and
  `#[instrument(ret)]` to override the level of the generated return
  value event (#2335)
- **attributes**: Improved compiler error message when `#[instrument]`
  is added to a `const fn` (#2418)

### Changed

- `tracing-attributes`: updated to [0.1.24][attrs-0.1.24]
- Removed unneeded `cfg-if` dependency (#2553)
- **attributes**: Updated [`syn`] dependency to 2.0 (#2516)

### Fixed

- **attributes**: Fix `clippy::unreachable` warnings in
  `#[instrument]`-generated code (#2356)
- **attributes**: Removed unused "visit" feature flag from `syn`
  dependency (#2530)

### Documented

- **attributes**: Documented default level for `#[instrument(err)]`
  (#2433)
- **attributes**: Improved documentation for levels in `#[instrument]`
  (#2350)

Thanks to @nitnelave, @jsgf, @Abhicodes-crypto, @LukeMathWalker,
@andrewpollack, @quad, @klensy, @davidpdrsn, @dbidwell94, @ldm0,
@NobodyXu, @ilsv, and @daxpedda for contributing to this release!

[`syn`]: https://crates.io/crates/syn
[attrs-0.1.24]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.24
hawkw added a commit that referenced this pull request Apr 25, 2023
# 0.1.38 (April 25th, 2023)

This `tracing` release changes the `Drop` implementation for
`Instrumented` `Future`s so that the attached `Span` is entered when
dropping the `Future`. This means that events emitted by the `Future`'s
`Drop` implementation will now be recorded within its `Span`. It also
adds `#[inline]` hints to methods called in the `event!` macro's
expansion, for an improvement in both binary size and performance.

Additionally, this release updates the `tracing-attributes` dependency
to [v0.1.24][attrs-0.1.24], which updates the [`syn`] dependency to
v2.x.x. `tracing-attributes` v0.1.24 also includes improvements to the
`#[instrument]` macro; see [the `tracing-attributes` 0.1.24 release
notes][attrs-0.1.24] for details.

### Added

- `Instrumented` futures will now enter the attached `Span` in their
  `Drop` implementation, allowing events emitted when dropping the
  future to occur within the span (#2562)
- `#[inline]` attributes for methods called by the `event!` macros,
  making generated code smaller (#2555)
- **attributes**: `level` argument to `#[instrument(err)]` and
  `#[instrument(ret)]` to override the level of the generated return
  value event (#2335)
- **attributes**: Improved compiler error message when `#[instrument]`
  is added to a `const fn` (#2418)

### Changed

- `tracing-attributes`: updated to [0.1.24][attrs-0.1.24]
- Removed unneeded `cfg-if` dependency (#2553)
- **attributes**: Updated [`syn`] dependency to 2.0 (#2516)

### Fixed

- **attributes**: Fix `clippy::unreachable` warnings in
  `#[instrument]`-generated code (#2356)
- **attributes**: Removed unused "visit" feature flag from `syn`
  dependency (#2530)

### Documented

- **attributes**: Documented default level for `#[instrument(err)]`
  (#2433)
- **attributes**: Improved documentation for levels in `#[instrument]`
  (#2350)

Thanks to @nitnelave, @jsgf, @Abhicodes-crypto, @LukeMathWalker,
@andrewpollack, @quad, @klensy, @davidpdrsn, @dbidwell94, @ldm0,
@NobodyXu, @ilsv, and @daxpedda for contributing to this release!

[`syn`]: https://crates.io/crates/syn
[attrs-0.1.24]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.24
kaffarell pushed a commit to kaffarell/tracing that referenced this pull request May 22, 2024
This branch adds the ability to override the level of the events
generated by the `ret` and `err` arguments to `#[instrument]`. An
overridden level can be specified with:

```rust

```
```rust

```
and so on.

This syntax is fully backwards compatible with existing uses of the
attribute.

In addition, some refactoring was done to how levels are parsed and how
the tokens for a specified level is generated.

Fixes tokio-rs#2330
; Conflicts:
;	tracing-attributes/src/lib.rs
kaffarell pushed a commit to kaffarell/tracing that referenced this pull request May 22, 2024
# 0.1.24 (April 24th, 2023)

This release of `tracing-attributes` adds support for passing an
optional `level` to the `err` and `ret` arguments to `#[instrument]`,
allowing the level of the generated return-value event to be overridden.
For example,

```rust
#[instrument(err(level = "info"))]
fn my_great_function() -> Result<(), &'static str> {
    // ...
}
```

will emit an `INFO`-level event if the function returns an `Err`.

In addition, this release updates the [`syn`] dependency to v2.x.x.

### Added

- `level` argument to `err` and `ret` to override the level of the
  generated return value event (tokio-rs#2335)
- Improved compiler error message when `#[instrument]` is added to a
  `const fn` (tokio-rs#2418)

### Changed

- Updated `syn` dependency to 2.0 (tokio-rs#2516)

### Fixed

- Fix `clippy::unreachable` warnings in `#[instrument]`-generated code
  (tokio-rs#2356)
- Removed unused "visit" feature flag from `syn` dependency (tokio-rs#2530)

### Documented

- Documented default level for `err` (tokio-rs#2433)
- Improved documentation for levels in `#[instrument]` (tokio-rs#2350)

Thanks to @nitnelave, @jsgf, @Abhicodes-crypto, @LukeMathWalker,
@andrewpollack, @quad, @klensy, @davidpdrsn, and @dbidwell94 for
contributign to this release!

[`syn`]: https://crates.io/crates/syn
kaffarell pushed a commit to kaffarell/tracing that referenced this pull request May 22, 2024
# 0.1.38 (April 25th, 2023)

This `tracing` release changes the `Drop` implementation for
`Instrumented` `Future`s so that the attached `Span` is entered when
dropping the `Future`. This means that events emitted by the `Future`'s
`Drop` implementation will now be recorded within its `Span`. It also
adds `#[inline]` hints to methods called in the `event!` macro's
expansion, for an improvement in both binary size and performance.

Additionally, this release updates the `tracing-attributes` dependency
to [v0.1.24][attrs-0.1.24], which updates the [`syn`] dependency to
v2.x.x. `tracing-attributes` v0.1.24 also includes improvements to the
`#[instrument]` macro; see [the `tracing-attributes` 0.1.24 release
notes][attrs-0.1.24] for details.

### Added

- `Instrumented` futures will now enter the attached `Span` in their
  `Drop` implementation, allowing events emitted when dropping the
  future to occur within the span (tokio-rs#2562)
- `#[inline]` attributes for methods called by the `event!` macros,
  making generated code smaller (tokio-rs#2555)
- **attributes**: `level` argument to `#[instrument(err)]` and
  `#[instrument(ret)]` to override the level of the generated return
  value event (tokio-rs#2335)
- **attributes**: Improved compiler error message when `#[instrument]`
  is added to a `const fn` (tokio-rs#2418)

### Changed

- `tracing-attributes`: updated to [0.1.24][attrs-0.1.24]
- Removed unneeded `cfg-if` dependency (tokio-rs#2553)
- **attributes**: Updated [`syn`] dependency to 2.0 (tokio-rs#2516)

### Fixed

- **attributes**: Fix `clippy::unreachable` warnings in
  `#[instrument]`-generated code (tokio-rs#2356)
- **attributes**: Removed unused "visit" feature flag from `syn`
  dependency (tokio-rs#2530)

### Documented

- **attributes**: Documented default level for `#[instrument(err)]`
  (tokio-rs#2433)
- **attributes**: Improved documentation for levels in `#[instrument]`
  (tokio-rs#2350)

Thanks to @nitnelave, @jsgf, @Abhicodes-crypto, @LukeMathWalker,
@andrewpollack, @quad, @klensy, @davidpdrsn, @dbidwell94, @ldm0,
@NobodyXu, @ilsv, and @daxpedda for contributing to this release!

[`syn`]: https://crates.io/crates/syn
[attrs-0.1.24]:
    https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Configurable log level for #[instrument(err)]
2 participants