## Motivation
As seen here #2512 and #2223. Previously pr'ed here #2525, but no progress has
been made there for quite some. I have applied the suggested changes. Not sure
the formatting of the doc is sufficient or otherwise correct
## Solution
Make the `format::Writer::new()` function public. I don't see any obvious
trade-offs, but I am not familiar with the larger direction of
tracing/subscriber, so I may be wrong.
Closes #2512Closes#2223
Co-authored-by: Cephas Storm <cephas.storm@borisfx.com>
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
It's currently awkward to have an optional per-layer filter.
Implement `Filter<L>` for `Option<F> where F: Filter<L>`, following the example
of `Layer`. A `None` filter passes everything through.
Also, it looks like Filter for Arc/Box doesn't pass through all the methods, so
extend the `filter_impl_body` macro to include them.
This also adds a couple of tests and updates the docs.
---------
Co-authored-by: David Barsky <me@davidbarsky.com>
Co-authored-by: Ryan Johnson <ryantj@fb.com>
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
Issue https://github.com/tokio-rs/tracing/issues/2080 explains that it's not
possible to soundly use
[`tracing_subscriber::fmt::time::LocalTime`](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/time/struct.LocalTime.html)
in a multithreaded context. It proposes adding alternative time formatters that
use the [chrono crate](https://docs.rs/chrono/latest/chrono/) to workaround
which is what this PR offers.
A new source file 'chrono_crate.rs' is added to the 'tracing-subscriber'
package implementing `mod chrono_crate` providing two new tag types `LocalTime`
and `Utc` with associated `time::FormatTime` trait implementations that call
`chrono::Local::now().to_rfc3339()` and `chrono::Utc::now().to_rfc3339()`
respectively. Simple unit-tests of the new functionality accompany the
additions.
---------
Co-authored-by: David Barsky <me@davidbarsky.com>
Co-authored-by: Shayne Fletcher <shaynefletcher@meta.com>
This branch fixes a handful of new warnings which have shown up after
updating to Rust 1.72.0.
This includes:
* `clippy::redundant_closure_call` in macros --- allowed because the
macro sometimes calls a function that isn't a closure, and the closure
is just used in the case where it's not a function.
* Unnecessary uses of `#` in raw string literals that don't contain `"`
characters.
* Dead code warnings with specific feature flag combinations in
`tracing-subscriber`.
In addition, I've fixed a broken RustDoc link that was making the
Netlify build sad.
It's necessary at times to be able to disable ANSI color output for
rust utilities using `tracing`. The informal standard for this is the
`NO_COLOR` environment variable described here: https://no-color.org/
Further details/discussion in #2388
This commit updates `fmt::Layer` to check the `NO_COLOR`
environment variable when determining whether ANSI color output is
enabled by default. As described in the spec, any non-empty value set
for `NO_COLOR` will cause ANSI color support to be disabled by default.
If the user manually overrides ANSI color support, such as by calling
`with_ansi(true)`, this will still enable ANSI colors, even if
`NO_COLOR` is set. The `NO_COLOR` env var only effects the default
behavior.
Fixes#2388
Currently, in many places, macros do not use fully qualified names for
items exported from the prelude. This means that naming collisions
(`struct Some`) or the removal of the std library prelude will cause
compilation errors.
- Identify and use fully qualified names in macros were we previously
assumed the Rust std prelude. We use `::core` rather than `::std`.
- Add
[`no_implicit_prelude`](https://doc.rust-lang.org/reference/names/preludes.html#the-no_implicit_prelude-attribute)
to `tracing/tests/macros.rs`. I'm unsure if this is giving us good
coverage - can we improve on this approach? I'm not confident I've
caught everything.
There has been interest around publishing `tracing-mock` to crates.io
for some time. In order to make this possible, documentation and some
code clean up is needed.
This change adds documentation to the collector module itself and to all the
public APIs in the module. This includes doctests on all the methods
that serve as examples.
Additionally the implementation for the `Expect` struct has been moved
into the module with the definition, this was missed in #2369.
Refs: #539
* mock: change helper functions to `expect::<thing>`
The current format of test expectations in `tracing-mock` isn't ideal.
The format `span::expect` requires importing `tracing_mock::<thing>` which
may conflict with imports from other tracing crates, especially
`tracing-core`.
So we change the order and move the functions into a module called
`expect` so that:
* `event::expect` becomes `expect::event`
* `span::expect` becomes `expect::span`
* `field::expect` becomes `expect::field`
This format has two advantages.
1. It reads as natural English, e.g "expect span"
2. It is no longer common to import the modules directly.
Regarding point (2), the following format was previously common:
```rust
use tracing_mock::field;
field::expect();
```
This import of the `field` module may then conflict with importing the
same from `tracing_core`, making it necessary to rename one of the
imports.
The same code would now be written:
```rust
use tracing_mock::expect;
expect::field();
```
Which is less likely to conflict.
This change also fixes an unused warning on `MockHandle::new` when the
`tracing-subscriber` feature is not enabled.
Refs: #539
The `tracing-mock` crate provides a mock collector (and a subscriber for
use by the tests in the `tracing-subscriber` crate) which is able to
make assertions about what diagnostics are emitted.
These assertions are defined by structs that match on events, span, and
their fields and metadata. The structs that matched these objects have
been called, up until now, mocks, however this terminology may be
misleading, as the created objects don't mock anything.
There were two different names for similar functionality with `only()`
and `done()` on fields and collectors/subscribers respectively. Using a
single name for these may make it easier to onboard onto `tracing-mock`.
To reduce confusion, these structs have been split into two categories:
mocks and expectations.
Additionally, the `done()` function on the `Collector` and `Subscriber`
mocks has been replaced with `only()`. This matches the similar function
for `ExpectedField`, and may be more intuitive.
The mocks replace some component in the tracing ecosystem when a library
is under test. The expectations define the assertions we wish to make
about traces received by the mocks.
Mocks (per module):
* collector - `MockCollector`, no change
* subscriber - `MockSubscriber`, renamed from `ExpectSubscriber`
Expectations (per module):
* event - `ExpectedEvent`, renamed from `MockEvent`
* span - `ExpectedSpan`, renamed from `MockSpan`
* field - `ExpectedField` and `ExpectedFields`, renamed from `MockField`
and `Expected`. Also `ExpectedValue` renamed from `MockValue`.
* metadata - `ExpectedMetadata`, renamed from `Expected`
Refs: #539
## Motivation
This was inconsistent with other features, which mention their
requirements, and a reader might assume they don't need to inspect the
feature flags page or manifest.
# 0.3.17 (April 21, 2023)
This release of `tracing-subscriber` fixes a build error when using
`env-filter` with recent versions of the `regex` crate. It also
introduces several minor API improvements.
### Fixed
- **env-filter**: Add "unicode-case" and "unicode-perl" to the `regex`
dependency, fixing a build error with recent versions of `regex`
(#2566)
- A number of minor documentation typos and other fixes (#2384, #2378,
#2368, #2548)
### Added
- **filter**: Add `fmt::Display` impl for `filter::Targets` (#2343)
- **fmt**: Made `with_ansi(false)` no longer require the "ansi" feature,
so that ANSI formatting escapes can be disabled without requiring
ANSI-specific dependencies (#2532)
### Changed
- **fmt**: Dim targets in the `Compact` formatter, matching the default
formatter (#2409)
Thanks to @keepsimple1, @andrewhalle, @LeoniePhiline, @LukeMathWalker,
@howardjohn, @daxpedda, and @dbidwell94 for contributing to this
release!
## Motivation
Missing features for the `regex` crate were causing build time errors
due to the the use of unicode characters in the regex without using
the proper features within the regex crate
## Solution
Add the missing feature flags.
Fixes#2565
Authored-by: Devin Bidwell <dbidwell@biddydev.com>
The `tracing-subscriber` module `tests::support` included functionality
to mock a layer (via the `Layer` trait). This code depends on
some items from `tracing_mock::collector` which should otherwise not be
public.
This change moves the mocking functionality inside `tracing-mock` behind
a feature flag. Allowing the `Expect` enum and `MockHandle::new` from
`tracing_mock::collector` to be made `pub(crate)` instead of `pub`.
Since it's now used from two different modules, the `Expect` enum has
been moved to its own module.
This requires a lot of modifications to imports so that we're not doing
wildcard imports from another crate (i.e. in `tracing-subscriber`
importing wildcards from `tracing-mock`).
This PR is based on @hds' PR #2369, but modified to track renamings. I
also deleted all the doc comments temporarily because updating them was
a lot of work and I need to get a release of `tracing-subscriber` out
first.
Closes: #2359
## Motivation
Currently it is not possible to disable ANSI in `fmt::Subscriber`
without enabling the "ansi" crate feature. This makes it difficult for
users to implement interoperable settings that are controllable with
crate features without having to pull in the dependencies "ansi" does.
I hit this while writing an application with multiple logging options
set during compile-time and I wanted to cut down on dependencies if
possible.
## Solution
This changes `fmt::Subscriber::with_ansi()` to not require the "ansi"
feature flag. This way, `with_ansi(false)` can be called even when the
"ansi" feature is disabled. Calling `with_ansi(true)` when the "ansi"
feature is not enabled will panic in debug mode, or print a warning if
debug assertions are disabled.
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
There is a small wording mistake in the tracing-subscriber docs
that can be fixed quickly and easily.
## Solution
Two duplicate words were removed.
This `doc_cfg` attribute's `cfg` part has multiple predicates without an
`all`, which iis what's breaking the netlify build. I'm...kind of
surprised this ever succeeded, since the cfg is malformed...
## Motivation
There's currently a `fmt::Display` impl for `EnvFilter` that emits an
equiovalent filter string that can be parsed back into an `EnvFilter`,
but the `Targets` filter does not have a `fmt::Display` impl. We ought
to have one, especially to make using `Targets` with `clap` v4.0 easier.
## Solution
This branch adds a `fmt::Display` impl for `filter::Targets`. The
implementation is pretty straightforward.
I also added tests that a `Targets`' `fmt::Display` output can be parsed
back into a filter that's equivalent to the original.
## Motivation
Clippy check fails in recent CI runs in v0.1.x branch PRs, for example
this run:
https://github.com/tokio-rs/tracing/actions/runs/4641107803/jobs/8215263838
Relevant error logs:
```
error: lint `const_err` has been removed: converted into hard error, see issue #71800 <https://github.com/rust-lang/rust/issues/71800> for more information
--> tracing-core/src/lib.rs:132:5
|
132 | const_err,
| ^^^^^^^^^
|
= note: `-D renamed-and-removed-lints` implied by `-D warnings`
error: deref which would be done by auto-deref
--> tracing-core/src/dispatcher.rs:371:26
|
371 | return f(&*entered.current());
| ^^^^^^^^^^^^^^^^^^^ help: try this: `&entered.current()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_auto_deref
= note: `-D clippy::explicit-auto-deref` implied by `-D warnings`
error: deref which would be done by auto-deref
--> tracing-core/src/dispatcher.rs:393:20
|
393 | Some(f(&*entered.current()))
| ^^^^^^^^^^^^^^^^^^^ help: try this: `&entered.current()`
|
= help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#explicit_auto_deref
```
## Solution
Fix the warnings based on the suggestions for Clippy.
# 0.3.16 (October 6, 2022)
This release of `tracing-subscriber` fixes a regression introduced in
[v0.3.15][subscriber-0.3.15] where `Option::None`'s `Layer`
implementation would set the max level hint to `OFF`. In addition, it
adds several new APIs, including the `Filter::event_enabled` method for
filtering events based on fields values, and the ability to log internal
errors that occur when writing a log line.
This release also replaces the dependency on the unmaintained
[`ansi-term`] crate with the [`nu-ansi-term`] crate, resolving an
*informational* security advisory ([RUSTSEC-2021-0139] for
[`ansi-term`]'s maintainance status. This increases the minimum
supported Rust version (MSRV) to Rust 1.50+, although the crate should
still compile for the previous MSRV of Rust 1.49+ when the `ansi`
feature is not enabled.
### Fixed
- **layer**: `Option::None`'s `Layer` impl always setting the
`max_level_hint` to `LevelFilter::OFF` (#2321)
- Compilation with `-Z minimal versions` (#2246)
- **env-filter**: Clarify that disabled level warnings are emitted by
`tracing-subscriber` (#2285)
### Added
- **fmt**: Log internal errors to `stderr` if writing a log line fails
(#2102)
- **fmt**: `FmtLayer::log_internal_errors` and
`FmtSubscriber::log_internal_errors` methods for configuring whether
internal writer errors are printed to `stderr` (#2102)
- **fmt**: `#[must_use]` attributes on builders to warn if a
`Subscriber` is configured but not set as the default subscriber
(#2239)
- **filter**: `Filter::event_enabled` method for filtering an event
based on its fields (#2245, #2251)
- **filter**: `Targets::default_level` accessor (#2242)
### Changed
- **ansi**: Replaced dependency on unmaintained `ansi-term` crate with
`nu-ansi-term` ((#2287, fixes informational advisory
[RUSTSEC-2021-0139])
- `tracing-core`: updated to [0.1.30][core-0.1.30]
- Minimum Supported Rust Version (MSRV) increased to Rust 1.50+ (when
the `ansi`) feature flag is enabled (#2287)
### Documented
- **fmt**: Correct inaccuracies in `fmt::init` documentation (#2224)
- **filter**: Fix incorrect doc link in `filter::Not` combinator
(#2249)
Thanks to new contributors @cgbur, @DesmondWillowbrook, @RalfJung, and
@poliorcetics, as well as returning contributors @CAD97, @connec,
@jswrenn, @guswynn, and @bryangarza, for contributing to this release!
[nu-ansi-term]: https://github.com/nushell/nu-ansi-term
[ansi_term]: https://github.com/ogham/rust-ansi-term
[RUSTSEC-2021-0139]: https://rustsec.org/advisories/RUSTSEC-2021-0139.html
[core-0.1.30]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.30
[subscriber-0.3.15]: https://github.com/tokio-rs/tracing/releases/tag/tracing-subscriber-0.3.15
This reverts commit a0824d398aa2511de28371d30dda9203360a6cf5 (PR #2247).
As discussed in [this comment][1], the implementation for `Arc`s may
cause subtly incorrect behavior if actually used, due to the `&mut self`
receiver of the `LookupSpan::register_filter` method, since the `Arc`
cannot be mutably borrowed if any clones of it exist.
The APIs added in PRs #2269 and #2293 offer an alternative solution to
the same problems this change was intended to solve, and --- since this
change hasn't been published yet --- it can safely be reverted.
[1]:
https://giethub.com/tokio-rs/tracing/pull/2247#issuecomment-1199924876
## Motivation
Currently, when using the `Layer` impl for `Option<S: Layer<...>>`, the
`Layer::max_level_hint` returns `Some(LevelFilter::OFF)`. This was
intended to allow totally disabling output in the case where a
`Subscriber` is composed entirely of `None` `Layer`s. However, when
other `Layer`s *do* exist but return `None` from their `max_level_hint`
implementations to indicate that they don't care what the max level is,
the presence of a single `None` layer will globally disable everything,
which is not the wanted behavior.
Fixes#2265
## Solution
This branch introduces a special downcast marker that can be used to
detect when a `Layer` in a `Layered` is `None`. This allows the
`pick_level_hint` method to short-circuit when a `Layer` implementation
which is `None` returns `Some(LevelFilter::OFF)` from its
`max_level_hint` if the other half of the `Layered` is not `None`. The
tests I added should be pretty thorough!
Additionally, the downcast marker is special-cased in the `reload`
`Layer`. Normally, this `Layer` doesn't support downcasting, but it can
in the case of the special marker value.
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
Allows `Subscriber`s and `Layer`s to stash their own `Dispatch` without
causing a memory leak.
## Motivation
Resolves a shortcoming of #2269: that it's impossible for `Subscriber`s
or `Layer`s to stash a copy of their own `Dispatch` without creating a
reference cycle that would prevent them from being dropped.
## Solution
Introduces `WeakDispatch` (analogous to `std::sync::Weak`) that holds a
weak pointer to a `Subscriber`. `WeakDispatch` can be created via
`Dispatch::downgrade`, and can be transformed into a `Dispatch` via
`WeakDispatch::upgrade`.
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
The `on_register_dispatch` method is invoked when a `Subscriber` is
registered as a `Dispatch`. This method should be overridden to
perform actions upon the installation of a subscriber/layer;
for instance, to send a copy of the subscriber's `Dispatch` to a
worker thread.
I just saw this warning when trying to debug something in Miri:
```
warning: some trace filter directives would enable traces that are disabled statically
| `miri::tls=trace` would enable the TRACE level for the `miri::tls` target
= note: the static max level is `info`
= help: to enable DEBUG logging, remove the `max_level_info` feature
```
I spent 10min figuring out why the `log` crate is doing this (Miri is
using env-logger for logging), until I realized that this error actually
originates from inside rustc, which I guess uses `tracing`. It would
have helped if the error message would say which crate is even talking
to me here. :)
## Motivation
Like for `Subscriber` and `Layer`, allow per-layer `Filter`s to filter
based on event fields.
## Solution
Add `Filter::event_enabled`, plumb it through the combinator
implementations, and call it from `Filtered`.
The bit I'm the least confident about is the check in `Registry`'s
implementation, but I *think* it matches what `event` is doing and
everything seems to function correctly.
## Motivation
This makes it possible to fully "override" some base `Targets` filter
with another (e.g. user-supplied) filter. Without some way to obtain the
default, only explicit targets can be overridden (via `IntoIter` and
friends).
See also https://github.com/tokio-rs/tracing/issues/1790#issuecomment-999739222
## Solution
We can add a method to `Targets` that filters the underlying
`DirectiveSet` for the default directive. This works because
`DirectiveSet::add` will replace directives with the same
`target`/`field_names`, which is always `None`/`vec![]` for the
directive added by `with_default` (and in fact we are only concerned
with `target`, since no other `Targets` API allows adding directives
with a `None` target).
Ideally the method would be named `default`, corresponding to
`with_default`, however this conflicts with `Default::default` and so
would be a breaking change (and harm ergonomics). `default_level` seemed
a better name than `get_default`, since "getters" of this style are
generally considered unidiomatic<sup>[citation needed]</sup>.
Example usage:
```rust
let mut filter = Targets::new().with_target("some_module", LevelFilter::INFO);
// imagine this came from `RUST_LOG` or similar
let override: Targets = "trace".parse().unwrap();
// merge the override
if let Some(default) = override.default_level() {
filter = filter.with_default(default);
}
for (target, level) in override.iter() {
filter = filter.with_target(target, level);
}
```
Closes#1790
## Motivation
Previously the documentation for `fmt::init()` was misleading. It stated
that it was shorthand for `fmt().init()`. This lead to confusion as
users would expect the same behavior from both. However `fmt::init()`
would, whether you used the env-filter feature or not, rely on RUST_LOG
to set the tracing level. `fmt().init()` does not do this and it must be
set with a specific configuration via `with_env_filter`.
## Solution
The documentation has been updated to no longer state that it is 1:1
shorthand for the other. The documentation now specifically points out
that you must be using the `env-filter` feature and gives a correct
example to mimic the `fmt::init()` behavior using `fmt().init()`.
Fixes#2217Fixes#1329
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
Fix minimal-versions failure.
## Solution
Upgrade all the dependencies to their most recent semver-compatible
version, adjusting back down as necessary for MSRV.
Essentially a cherry-pick of #2231, but redone by hand.
## Tests
- `cargo minimal-versions msrv verify -- cargo check --all-features`
- `cargo minimal-versions msrv verify -- cargo check --no-default-features`
## Methodology
- `cargo update && cargo upgrade --to-lockfile`
- Identify [a bug](https://github.com/killercup/cargo-edit/issues/750) and manually resolve it
- loop; upgrade transitive deps
- `cargo minimal-versions check --all-features`
- Identify failing dep
- `cargo minimal-versions tree -i dep --all-features`
- Find the closest dependency leading to pulling in `dep`
- `cargo add fixdep --optional` to force a more recent more-minimal-versions-correct version
- loop; downgrade to msrv
- `cargo minimal-versions msrv verify -- cargo check --all-features`
- Identify failing dep
- `cargo minimal-versions tree -i dep --all-features`
- Find the version that supports MSRV from lib.rs
- `cargo upgrade dep@msrv`
Motivation:
When `Format_event::format_event(...)` returns an error, we are
currently silently dropping that
Event. https://github.com/tokio-rs/valuable/issues/88 explains one
such case in which this was encountered (due to a bug in
valuable-serde). We want to be made aware whenever an Event is dropped.
Solution:
Write to the Writer with an error message to let the user know that
we were unable to format a specific event. If writing to the Writer fails,
we fall back to writing to stderr. We are not emitting an actual tracing
Event, to avoid the risk of a cycle (the new Event could trigger the
same formatting error again).
Resolves#1965.
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
Co-authored-by: David Barsky <me@davidbarsky.com>
# 0.3.15 (Jul 20, 2022)
This release fixes a bug where the `reload` layer would fail to pass
through `max_level_hint` to the underlying layer, potentially breaking
filtering.
### Fixed
- **reload**: pass through `max_level_hint` to the inner `Layer`
([#2204])
Thanks to @guswynn for contributing to this release!
[#2204]: https://github.com/tokio-rs/tracing/pull/2204
## Motivation
When using a `reload` layer, the fast-path current level check doesn't
work, as the `max_level_hint` is just `None`, which `rebuild_interest`
interprets as `TRACE`
## Solution
Pass through to the underlying layer/filter. On poisons, when already
panicking, just return `None`
# 0.3.14 (Jul 1, 2022)
This release fixes multiple filtering bugs in the `Layer`
implementations for `Option<impl Layer>` and `Vec<impl Layer>`.
### Fixed
- **layer**: `Layer::event_enabled` implementation for `Option<impl
Layer<S>>` returning `false` when the `Option` is `None`, disabling
all events globally ([#2193])
- **layer**: `Layer::max_level_hint` implementation for `Option<impl
Layer<S>>` incorrectly disabling max level filtering when the option
is `None` ([#2195])
- **layer**: `Layer::max_level_hint` implementation for `Vec<impl
Layer<S>>` returning `LevelFilter::ERROR` rather than
`LevelFilter::OFF` when the `Vec` is empty ([#2195])
Thanks to @CAD97 and @guswynn for contributing to this release!
[#2193]: https://github.com/tokio-rs/tracing/pull/2193
[#2195]: https://github.com/tokio-rs/tracing/pull/2195
## Motivation
These are incorrect: currently, when you have a `None` layer, the `None`
hint it returns causes the default `TRACE` to win, which is inaccurate.
Similarly, `Vec` should default to `OFF` if it has no `Layer`s in it
## Solution
Change the default hints to `Some(OFF)`
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
This is wrong.
## Solution
Make it unwrong.
As described by the documentation on `Layer::event_enabled`, the
return value sets the global filtering of an event. This code used to
say that that `Option::<impl Layer>::None` existing in the
layer stack should disable any layer in the stack seeing
events
# 0.3.13 (Jun 30, 2022)
This release of `tracing-subscriber` fixes a compilation failure due to
an incorrect `tracing-core` dependency that was introduced in v0.3.12.
### Changed
- **tracing_core**: Updated minimum dependency version to 0.1.28 (#2190)
This fixes a Clippy lint for explicitly calling `drop` on a value
without a `Drop` impl, and a lint for `let` bindings whose
value is `()`.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
PR #2008 added a new method to the `tracing_core::Subscriber` trait, and
modified `tracing-subscriber` to and implement that method. However,
that PR did *not* increase the minimum `tracing-core` dependency for the
`tracing-subscriber` crate.
This means that if a dependent of `tracing-subscriber` updates *only*
`tracing-subscriber` dependency version (e.g. by running
`cargo update -p tracing-subscriber`), it will not also update its
`tracing-core` version to one that contains the new method, and
`tracing-subscriber` will fail to compile. This is a common occurrence
with projects using Dependabot, for example.
## Solution
This commit updates `tracing-subscriber`'s minimum `tracing-core` dep to
0.1.28. Once this merges, I'll release 0.3.13 of `tracing-subscriber`
and yank 0.3.12.