# 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.
# 0.3.12 (Jun 29, 2022)
This release of `tracing-subscriber` adds a new `Layer::event_enabled`
method, which allows `Layer`s to filter events *after* their field
values are recorded; a `Filter` implementation for `reload::Layer`, to
make using `reload` with per-layer filtering more ergonomic, and
additional inherent method downcasting APIs for the `Layered` type. In
addition, it includes dependency updates, and minor fixes for
documentation and feature flagging.
### Added
- **layer**: `Layer::event_enabled` method, which can be implemented to
filter events based on their field values (#2008)
- **reload**: `Filter` implementation for `reload::Layer` (#2159)
- **layer**: `Layered::downcast_ref` and `Layered::is` inherent methods
(#2160)
### Changed
- **parking_lot**: Updated dependency on `parking_lot` to 0.13.0
(#2143)
- Replaced `lazy_static` dependency with `once_cell` (#2147)
### Fixed
- Don't enable `tracing-core` features by default (#2107)
- Several documentation link and typo fixes (#2064, #2068, #2077,
#2161, #1088)
Thanks to @ben0x539, @jamesmunns, @georgemp, @james7132, @jswrenn,
@CAD97, and @guswynn for contributing to this release!
## Motivation
The `reload` layer doesn't (and can't) implement downcasting correctly,
which breaks certain `Layer`s which require downcasting (such as
`tracing-opentelemetry`'s `OpenTelemetryLayer`).
## Solution
Most usages of `reload` (including mine) are just to change a `Filter`,
so this PR implements `Filter` on the `reload::Layer` type to allow
users to not need to wrap the whole `Filtered` layer. Another advantage
of this is that the common-case critical sections are shortened
Co-authored-by: Eliza Weisman <eliza@buoyant.io>
In many cases, new releases of a dependency can break compatibility with
`tracing`'s minimum supported Rust version (MSRV). It shouldn't be
necessary for a `tracing` crate to bump its MSRV when a dependency does,
as users on older Rust versions should be able to depend on older
versions of that crate explicitly and avoid bumping. Instead, we should
probably just run our MSRV checks with minimal dependency versions. This
way, we don't need to bump our MSRV when the latest version of a
dependency does, unless we actually *need* to pick up that new version.
This branch changes the `check_msrv` CI jobs to do that. I also did some
minor dependency editing to actually make tracing build with
`-Zminimal-versions`.
Note that `tracing-futures` is currently excluded from the MSRV build
because it depends on a really ancient version of Tokio that pulls in
broken deps. We should probably drop support for Tokio 0.1 and release a
new version of that crate, but for now, we have to skip it from the CI
job temporarily.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
Allow filter layers to filter on the contents of events (see #2007).
## Solution
This branch adds a new `Subscriber::event_enabled` method, taking an
`Event` and returning `bool`. This is called before the
`Subscriber::event` method, and if it returns `false`,
`Subscriber::event` is not called.
For simple subscriber (e.g. not using `Layer`s), the `event_enabled`
method is not particulary necessary, as the subscriber can just skip the
`event` call. However, this branch also adds a new
`Layer::event_enabled` method, with the signature:
```rust
fn event_enabled(&self, event: &Event<'_>, ctx: Context<'_, S>) -> bool;
```
This is called before `Layer::on_event`, and if `event_enabled`
returns `false`, `on_event` is not called (nor is `Subscriber::event`).
This allows filter `Layer`s to filter out an `Event` based on its
fields.
Closes#2007
Adds inherent `downcast_ref` and `is` inherent methods to:
- `dyn Subscriber + Send`
- `dyn Subscriber + Sync`
- `dyn Subscriber + Send + Sync`
- `Layered`
These additional implementations reduce the circumstances in which one
must cast to `dyn Subscriber` (which, previously, was the only type for
which `downcast_ref` and `is` were available).
Replace `lazy_static` with `once_cell`. Fixes#2146.
## Motivation
`lazy_static!`, while a declarative macro, is a macro nonetheless. It
can add quite a bit of additional compilation time cost.
`once_cell::sync::Lazy` does the same thing with generics, and can be
used more flexibly (i.e. non-static lazily initialized values), and has
been proposed to be added to `std` (see linked issue).
I'm trying to reduce the compile time and dependency tree complexity of
a dependent project: [bevy](https://bevyengine.org), which is using
tracing. `lazy_static` and `once_cell` are both in our dependency tree
and both end up doing the same thing.
## Solution
Migrate to `once_cell`.
This attempts to address #2106 by disabling the `tracing-core`
crate's default features in `tracing-subscriber`'s dependency.
Now, `tracing-core`'s optional "alloc" feature is only enabled
when "tracing-subscriber/alloc" is enabled.
Closes#2106
* docs: `cargo intraconv` for more intra-doc links
... also it deleted some redundant ones, and it got some things wrong,
and it was gonna delete some of the cross-crate docs.rs links we can't
do as intra-doc links so I passed `--no-favored`.
* docs: convert https:// links to std/core/alloc to intra-doc links
Note that this adds some more broken intra doc links when building
without std support, but that was already a thing and I expect people
who build their own docs without std support can handle it.
This time I gave up on sed and used ruby.
find -name '*.rs' -exec ruby -i -p blah.rb {} +
with
$_.gsub!(%r{
https://doc\.rust-lang\.org/
(?: stable/)?
((?:core | std | alloc)(?:/\S+?)*)
/(\w+)\.(\w+)\.html}x
) {
path, kind, name = $~.captures
suffix = case kind
when 'method' then '()'
when 'macro' then '!'
else ''
end
r = [path.gsub('/', '::'), '::', name, suffix].join
STDERR.puts [path, kind, name, suffix, r].inspect
r
}
$_.gsub!(%r{
https://doc\.rust-lang\.org/
(?: stable/)?
((?: core | std | alloc)(?:/\S+?)*)
/(?:
index\.html
| $
| (?= \#)
)}x
) {
path, _ = $~.captures
r = path.gsub('/', '::')
STDERR.puts [path, r].inspect
r
}
* docs: more cross-crate intra-doc links
cargo intraconv doesn't seem to get them reliably and also plenty of
links to other crates aren't actually intra-doc because they're in
crates that don't depend (or only dev-depend, or only conditionally
depend) on those crates, so this wasn't very automated.
I tried to only convert docs.rs links to unconditional dependencies to
intra-crate links, but it's possible that some slipped through in either
direction.
## Motivation
#940, I guess. I kept running into the odd broken link in the docs and
eventually realized it's because a lot of stuff is reexported in parent
modules and so the file path based relative links couldn't possibly work
in all contexts. Looks like master already underwent this treatment but
I suspect this is easier than backporting.
## Solution
Intra-doc links seem pretty good.
I started with
```
find -name \*.rs -exec sed -i -e '
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\.\./\w\+\.\(\w\+\)\.html@\1super::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\.\./\(\w\+\)/\w\+\.\(\w\+\)\.html@\1super::\2::\3@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\.\./\.\./\w\+\.\(\w\+\)\.html@\1super::super::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\.\./\.\./\(\w\+\)/\w\+\.\(\w\+\)\.html@\1super::super::\2::\3@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\.\./\(\w\+\)/index\.html@\1super::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\.\./index\.html@\1super@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\.\./\(\w\+\)/\?$@\1super::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\./\w\+\.\(\w\+\)\.html@\1self::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\./\(\w\+\)/\w\+\.\(\w\+\)\.html@\1self::\2::\3@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\./\(\w\+\)/index\.html@\1self::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\./index\.html@\1self@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\./\(\w\+\)/\?$@\1self::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\w\+\.\(\w\+\)\.html@\1self::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\(\w\+\)/\w\+\.\(\w\+\)\.html@\1self::\2::\3@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\(\w\+\)/index\.html@\1self::\2@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?index\.html@\1self@;
s@\(//. \[[^]]*\]:\s\+\)[:"]\?\(\w\+\)/\?$@\1self::\2@;
s@\(//. \[[^]]*\]:\s\+[A-Za-z_0-9:]\+\)#method\.\(\w\+\)@\1::\2@;
' {} +
```
and then removed redundant `self::`s when I realized you don't actually
need a `::` in the links, and fixed stuff up by hand as I ran into
errors from
```
x='--cfg docsrs --cfg tracing_unstable'; RUSTFLAGS=$x RUSTDOCFLAGS=$x cargo doc --all-features
```
I hope that's roughly how the docs are supposed to work.
I understand this is a relatively big unsolicited change in that it
touches a whole lot of files (definitely went further than I originally
intended), I'm happy to revise or split or reduce scope of this PR as
desired.
Depends on #2057
## Motivation
Currently, `EnvFilter`'s `Layer` implementation provides a
`Layer::on_record` method, but its `Filter` implementation is
missing the corresponding `Filter::on_record` implementation. This means
that when using `EnvFilter` as a per-layer filter, recording span
fields after the spans were created will not update the filter state.
## Solution
This commit factors out the `on_record` implementation for `Layer`
into an inherent method, and adds a new `Filter::on_record` method that
calls it as well.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
Currently, there is a potential namespace resolution issue when calling
`EnvFilter` methods that have the same name in the `Filter` and
`Layer` traits (such as `enabled` and `max_level_hint`). When both
`Filter` and `Layer` are in scope, the method resolution is
ambiguous.
See https://github.com/tokio-rs/tracing/pull/1983#issuecomment-1088984580
## Solution
This commit solves the problem by making the inherent method versions of
these methods public. When the traits are in scope, name resolution will
always select the inherent method prefer`entially, preventing the name
clash.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
See issue #2046. When using calling [`Builder::parse`] or
[`Builder::parse_lossy`] with an empty string an error is produced.
This happens for example when `EnvFilter::from_default_env()` is called,
but the `RUST_LOG` variable is unset. This regression was introduced by
#2035.
## Solution
Filter any empty directives. This allows the whole string to be empty,
as well as leading and trailing commas. A unit test was added for
[`Builder::parse`], but not [`Builder::parse_lossy`] because it (per
definition) doesn't produce any side effects visible from tests when
erroring.
Fixes#2046
[`Builder::parse`]: cade7e3118/tracing-subscriber/src/filter/env/builder.rs (L151)=
[`Builder::parse_lossy`]: cade7e3118/tracing-subscriber/src/filter/env/builder.rs (L135)=
## Motivation
The Rust 1.60 release introduced a few new lints that trigger on the
`tracing` codebase. In particular, `clippy` added some new lints for
method naming, and the `unreachable_pub` lint now seems to be triggered
incorrectly by `pub use foo as _` re-exports.
## Solution
This branch fixes the lints.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
Currently, `EnvFilter` will always interpret all field value filter
directives that are not numeric,or boolean literals as regular
expressions that are matched against a field's `fmt::Debug` output. In
many cases, it may not be desirable to use regular expressions in this
case, so users may prefer to perform literal matching of `fmt::Debug`
output against a string value instead. Currently, this is not possible.
## Solution
This branch introduces the ability to control whether an `EnvFilter`
interprets field value `fmt::Debug` match filters as regular expressions
or as literal strings. When matching literal `fmt::Debug` patterns, the
string is matched without requiring a temporary allocation for the
formatted representation by implementing `fmt::Write` for a matcher type
and "writing" the field's `Debug` output to it. This is similar to the
technique already used for matching regular expression patterns.
Since there is not currently a nice way to specify configurations prior
to parsing an `EnvFilter` from a string or environment variable, I've
also added a builder API. This allows setting things like whether field
value filters should use strict matching or regular expressions.
## Notes
Ideally, I think we would want the filter language to allow specifying
whether a field value filter should be interpreted as a regular
expression or as a literal string match. Instead of having a global
toggle between regular expressions and literal strings, we would
introduce new syntax for indicating that a value match pattern is a
regular expression. This way, a single filter can have both regular
expression and literal string value matchers. The `with_regex(false)`
configuration would just return an error any time the regex syntax was
used when parsing the filter string.
However, this would be a breaking change in behavior. Currently, field
value filters are interpreted as regex by default, so changing the
parser to only interpret a value filter as a regex if there's additional
syntax indicating it's a regex would break existing filter
configurations that rely on regex matching.
In `tracing-subscriber` 0.4, we should definitely consider introducing
new syntax to indicate a match pattern is a regex, and change the
`with_regex` method's behavior to disallow the use of that syntax. For
now, however, making it a global toggle at least allows users to control
whether or not we use regex matching, so this is a significant
improvement for v0.3.x.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
This adds more modification methods for use with reloading. Replaces
#2032.
## Motivation
I have a `Filtered` layer that I'd like to modify with a reload handle. If
I use `reload` then the filter doesn't work. If I use `modify` with
`filter_mut` I can't update the writer.
## Solution
Adds some additional accessor methods to allow the writer to be modified
in `modify`:
* `Filtered::inner`
* `Filtered::inner_mut`
* `fmt::Layer::writer`
* `fmt::Layer::writer_mut`
* `fmt::Layer::set_ansi`
Depends on #2028
## Motivation
In many cases, it is desirable to have a variable number of `Layer`s
at runtime (such as when reading a logging configuration from a config
file). The current approach, where types implementing `Layer` are
composed at the type level into `Layered` layers, doesn't work well
when the number of layers varies at runtime.
## Solution
To solve this, this branch adds a `Layer` implementation for
`Vec<L> where L: Layer`. This allows variable-length lists of
layers to be added to a subscriber. Although the impl for `Vec<L>`
requires all the layers to be the same type, it can also be used in
onjunction with `Box<dyn Layer<S> + ...>` trait objects to
implement a variable-length list of layers of multiple types.
I also wrote a bunch of docs examples.
## Notes
Alternatively, we could have a separate type defined in
`tracing-subscriber` for a variable-length list of type-erased
`Layer`s. This would have one primary usability benefit, which is
that we could have a `push` operation that takes an `impl Layer`
and boxes it automatically. However, I thought the approach used
here is nicer, since it's based on composing together existing
primitives such as `Vec` and `Box`, rather than adding a whole new API.
Additionally, it allows avoiding the additional `Box`ing in the case
where the list consists of layers that are all the same type.
Closes#1708
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
## Motivation
EnvFilter with ansi_term will say something like the following when
statically disabled filters are present:
```
warning: some trace filter directives would enable traces ...
= note: the static max level is `LEVEL`
= help: to enable LEVEL logging, ...
```
Without the ansi_term feature, it instead says something like the
following:
```
warning: some trace filter directives would enable traces ...
note: the static max level is `LEVEL`
note: to enable LEVEL logging, ...
```
This is due to a simple error in cfg'd code that ignores the requested
prefix and always uses `note:` when `not(feature = "ansi_term")`.
## Solution
Use the unused `prefix` variable to do what it does when `feature =
"ansi_term"`.
The output without ansi_term is now
```
warning: some trace filter directives would enable traces ...
note: the static max level is `LEVEL`
help: to enable LEVEL logging, ...
```
## Motivation
PR #2023 made the `impl Layer` for boxed `dyn Layer` trait
objects actually be useful. One minor annoyance when working with boxed
trait objects is that, in some cases, in order to use `Box::new` to
erase a `Layer`'s type, it's necessary to add a type annotation like
this:
```rust
let boxed_layer: Box<dyn Layer<_> + Send + Sync + 'static>
= Box::new(some_layer);
```
Because the trait object includes `Send + Sync + 'static`, this is a bit
wordy to type out.
## Solution
This commit adds a `Layer::boxed` method that takes `Self` and boxes
it as a type-erased `dyn Layer` trait object. This can then be
chained after a a chain of layer builder methods. Because the
`boxed` method _explicitly_ returns a `dyn Layer<_> + ...` trait
object, it's not necessary to use a wordy type annotation when
using this method.
Depends on #2023
## Motivation
Currently, `FmtLayer` holds a `PhantomData<S>` with the `Subscriber`
type it wraps. This is unfortunate because it means that the
layer's auto traits such as `Send`, `Sync`, and `'static` (as well
as `UnwindSafe`, `Unpin`, etc) depend on the `Subscriber` type's auto
traits...but the layer will never actually _store_ a value of type
`S`. While all `Subscriber` will be `Send + Sync + 'static` in practice,
the `PhantomData` means that functions returning a boxed `FmtLayer`
must unnecessarily bound the subscriber type parameter.
## Solution
This commit changes the `PhantomData` to `PhantomData<fn(S)>`, solving
the problem.
Signed-off-by: Eliza Weisman <eliza@buoyant.io>