summaryrefslogtreecommitdiffstats
path: root/third_party/rust/tracing
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/tracing
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--third_party/rust/tracing-attributes/.cargo-checksum.json1
-rw-r--r--third_party/rust/tracing-attributes/CHANGELOG.md327
-rw-r--r--third_party/rust/tracing-attributes/Cargo.toml91
-rw-r--r--third_party/rust/tracing-attributes/LICENSE25
-rw-r--r--third_party/rust/tracing-attributes/README.md91
-rw-r--r--third_party/rust/tracing-attributes/src/attr.rs413
-rw-r--r--third_party/rust/tracing-attributes/src/expand.rs814
-rw-r--r--third_party/rust/tracing-attributes/src/lib.rs677
-rw-r--r--third_party/rust/tracing-attributes/tests/async_fn.rs462
-rw-r--r--third_party/rust/tracing-attributes/tests/destructuring.rs213
-rw-r--r--third_party/rust/tracing-attributes/tests/err.rs233
-rw-r--r--third_party/rust/tracing-attributes/tests/fields.rs160
-rw-r--r--third_party/rust/tracing-attributes/tests/follows_from.rs99
-rw-r--r--third_party/rust/tracing-attributes/tests/instrument.rs252
-rw-r--r--third_party/rust/tracing-attributes/tests/levels.rs96
-rw-r--r--third_party/rust/tracing-attributes/tests/names.rs63
-rw-r--r--third_party/rust/tracing-attributes/tests/parents.rs102
-rw-r--r--third_party/rust/tracing-attributes/tests/ret.rs255
-rw-r--r--third_party/rust/tracing-attributes/tests/targets.rs97
-rw-r--r--third_party/rust/tracing-attributes/tests/ui.rs7
-rw-r--r--third_party/rust/tracing-attributes/tests/ui/async_instrument.rs46
-rw-r--r--third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr98
-rw-r--r--third_party/rust/tracing-core/.cargo-checksum.json1
-rw-r--r--third_party/rust/tracing-core/CHANGELOG.md495
-rw-r--r--third_party/rust/tracing-core/Cargo.toml66
-rw-r--r--third_party/rust/tracing-core/LICENSE25
-rw-r--r--third_party/rust/tracing-core/README.md121
-rw-r--r--third_party/rust/tracing-core/src/callsite.rs621
-rw-r--r--third_party/rust/tracing-core/src/dispatcher.rs1008
-rw-r--r--third_party/rust/tracing-core/src/event.rs128
-rw-r--r--third_party/rust/tracing-core/src/field.rs1263
-rw-r--r--third_party/rust/tracing-core/src/lazy.rs76
-rw-r--r--third_party/rust/tracing-core/src/lib.rs295
-rw-r--r--third_party/rust/tracing-core/src/metadata.rs1114
-rw-r--r--third_party/rust/tracing-core/src/parent.rs11
-rw-r--r--third_party/rust/tracing-core/src/span.rs341
-rw-r--r--third_party/rust/tracing-core/src/spin/LICENSE21
-rw-r--r--third_party/rust/tracing-core/src/spin/mod.rs7
-rw-r--r--third_party/rust/tracing-core/src/spin/mutex.rs118
-rw-r--r--third_party/rust/tracing-core/src/spin/once.rs158
-rw-r--r--third_party/rust/tracing-core/src/stdlib.rs78
-rw-r--r--third_party/rust/tracing-core/src/subscriber.rs870
-rw-r--r--third_party/rust/tracing-core/tests/common/mod.rs30
-rw-r--r--third_party/rust/tracing-core/tests/dispatch.rs56
-rw-r--r--third_party/rust/tracing-core/tests/global_dispatch.rs34
-rw-r--r--third_party/rust/tracing-core/tests/macros.rs48
-rw-r--r--third_party/rust/tracing/.cargo-checksum.json1
-rw-r--r--third_party/rust/tracing/CHANGELOG.md806
-rw-r--r--third_party/rust/tracing/Cargo.toml142
-rw-r--r--third_party/rust/tracing/LICENSE25
-rw-r--r--third_party/rust/tracing/README.md465
-rw-r--r--third_party/rust/tracing/benches/baseline.rs24
-rw-r--r--third_party/rust/tracing/benches/dispatch_get_clone.rs15
-rw-r--r--third_party/rust/tracing/benches/dispatch_get_ref.rs16
-rw-r--r--third_party/rust/tracing/benches/empty_span.rs43
-rw-r--r--third_party/rust/tracing/benches/enter_span.rs16
-rw-r--r--third_party/rust/tracing/benches/event.rs12
-rw-r--r--third_party/rust/tracing/benches/shared.rs160
-rw-r--r--third_party/rust/tracing/benches/span_fields.rs23
-rw-r--r--third_party/rust/tracing/benches/span_no_fields.rs13
-rw-r--r--third_party/rust/tracing/benches/span_repeated.rs20
-rw-r--r--third_party/rust/tracing/src/dispatcher.rs145
-rw-r--r--third_party/rust/tracing/src/field.rs170
-rw-r--r--third_party/rust/tracing/src/instrument.rs370
-rw-r--r--third_party/rust/tracing/src/level_filters.rs94
-rw-r--r--third_party/rust/tracing/src/lib.rs1115
-rw-r--r--third_party/rust/tracing/src/macros.rs2504
-rw-r--r--third_party/rust/tracing/src/span.rs1623
-rw-r--r--third_party/rust/tracing/src/stdlib.rs55
-rw-r--r--third_party/rust/tracing/src/subscriber.rs65
-rw-r--r--third_party/rust/tracing/tests/enabled.rs54
-rw-r--r--third_party/rust/tracing/tests/event.rs500
-rw-r--r--third_party/rust/tracing/tests/filter_caching_is_lexically_scoped.rs65
-rw-r--r--third_party/rust/tracing/tests/filters_are_not_reevaluated_for_the_same_span.rs70
-rw-r--r--third_party/rust/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs80
-rw-r--r--third_party/rust/tracing/tests/filters_dont_leak.rs81
-rw-r--r--third_party/rust/tracing/tests/future_send.rs22
-rw-r--r--third_party/rust/tracing/tests/macro_imports.rs23
-rw-r--r--third_party/rust/tracing/tests/macros.rs963
-rw-r--r--third_party/rust/tracing/tests/macros_incompatible_concat.rs24
-rw-r--r--third_party/rust/tracing/tests/macros_redefined_core.rs18
-rw-r--r--third_party/rust/tracing/tests/max_level_hint.rs37
-rw-r--r--third_party/rust/tracing/tests/multiple_max_level_hints.rs69
-rw-r--r--third_party/rust/tracing/tests/no_subscriber.rs15
-rw-r--r--third_party/rust/tracing/tests/register_callsite_deadlock.rs47
-rw-r--r--third_party/rust/tracing/tests/scoped_clobbers_default.rs35
-rw-r--r--third_party/rust/tracing/tests/span.rs825
-rw-r--r--third_party/rust/tracing/tests/subscriber.rs130
88 files changed, 22587 insertions, 0 deletions
diff --git a/third_party/rust/tracing-attributes/.cargo-checksum.json b/third_party/rust/tracing-attributes/.cargo-checksum.json
new file mode 100644
index 0000000000..e29c0854b7
--- /dev/null
+++ b/third_party/rust/tracing-attributes/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"7c292985e41b0fd9c89d32bd15594b76bb3109ff96177af7461d1a0d3ea48574","Cargo.toml":"1c272401b940ef2fd88638a6228af02c14e3d47d4b592ee5c445f7470a0d1763","LICENSE":"898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1","README.md":"aae710a2c0c4ade929a84f8f3d9f98fcb9ad1c1e9e52ae0b0393db9f353f6248","src/attr.rs":"4d26dad70c765fff3d4677ebe8e71b63599d67ceba5c48dbcb204d247b5394ce","src/expand.rs":"f070e38eb3526c4c50e98cfafb2c26e50c7170f27d0bd716838a29777c1174cd","src/lib.rs":"14803c868525f6ae95b846ce2f369a47d50b2befba336335354867cf2a1b2455","tests/async_fn.rs":"6ae845ab6c508f9f2d1ea7ec3855971e8cff85afdae326593089d0a53c9c6dcf","tests/destructuring.rs":"26b9800678bad09e06512a113a54556e2fac3ecb15a18dcccefe105fb8911c26","tests/err.rs":"3beb5f065e57a578825c383a56b9d64fb89794a508018bf36e16f113557909b8","tests/fields.rs":"3882bd4e744d6b492f59beac7475e8bf4ff4ca8ad85c6951c305a22c78e75fae","tests/follows_from.rs":"5bc856923e87b34e0558959149118238fe668ac621f1748cc444c21c90a86647","tests/instrument.rs":"e3a90f2aef0d2f56c2c25018e2fbacf518e90ef6810930941f86740279252d03","tests/levels.rs":"80ffb684163a4d28c69c40e31a82609ac02daf922086bab8247bca125aec3c69","tests/names.rs":"5afd6c4d526588bcea3141c130a45a21872956495b6868a01b44ddff57749827","tests/parents.rs":"673d3f81eed6ba433f685ec53fd007c5dd957b97d32499d7ea1537e1f289cb2e","tests/ret.rs":"083b4ca456d766c469b2fff7608b59524b422941e5c5e84f07c1ce0d7b345c7a","tests/targets.rs":"95ce1ce1e2d29794062c5b3429d91c1bfaba5813251d5d8440c12cb2db6e11bf","tests/ui.rs":"c73c70fe7371998df077862092f40df7210b13496e119ab4e657a1848e42ab30","tests/ui/async_instrument.rs":"00fcde05841e8f9f6cc6f9434f8cc4baed5cf6e3ca73e8faddccbdace14e9485","tests/ui/async_instrument.stderr":"6f0457b5cd035a9bc82f5e98fb6d3a74177336ec6a19ba2e7cb9dbf3e67c3aff"},"package":"4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"} \ No newline at end of file
diff --git a/third_party/rust/tracing-attributes/CHANGELOG.md b/third_party/rust/tracing-attributes/CHANGELOG.md
new file mode 100644
index 0000000000..42cb09b6a1
--- /dev/null
+++ b/third_party/rust/tracing-attributes/CHANGELOG.md
@@ -0,0 +1,327 @@
+# 0.1.23 (October 6, 2022)
+
+This release of `tracing-attributes` fixes a bug where compiler diagnostic spans
+for type errors in `#[instrument]`ed `async fn`s have the location of the
+`#[instrument]` attribute rather than the location of the actual error, and a
+bug where inner attributes in `#[instrument]`ed functions would cause a compiler
+error.
+### Fixed
+
+- Fix incorrect handling of inner attributes in `#[instrument]`ed functions ([#2307])
+- Add fake return to improve spans generated for type errors in `async fn`s ([#2270])
+- Updated `syn` dependency to fix compilation with `-Z minimal-versions`
+ ([#2246])
+
+Thanks to new contributors @compiler-errors and @e-nomem, as well as @CAD97, for
+contributing to this release!
+
+[#2307]: https://github.com/tokio-rs/tracing/pull/2307
+[#2270]: https://github.com/tokio-rs/tracing/pull/2270
+[#2246]: https://github.com/tokio-rs/tracing/pull/2246
+
+# 0.1.22 (July 1, 2022)
+
+This release fixes an issue where using the `err` or `ret` arguments to
+`#[instrument]` along with an overridden target, such as
+
+```rust
+#[instrument(target = "...", err, ret)]
+```
+
+would not propagate the overridden target to the events generated for
+errors/return values.
+
+### Fixed
+
+- Error and return value events generated by `#[instrument(err)]` or
+ `#[instrument(ret)]` not inheriting an overridden target ([#2184])
+- Incorrect default level in documentation ([#2119])
+
+Thanks to new contributor @tbraun96 for contributing to this release!
+
+[#2184]: https://github.com/tokio-rs/tracing/pull/2184
+[#2119]: https://github.com/tokio-rs/tracing/pull/2119
+
+# 0.1.21 (April 26, 2022)
+
+This release adds support for setting explicit parent and follows-from spans
+in the `#[instrument]` attribute.
+
+### Added
+
+- `#[instrument(follows_from = ...)]` argument for setting one or more
+ follows-from span ([#2093])
+- `#[instrument(parent = ...)]` argument for overriding the generated span's
+ parent ([#2091])
+
+### Fixed
+
+- Extra braces around `async` blocks in expanded code (causes a Clippy warning)
+ ([#2090])
+- Broken documentation links ([#2068], [#2077])
+
+Thanks to @jarrodldavis, @ben0x539, and new contributor @jswrenn for
+contributing to this release!
+
+
+[#2093]: https://github.com/tokio-rs/tracing/pull/2093
+[#2091]: https://github.com/tokio-rs/tracing/pull/2091
+[#2090]: https://github.com/tokio-rs/tracing/pull/2090
+[#2077]: https://github.com/tokio-rs/tracing/pull/2077
+[#2068]: https://github.com/tokio-rs/tracing/pull/2068
+
+# 0.1.20 (March 8, 2022)
+
+### Fixed
+
+- Compilation failure with `--minimal-versions` due to a too-permissive `syn`
+ dependency ([#1960])
+
+### Changed
+
+- Bumped minimum supported Rust version (MSRV) to 1.49.0 ([#1913])
+
+Thanks to new contributor @udoprog for contributing to this release!
+
+[#1960]: https://github.com/tokio-rs/tracing/pull/1960
+[#1913]: https://github.com/tokio-rs/tracing/pull/1913
+
+# 0.1.19 (February 3, 2022)
+
+This release introduces a new `#[instrument(ret)]` argument to emit an event
+with the return value of an instrumented function.
+
+### Added
+
+- `#[instrument(ret)]` to record the return value of a function ([#1716])
+- added `err(Debug)` argument to cause `#[instrument(err)]` to record errors
+ with `Debug` rather than `Display ([#1631])
+
+### Fixed
+
+- incorrect code generation for functions returning async blocks ([#1866])
+- incorrect diagnostics when using `rust-analyzer` ([#1634])
+
+Thanks to @Swatinem, @hkmatsumoto, @cynecx, and @ciuncan for contributing to
+this release!
+
+[#1716]: https://github.com/tokio-rs/tracing/pull/1716
+[#1631]: https://github.com/tokio-rs/tracing/pull/1631
+[#1634]: https://github.com/tokio-rs/tracing/pull/1634
+[#1866]: https://github.com/tokio-rs/tracing/pull/1866
+
+# 0.1.18 (October 5, 2021)
+
+This release fixes issues introduced in v0.1.17.
+
+### Fixed
+
+- fixed mismatched types compiler error that may occur when using
+ `#[instrument]` on an `async fn` that returns an `impl Trait` value that
+ includes a closure ([#1616])
+- fixed false positives for `clippy::suspicious_else_formatting` warnings due to
+ rust-lang/rust-clippy#7760 and rust-lang/rust-clippy#6249 ([#1617])
+- fixed `clippy::let_unit_value` lints when using `#[instrument]` ([#1614])
+
+[#1617]: https://github.com/tokio-rs/tracing/pull/1617
+[#1616]: https://github.com/tokio-rs/tracing/pull/1616
+[#1614]: https://github.com/tokio-rs/tracing/pull/1614
+
+# 0.1.17 (YANKED) (October 1, 2021)
+
+This release significantly improves performance when `#[instrument]`-generated
+spans are below the maximum enabled level.
+
+### Added
+
+- improve performance when skipping `#[instrument]`-generated spans below the
+ max level ([#1600], [#1605])
+
+Thanks to @oli-obk for contributing to this release!
+
+[#1600]: https://github.com/tokio-rs/tracing/pull/1600
+[#1605]: https://github.com/tokio-rs/tracing/pull/1605
+
+# 0.1.16 (September 13, 2021)
+
+This release adds a new `#[instrument(skip_all)]` option to skip recording *all*
+arguments to an instrumented function as fields. Additionally, it adds support
+for recording arguments that are `tracing` primitive types as typed values,
+rather than as `fmt::Debug`.
+
+### Added
+
+- add `skip_all` option to `#[instrument]` ([#1548])
+- record primitive types as primitive values rather than as `fmt::Debug`
+ ([#1378])
+- added support for `f64`s as typed values ([#1522])
+
+Thanks to @Folyd and @jsgf for contributing to this release!
+
+[#1548]: https://github.com/tokio-rs/tracing/pull/1548
+[#1378]: https://github.com/tokio-rs/tracing/pull/1378
+[#1522]: https://github.com/tokio-rs/tracing/pull/1524
+
+# 0.1.15 (March 12, 2021)
+
+### Fixed
+
+- `#[instrument]` on functions returning `Box::pin`ned futures incorrectly
+ skipping function bodies prior to returning a future ([#1297])
+
+Thanks to @nightmared for contributing to this release!
+
+[#1297]: https://github.com/tokio-rs/tracing/pull/1297
+
+# 0.1.14 (March 10, 2021)
+
+### Fixed
+
+- Compatibility between `#[instrument]` and `async-trait` v0.1.43 and newer
+ ([#1228])
+
+Thanks to @nightmared for lots of hard work on this fix!
+
+[#1228]: https://github.com/tokio-rs/tracing/pull/1228
+
+# 0.1.13 (February 17, 2021)
+
+### Fixed
+
+- Compiler error when using `#[instrument(err)]` on functions which return `impl
+ Trait` ([#1236])
+
+[#1236]: https://github.com/tokio-rs/tracing/pull/1236
+
+# 0.1.12 (February 4, 2021)
+
+### Fixed
+
+- Compiler error when using `#[instrument(err)]` on functions with mutable
+ parameters ([#1167])
+- Missing function visibility modifier when using `#[instrument]` with
+ `async-trait` ([#977])
+- Multiple documentation fixes and improvements ([#965], [#981], [#1215])
+
+### Changed
+
+- `tracing-futures` dependency is no longer required when using `#[instrument]`
+ on async functions ([#808])
+
+Thanks to @nagisa, @Txuritan, @TaKO8Ki, and @okready for contributing to this
+release!
+
+[#1167]: https://github.com/tokio-rs/tracing/pull/1167
+[#977]: https://github.com/tokio-rs/tracing/pull/977
+[#965]: https://github.com/tokio-rs/tracing/pull/965
+[#981]: https://github.com/tokio-rs/tracing/pull/981
+[#1215]: https://github.com/tokio-rs/tracing/pull/1215
+[#808]: https://github.com/tokio-rs/tracing/pull/808
+
+# 0.1.11 (August 18, 2020)
+
+### Fixed
+
+- Corrected wrong minimum supported Rust version note in docs (#941)
+- Removed unused `syn` features (#928)
+
+Thanks to new contributor @jhpratt for contributing to this release!
+
+# 0.1.10 (August 10, 2020)
+
+### Added
+
+- Support for using `self` in field expressions when instrumenting `async-trait`
+ functions (#875)
+- Several documentation improvements (#832, #897, #911, #913)
+
+Thanks to @anton-dutov and @nightmared for contributing to this release!
+
+# 0.1.9 (July 8, 2020)
+
+### Added
+
+- Support for arbitrary expressions as fields in `#[instrument]` (#672)
+
+### Changed
+
+- `#[instrument]` now emits a compiler warning when ignoring unrecognized
+ input (#672, #786)
+
+# 0.1.8 (May 13, 2020)
+
+### Added
+
+- Support for using `#[instrument]` on methods that are part of [`async-trait`]
+ trait implementations (#711)
+- Optional `#[instrument(err)]` argument to automatically emit an event if an
+ instrumented function returns `Err` (#637)
+
+Thanks to @ilana and @nightmared for contributing to this release!
+
+[`async-trait`]: https://crates.io/crates/async-trait
+
+# 0.1.7 (February 26, 2020)
+
+### Added
+
+- Support for adding arbitrary literal fields to spans generated by
+ `#[instrument]` (#569)
+- `#[instrument]` now emits a helpful compiler error when attempting to skip a
+ function parameter (#600)
+
+Thanks to @Kobzol for contributing to this release!
+
+# 0.1.6 (December 20, 2019)
+
+### Added
+
+- Updated documentation (#468)
+
+# 0.1.5 (October 22, 2019)
+
+### Added
+
+- Support for destructuring in arguments to `#[instrument]`ed functions (#397)
+- Generated field for `self` parameters when `#[instrument]`ing methods (#397)
+
+# 0.1.4 (September 26, 2019)
+
+### Added
+
+- Optional `skip` argument to `#[instrument]` for excluding function parameters
+ from generated spans (#359)
+
+# 0.1.3 (September 12, 2019)
+
+### Fixed
+
+- Fixed `#[instrument]`ed async functions not compiling on `nightly-2019-09-11`
+ or newer (#342)
+
+# 0.1.2 (August 19, 2019)
+
+### Changed
+
+- Updated `syn` and `quote` dependencies to 1.0 (#292)
+- Removed direct dependency on `proc-macro2` to avoid potential version
+ conflicts (#296)
+
+### Fixed
+
+- Outdated idioms in examples (#271, #273)
+
+# 0.1.1 (August 9, 2019)
+
+### Changed
+
+- Using the `#[instrument]` attribute on `async fn`s no longer requires a
+ feature flag (#258)
+
+### Fixed
+
+- The `#[instrument]` macro now works on generic functions (#262)
+
+# 0.1.0 (August 8, 2019)
+
+- Initial release
diff --git a/third_party/rust/tracing-attributes/Cargo.toml b/third_party/rust/tracing-attributes/Cargo.toml
new file mode 100644
index 0000000000..5639de0b3e
--- /dev/null
+++ b/third_party/rust/tracing-attributes/Cargo.toml
@@ -0,0 +1,91 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.49.0"
+name = "tracing-attributes"
+version = "0.1.23"
+authors = [
+ "Tokio Contributors <team@tokio.rs>",
+ "Eliza Weisman <eliza@buoyant.io>",
+ "David Barsky <dbarsky@amazon.com>",
+]
+description = """
+Procedural macro attributes for automatically instrumenting functions.
+"""
+homepage = "https://tokio.rs"
+readme = "README.md"
+keywords = [
+ "logging",
+ "tracing",
+ "macro",
+ "instrument",
+ "log",
+]
+categories = [
+ "development-tools::debugging",
+ "development-tools::profiling",
+ "asynchronous",
+]
+license = "MIT"
+repository = "https://github.com/tokio-rs/tracing"
+
+[lib]
+proc-macro = true
+
+[dependencies.proc-macro2]
+version = "1"
+
+[dependencies.quote]
+version = "1"
+
+[dependencies.syn]
+version = "1.0.98"
+features = [
+ "full",
+ "parsing",
+ "printing",
+ "visit",
+ "visit-mut",
+ "clone-impls",
+ "extra-traits",
+ "proc-macro",
+]
+default-features = false
+
+[dev-dependencies.async-trait]
+version = "0.1.56"
+
+[dev-dependencies.rustversion]
+version = "1.0.9"
+
+[dev-dependencies.tokio-test]
+version = "0.3.0"
+
+[dev-dependencies.tracing]
+version = "0.1.35"
+
+[dev-dependencies.tracing-core]
+version = "0.1.28"
+
+[dev-dependencies.tracing-subscriber]
+version = "0.3.0"
+features = ["env-filter"]
+
+[dev-dependencies.trybuild]
+version = "1.0.64"
+
+[features]
+async-await = []
+
+[badges.maintenance]
+status = "experimental"
diff --git a/third_party/rust/tracing-attributes/LICENSE b/third_party/rust/tracing-attributes/LICENSE
new file mode 100644
index 0000000000..cdb28b4b56
--- /dev/null
+++ b/third_party/rust/tracing-attributes/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2019 Tokio Contributors
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/tracing-attributes/README.md b/third_party/rust/tracing-attributes/README.md
new file mode 100644
index 0000000000..356b511f2a
--- /dev/null
+++ b/third_party/rust/tracing-attributes/README.md
@@ -0,0 +1,91 @@
+![Tracing — Structured, application-level diagnostics][splash]
+
+[splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg
+
+# tracing-attributes
+
+Macro attributes for application-level tracing.
+
+[![Crates.io][crates-badge]][crates-url]
+[![Documentation][docs-badge]][docs-url]
+[![Documentation (master)][docs-master-badge]][docs-master-url]
+[![MIT licensed][mit-badge]][mit-url]
+[![Build Status][actions-badge]][actions-url]
+[![Discord chat][discord-badge]][discord-url]
+
+[Documentation][docs-url] | [Chat][discord-url]
+
+[crates-badge]: https://img.shields.io/crates/v/tracing-attributes.svg
+[crates-url]: https://crates.io/crates/tracing-attributes
+[docs-badge]: https://docs.rs/tracing-attributes/badge.svg
+[docs-url]: https://docs.rs/tracing-attributes/0.1.23
+[docs-master-badge]: https://img.shields.io/badge/docs-master-blue
+[docs-master-url]: https://tracing-rs.netlify.com/tracing_attributes
+[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
+[mit-url]: LICENSE
+[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg
+[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI
+[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white
+[discord-url]: https://discord.gg/EeF3cQw
+
+## Overview
+
+[`tracing`] is a framework for instrumenting Rust programs to collect
+structured, event-based diagnostic information. This crate provides the
+`#[instrument]` attribute for automatically instrumenting functions using
+`tracing`.
+
+Note that this macro is also re-exported by the main `tracing` crate.
+
+*Compiler support: [requires `rustc` 1.49+][msrv]*
+
+[msrv]: #supported-rust-versions
+
+## Usage
+
+First, add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+tracing-attributes = "0.1.23"
+```
+
+
+This crate provides the `#[instrument]` attribute for instrumenting a function
+with a `tracing` [span]. For example:
+
+```rust
+use tracing_attributes::instrument;
+
+#[instrument]
+pub fn my_function(my_arg: usize) {
+ // ...
+}
+```
+
+[`tracing`]: https://crates.io/crates/tracing
+[span]: https://docs.rs/tracing/latest/tracing/span/index.html
+
+## Supported Rust Versions
+
+Tracing is built against the latest stable release. The minimum supported
+version is 1.49. The current Tracing version is not guaranteed to build on Rust
+versions earlier than the minimum supported version.
+
+Tracing follows the same compiler support policies as the rest of the Tokio
+project. The current stable Rust compiler and the three most recent minor
+versions before it will always be supported. For example, if the current stable
+compiler version is 1.45, the minimum supported version will not be increased
+past 1.42, three minor versions prior. Increasing the minimum supported compiler
+version is not considered a semver breaking change as long as doing so complies
+with this policy.
+
+## License
+
+This project is licensed under the [MIT license](LICENSE).
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Tokio by you, shall be licensed as MIT, without any additional
+terms or conditions.
diff --git a/third_party/rust/tracing-attributes/src/attr.rs b/third_party/rust/tracing-attributes/src/attr.rs
new file mode 100644
index 0000000000..ff875e1797
--- /dev/null
+++ b/third_party/rust/tracing-attributes/src/attr.rs
@@ -0,0 +1,413 @@
+use std::collections::HashSet;
+use syn::{punctuated::Punctuated, Expr, Ident, LitInt, LitStr, Path, Token};
+
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned, ToTokens};
+use syn::ext::IdentExt as _;
+use syn::parse::{Parse, ParseStream};
+
+#[derive(Clone, Default, Debug)]
+pub(crate) struct InstrumentArgs {
+ level: Option<Level>,
+ pub(crate) name: Option<LitStr>,
+ target: Option<LitStr>,
+ pub(crate) parent: Option<Expr>,
+ pub(crate) follows_from: Option<Expr>,
+ pub(crate) skips: HashSet<Ident>,
+ pub(crate) skip_all: bool,
+ pub(crate) fields: Option<Fields>,
+ pub(crate) err_mode: Option<FormatMode>,
+ pub(crate) ret_mode: Option<FormatMode>,
+ /// Errors describing any unrecognized parse inputs that we skipped.
+ parse_warnings: Vec<syn::Error>,
+}
+
+impl InstrumentArgs {
+ pub(crate) fn level(&self) -> impl ToTokens {
+ fn is_level(lit: &LitInt, expected: u64) -> bool {
+ match lit.base10_parse::<u64>() {
+ Ok(value) => value == expected,
+ Err(_) => false,
+ }
+ }
+
+ match &self.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 => quote!(tracing::Level::INFO),
+ }
+ }
+
+ pub(crate) fn target(&self) -> impl ToTokens {
+ if let Some(ref target) = self.target {
+ quote!(#target)
+ } else {
+ quote!(module_path!())
+ }
+ }
+
+ /// Generate "deprecation" warnings for any unrecognized attribute inputs
+ /// that we skipped.
+ ///
+ /// For backwards compatibility, we need to emit compiler warnings rather
+ /// than errors for unrecognized inputs. Generating a fake deprecation is
+ /// the only way to do this on stable Rust right now.
+ pub(crate) fn warnings(&self) -> impl ToTokens {
+ let warnings = self.parse_warnings.iter().map(|err| {
+ let msg = format!("found unrecognized input, {}", err);
+ let msg = LitStr::new(&msg, err.span());
+ // TODO(eliza): This is a bit of a hack, but it's just about the
+ // only way to emit warnings from a proc macro on stable Rust.
+ // Eventually, when the `proc_macro::Diagnostic` API stabilizes, we
+ // should definitely use that instead.
+ quote_spanned! {err.span()=>
+ #[warn(deprecated)]
+ {
+ #[deprecated(since = "not actually deprecated", note = #msg)]
+ const TRACING_INSTRUMENT_WARNING: () = ();
+ let _ = TRACING_INSTRUMENT_WARNING;
+ }
+ }
+ });
+ quote! {
+ { #(#warnings)* }
+ }
+ }
+}
+
+impl Parse for InstrumentArgs {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let mut args = Self::default();
+ while !input.is_empty() {
+ let lookahead = input.lookahead1();
+ if lookahead.peek(kw::name) {
+ if args.name.is_some() {
+ return Err(input.error("expected only a single `name` argument"));
+ }
+ let name = input.parse::<StrArg<kw::name>>()?.value;
+ args.name = Some(name);
+ } else if lookahead.peek(LitStr) {
+ // XXX: apparently we support names as either named args with an
+ // sign, _or_ as unnamed string literals. That's weird, but
+ // changing it is apparently breaking.
+ if args.name.is_some() {
+ return Err(input.error("expected only a single `name` argument"));
+ }
+ args.name = Some(input.parse()?);
+ } else if lookahead.peek(kw::target) {
+ if args.target.is_some() {
+ return Err(input.error("expected only a single `target` argument"));
+ }
+ let target = input.parse::<StrArg<kw::target>>()?.value;
+ args.target = Some(target);
+ } else if lookahead.peek(kw::parent) {
+ if args.target.is_some() {
+ return Err(input.error("expected only a single `parent` argument"));
+ }
+ let parent = input.parse::<ExprArg<kw::parent>>()?;
+ args.parent = Some(parent.value);
+ } else if lookahead.peek(kw::follows_from) {
+ if args.target.is_some() {
+ return Err(input.error("expected only a single `follows_from` argument"));
+ }
+ let follows_from = input.parse::<ExprArg<kw::follows_from>>()?;
+ args.follows_from = Some(follows_from.value);
+ } else if lookahead.peek(kw::level) {
+ if args.level.is_some() {
+ return Err(input.error("expected only a single `level` argument"));
+ }
+ args.level = Some(input.parse()?);
+ } else if lookahead.peek(kw::skip) {
+ if !args.skips.is_empty() {
+ return Err(input.error("expected only a single `skip` argument"));
+ }
+ if args.skip_all {
+ return Err(input.error("expected either `skip` or `skip_all` argument"));
+ }
+ let Skips(skips) = input.parse()?;
+ args.skips = skips;
+ } else if lookahead.peek(kw::skip_all) {
+ if args.skip_all {
+ return Err(input.error("expected only a single `skip_all` argument"));
+ }
+ if !args.skips.is_empty() {
+ return Err(input.error("expected either `skip` or `skip_all` argument"));
+ }
+ let _ = input.parse::<kw::skip_all>()?;
+ args.skip_all = true;
+ } else if lookahead.peek(kw::fields) {
+ if args.fields.is_some() {
+ return Err(input.error("expected only a single `fields` argument"));
+ }
+ args.fields = Some(input.parse()?);
+ } else if lookahead.peek(kw::err) {
+ let _ = input.parse::<kw::err>();
+ let mode = FormatMode::parse(input)?;
+ args.err_mode = Some(mode);
+ } else if lookahead.peek(kw::ret) {
+ let _ = input.parse::<kw::ret>()?;
+ let mode = FormatMode::parse(input)?;
+ args.ret_mode = Some(mode);
+ } else if lookahead.peek(Token![,]) {
+ let _ = input.parse::<Token![,]>()?;
+ } else {
+ // We found a token that we didn't expect!
+ // We want to emit warnings for these, rather than errors, so
+ // we'll add it to the list of unrecognized inputs we've seen so
+ // far and keep going.
+ args.parse_warnings.push(lookahead.error());
+ // Parse the unrecognized token tree to advance the parse
+ // stream, and throw it away so we can keep parsing.
+ let _ = input.parse::<proc_macro2::TokenTree>();
+ }
+ }
+ Ok(args)
+ }
+}
+
+struct StrArg<T> {
+ value: LitStr,
+ _p: std::marker::PhantomData<T>,
+}
+
+impl<T: Parse> Parse for StrArg<T> {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<T>()?;
+ let _ = input.parse::<Token![=]>()?;
+ let value = input.parse()?;
+ Ok(Self {
+ value,
+ _p: std::marker::PhantomData,
+ })
+ }
+}
+
+struct ExprArg<T> {
+ value: Expr,
+ _p: std::marker::PhantomData<T>,
+}
+
+impl<T: Parse> Parse for ExprArg<T> {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<T>()?;
+ let _ = input.parse::<Token![=]>()?;
+ let value = input.parse()?;
+ Ok(Self {
+ value,
+ _p: std::marker::PhantomData,
+ })
+ }
+}
+
+struct Skips(HashSet<Ident>);
+
+impl Parse for Skips {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<kw::skip>();
+ let content;
+ let _ = syn::parenthesized!(content in input);
+ let names: Punctuated<Ident, Token![,]> = content.parse_terminated(Ident::parse_any)?;
+ let mut skips = HashSet::new();
+ for name in names {
+ if skips.contains(&name) {
+ return Err(syn::Error::new(
+ name.span(),
+ "tried to skip the same field twice",
+ ));
+ } else {
+ skips.insert(name);
+ }
+ }
+ Ok(Self(skips))
+ }
+}
+
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub(crate) enum FormatMode {
+ Default,
+ Display,
+ Debug,
+}
+
+impl Default for FormatMode {
+ fn default() -> Self {
+ FormatMode::Default
+ }
+}
+
+impl Parse for FormatMode {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ if !input.peek(syn::token::Paren) {
+ return Ok(FormatMode::default());
+ }
+ let content;
+ let _ = syn::parenthesized!(content in input);
+ let maybe_mode: Option<Ident> = content.parse()?;
+ maybe_mode.map_or(Ok(FormatMode::default()), |ident| {
+ match ident.to_string().as_str() {
+ "Debug" => Ok(FormatMode::Debug),
+ "Display" => Ok(FormatMode::Display),
+ _ => Err(syn::Error::new(
+ ident.span(),
+ "unknown error mode, must be Debug or Display",
+ )),
+ }
+ })
+ }
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct Fields(pub(crate) Punctuated<Field, Token![,]>);
+
+#[derive(Clone, Debug)]
+pub(crate) struct Field {
+ pub(crate) name: Punctuated<Ident, Token![.]>,
+ pub(crate) value: Option<Expr>,
+ pub(crate) kind: FieldKind,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub(crate) enum FieldKind {
+ Debug,
+ Display,
+ Value,
+}
+
+impl Parse for Fields {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<kw::fields>();
+ let content;
+ let _ = syn::parenthesized!(content in input);
+ let fields: Punctuated<_, Token![,]> = content.parse_terminated(Field::parse)?;
+ Ok(Self(fields))
+ }
+}
+
+impl ToTokens for Fields {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ self.0.to_tokens(tokens)
+ }
+}
+
+impl Parse for Field {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let mut kind = FieldKind::Value;
+ if input.peek(Token![%]) {
+ input.parse::<Token![%]>()?;
+ kind = FieldKind::Display;
+ } else if input.peek(Token![?]) {
+ input.parse::<Token![?]>()?;
+ kind = FieldKind::Debug;
+ };
+ let name = Punctuated::parse_separated_nonempty_with(input, Ident::parse_any)?;
+ let value = if input.peek(Token![=]) {
+ input.parse::<Token![=]>()?;
+ if input.peek(Token![%]) {
+ input.parse::<Token![%]>()?;
+ kind = FieldKind::Display;
+ } else if input.peek(Token![?]) {
+ input.parse::<Token![?]>()?;
+ kind = FieldKind::Debug;
+ };
+ Some(input.parse()?)
+ } else {
+ None
+ };
+ Ok(Self { name, value, kind })
+ }
+}
+
+impl ToTokens for Field {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ if let Some(ref value) = self.value {
+ let name = &self.name;
+ let kind = &self.kind;
+ tokens.extend(quote! {
+ #name = #kind#value
+ })
+ } else if self.kind == FieldKind::Value {
+ // XXX(eliza): I don't like that fields without values produce
+ // empty fields rather than local variable shorthand...but,
+ // we've released a version where field names without values in
+ // `instrument` produce empty field values, so changing it now
+ // is a breaking change. agh.
+ let name = &self.name;
+ tokens.extend(quote!(#name = tracing::field::Empty))
+ } else {
+ self.kind.to_tokens(tokens);
+ self.name.to_tokens(tokens);
+ }
+ }
+}
+
+impl ToTokens for FieldKind {
+ fn to_tokens(&self, tokens: &mut TokenStream) {
+ match self {
+ FieldKind::Debug => tokens.extend(quote! { ? }),
+ FieldKind::Display => tokens.extend(quote! { % }),
+ _ => {}
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+enum Level {
+ Str(LitStr),
+ Int(LitInt),
+ Path(Path),
+}
+
+impl Parse for Level {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let _ = input.parse::<kw::level>()?;
+ let _ = input.parse::<Token![=]>()?;
+ let lookahead = input.lookahead1();
+ if lookahead.peek(LitStr) {
+ Ok(Self::Str(input.parse()?))
+ } else if lookahead.peek(LitInt) {
+ Ok(Self::Int(input.parse()?))
+ } else if lookahead.peek(Ident) {
+ Ok(Self::Path(input.parse()?))
+ } else {
+ Err(lookahead.error())
+ }
+ }
+}
+
+mod kw {
+ syn::custom_keyword!(fields);
+ syn::custom_keyword!(skip);
+ syn::custom_keyword!(skip_all);
+ syn::custom_keyword!(level);
+ syn::custom_keyword!(target);
+ syn::custom_keyword!(parent);
+ syn::custom_keyword!(follows_from);
+ syn::custom_keyword!(name);
+ syn::custom_keyword!(err);
+ syn::custom_keyword!(ret);
+}
diff --git a/third_party/rust/tracing-attributes/src/expand.rs b/third_party/rust/tracing-attributes/src/expand.rs
new file mode 100644
index 0000000000..7005b4423e
--- /dev/null
+++ b/third_party/rust/tracing-attributes/src/expand.rs
@@ -0,0 +1,814 @@
+use std::iter;
+
+use proc_macro2::TokenStream;
+use quote::{quote, quote_spanned, ToTokens};
+use syn::visit_mut::VisitMut;
+use syn::{
+ punctuated::Punctuated, spanned::Spanned, Block, Expr, ExprAsync, ExprCall, FieldPat, FnArg,
+ Ident, Item, ItemFn, Pat, PatIdent, PatReference, PatStruct, PatTuple, PatTupleStruct, PatType,
+ Path, ReturnType, Signature, Stmt, Token, Type, TypePath,
+};
+
+use crate::{
+ attr::{Field, Fields, FormatMode, InstrumentArgs},
+ MaybeItemFn, MaybeItemFnRef,
+};
+
+/// Given an existing function, generate an instrumented version of that function
+pub(crate) fn gen_function<'a, B: ToTokens + 'a>(
+ input: MaybeItemFnRef<'a, B>,
+ args: InstrumentArgs,
+ instrumented_function_name: &str,
+ self_type: Option<&TypePath>,
+) -> proc_macro2::TokenStream {
+ // these are needed ahead of time, as ItemFn contains the function body _and_
+ // isn't representable inside a quote!/quote_spanned! macro
+ // (Syn's ToTokens isn't implemented for ItemFn)
+ let MaybeItemFnRef {
+ outer_attrs,
+ inner_attrs,
+ vis,
+ sig,
+ block,
+ } = input;
+
+ let Signature {
+ output,
+ inputs: params,
+ unsafety,
+ asyncness,
+ constness,
+ abi,
+ ident,
+ generics:
+ syn::Generics {
+ params: gen_params,
+ where_clause,
+ ..
+ },
+ ..
+ } = sig;
+
+ let warnings = args.warnings();
+
+ let (return_type, return_span) = if let ReturnType::Type(_, return_type) = &output {
+ (erase_impl_trait(return_type), return_type.span())
+ } else {
+ // Point at function name if we don't have an explicit return type
+ (syn::parse_quote! { () }, ident.span())
+ };
+ // Install a fake return statement as the first thing in the function
+ // body, so that we eagerly infer that the return type is what we
+ // declared in the async fn signature.
+ // The `#[allow(..)]` is given because the return statement is
+ // unreachable, but does affect inference, so it needs to be written
+ // exactly that way for it to do its magic.
+ let fake_return_edge = quote_spanned! {return_span=>
+ #[allow(unreachable_code, clippy::diverging_sub_expression, clippy::let_unit_value)]
+ if false {
+ let __tracing_attr_fake_return: #return_type =
+ unreachable!("this is just for type inference, and is unreachable code");
+ return __tracing_attr_fake_return;
+ }
+ };
+ let block = quote! {
+ {
+ #fake_return_edge
+ #block
+ }
+ };
+
+ let body = gen_block(
+ &block,
+ params,
+ asyncness.is_some(),
+ args,
+ instrumented_function_name,
+ self_type,
+ );
+
+ quote!(
+ #(#outer_attrs) *
+ #vis #constness #unsafety #asyncness #abi fn #ident<#gen_params>(#params) #output
+ #where_clause
+ {
+ #(#inner_attrs) *
+ #warnings
+ #body
+ }
+ )
+}
+
+/// Instrument a block
+fn gen_block<B: ToTokens>(
+ block: &B,
+ params: &Punctuated<FnArg, Token![,]>,
+ async_context: bool,
+ mut args: InstrumentArgs,
+ instrumented_function_name: &str,
+ self_type: Option<&TypePath>,
+) -> proc_macro2::TokenStream {
+ // generate the span's name
+ let span_name = args
+ // did the user override the span's name?
+ .name
+ .as_ref()
+ .map(|name| quote!(#name))
+ .unwrap_or_else(|| quote!(#instrumented_function_name));
+
+ let level = args.level();
+
+ let follows_from = args.follows_from.iter();
+ let follows_from = quote! {
+ #(for cause in #follows_from {
+ __tracing_attr_span.follows_from(cause);
+ })*
+ };
+
+ // generate this inside a closure, so we can return early on errors.
+ let span = (|| {
+ // Pull out the arguments-to-be-skipped first, so we can filter results
+ // below.
+ let param_names: Vec<(Ident, (Ident, RecordType))> = params
+ .clone()
+ .into_iter()
+ .flat_map(|param| match param {
+ FnArg::Typed(PatType { pat, ty, .. }) => {
+ param_names(*pat, RecordType::parse_from_ty(&*ty))
+ }
+ FnArg::Receiver(_) => Box::new(iter::once((
+ Ident::new("self", param.span()),
+ RecordType::Debug,
+ ))),
+ })
+ // Little dance with new (user-exposed) names and old (internal)
+ // names of identifiers. That way, we could do the following
+ // even though async_trait (<=0.1.43) rewrites "self" as "_self":
+ // ```
+ // #[async_trait]
+ // impl Foo for FooImpl {
+ // #[instrument(skip(self))]
+ // async fn foo(&self, v: usize) {}
+ // }
+ // ```
+ .map(|(x, record_type)| {
+ // if we are inside a function generated by async-trait <=0.1.43, we need to
+ // take care to rewrite "_self" as "self" for 'user convenience'
+ if self_type.is_some() && x == "_self" {
+ (Ident::new("self", x.span()), (x, record_type))
+ } else {
+ (x.clone(), (x, record_type))
+ }
+ })
+ .collect();
+
+ for skip in &args.skips {
+ if !param_names.iter().map(|(user, _)| user).any(|y| y == skip) {
+ return quote_spanned! {skip.span()=>
+ compile_error!("attempting to skip non-existent parameter")
+ };
+ }
+ }
+
+ let target = args.target();
+
+ let parent = args.parent.iter();
+
+ // filter out skipped fields
+ let quoted_fields: Vec<_> = param_names
+ .iter()
+ .filter(|(param, _)| {
+ if args.skip_all || args.skips.contains(param) {
+ return false;
+ }
+
+ // If any parameters have the same name as a custom field, skip
+ // and allow them to be formatted by the custom field.
+ if let Some(ref fields) = args.fields {
+ fields.0.iter().all(|Field { ref name, .. }| {
+ let first = name.first();
+ first != name.last() || !first.iter().any(|name| name == &param)
+ })
+ } else {
+ true
+ }
+ })
+ .map(|(user_name, (real_name, record_type))| match record_type {
+ RecordType::Value => quote!(#user_name = #real_name),
+ RecordType::Debug => quote!(#user_name = tracing::field::debug(&#real_name)),
+ })
+ .collect();
+
+ // replace every use of a variable with its original name
+ if let Some(Fields(ref mut fields)) = args.fields {
+ let mut replacer = IdentAndTypesRenamer {
+ idents: param_names.into_iter().map(|(a, (b, _))| (a, b)).collect(),
+ types: Vec::new(),
+ };
+
+ // when async-trait <=0.1.43 is in use, replace instances
+ // of the "Self" type inside the fields values
+ if let Some(self_type) = self_type {
+ replacer.types.push(("Self", self_type.clone()));
+ }
+
+ for e in fields.iter_mut().filter_map(|f| f.value.as_mut()) {
+ syn::visit_mut::visit_expr_mut(&mut replacer, e);
+ }
+ }
+
+ let custom_fields = &args.fields;
+
+ quote!(tracing::span!(
+ target: #target,
+ #(parent: #parent,)*
+ #level,
+ #span_name,
+ #(#quoted_fields,)*
+ #custom_fields
+
+ ))
+ })();
+
+ let target = args.target();
+
+ let err_event = match args.err_mode {
+ Some(FormatMode::Default) | Some(FormatMode::Display) => {
+ Some(quote!(tracing::error!(target: #target, error = %e)))
+ }
+ Some(FormatMode::Debug) => Some(quote!(tracing::error!(target: #target, error = ?e))),
+ _ => None,
+ };
+
+ let ret_event = match args.ret_mode {
+ Some(FormatMode::Display) => Some(quote!(
+ tracing::event!(target: #target, #level, return = %x)
+ )),
+ Some(FormatMode::Default) | Some(FormatMode::Debug) => Some(quote!(
+ tracing::event!(target: #target, #level, return = ?x)
+ )),
+ _ => None,
+ };
+
+ // Generate the instrumented function body.
+ // If the function is an `async fn`, this will wrap it in an async block,
+ // which is `instrument`ed using `tracing-futures`. Otherwise, this will
+ // enter the span and then perform the rest of the body.
+ // If `err` is in args, instrument any resulting `Err`s.
+ // If `ret` is in args, instrument any resulting `Ok`s when the function
+ // returns `Result`s, otherwise instrument any resulting values.
+ if async_context {
+ let mk_fut = match (err_event, ret_event) {
+ (Some(err_event), Some(ret_event)) => quote_spanned!(block.span()=>
+ async move {
+ match async move #block.await {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => {
+ #ret_event;
+ Ok(x)
+ },
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ }
+ ),
+ (Some(err_event), None) => quote_spanned!(block.span()=>
+ async move {
+ match async move #block.await {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => Ok(x),
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ }
+ ),
+ (None, Some(ret_event)) => quote_spanned!(block.span()=>
+ async move {
+ let x = async move #block.await;
+ #ret_event;
+ x
+ }
+ ),
+ (None, None) => quote_spanned!(block.span()=>
+ async move #block
+ ),
+ };
+
+ return quote!(
+ let __tracing_attr_span = #span;
+ let __tracing_instrument_future = #mk_fut;
+ if !__tracing_attr_span.is_disabled() {
+ #follows_from
+ tracing::Instrument::instrument(
+ __tracing_instrument_future,
+ __tracing_attr_span
+ )
+ .await
+ } else {
+ __tracing_instrument_future.await
+ }
+ );
+ }
+
+ let span = quote!(
+ // These variables are left uninitialized and initialized only
+ // if the tracing level is statically enabled at this point.
+ // While the tracing level is also checked at span creation
+ // time, that will still create a dummy span, and a dummy guard
+ // and drop the dummy guard later. By lazily initializing these
+ // variables, Rust will generate a drop flag for them and thus
+ // only drop the guard if it was created. This creates code that
+ // is very straightforward for LLVM to optimize out if the tracing
+ // level is statically disabled, while not causing any performance
+ // regression in case the level is enabled.
+ let __tracing_attr_span;
+ let __tracing_attr_guard;
+ if tracing::level_enabled!(#level) {
+ __tracing_attr_span = #span;
+ #follows_from
+ __tracing_attr_guard = __tracing_attr_span.enter();
+ }
+ );
+
+ match (err_event, ret_event) {
+ (Some(err_event), Some(ret_event)) => quote_spanned! {block.span()=>
+ #span
+ #[allow(clippy::redundant_closure_call)]
+ match (move || #block)() {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => {
+ #ret_event;
+ Ok(x)
+ },
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ },
+ (Some(err_event), None) => quote_spanned!(block.span()=>
+ #span
+ #[allow(clippy::redundant_closure_call)]
+ match (move || #block)() {
+ #[allow(clippy::unit_arg)]
+ Ok(x) => Ok(x),
+ Err(e) => {
+ #err_event;
+ Err(e)
+ }
+ }
+ ),
+ (None, Some(ret_event)) => quote_spanned!(block.span()=>
+ #span
+ #[allow(clippy::redundant_closure_call)]
+ let x = (move || #block)();
+ #ret_event;
+ x
+ ),
+ (None, None) => quote_spanned!(block.span() =>
+ // Because `quote` produces a stream of tokens _without_ whitespace, the
+ // `if` and the block will appear directly next to each other. This
+ // generates a clippy lint about suspicious `if/else` formatting.
+ // Therefore, suppress the lint inside the generated code...
+ #[allow(clippy::suspicious_else_formatting)]
+ {
+ #span
+ // ...but turn the lint back on inside the function body.
+ #[warn(clippy::suspicious_else_formatting)]
+ #block
+ }
+ ),
+ }
+}
+
+/// Indicates whether a field should be recorded as `Value` or `Debug`.
+enum RecordType {
+ /// The field should be recorded using its `Value` implementation.
+ Value,
+ /// The field should be recorded using `tracing::field::debug()`.
+ Debug,
+}
+
+impl RecordType {
+ /// Array of primitive types which should be recorded as [RecordType::Value].
+ const TYPES_FOR_VALUE: &'static [&'static str] = &[
+ "bool",
+ "str",
+ "u8",
+ "i8",
+ "u16",
+ "i16",
+ "u32",
+ "i32",
+ "u64",
+ "i64",
+ "f32",
+ "f64",
+ "usize",
+ "isize",
+ "NonZeroU8",
+ "NonZeroI8",
+ "NonZeroU16",
+ "NonZeroI16",
+ "NonZeroU32",
+ "NonZeroI32",
+ "NonZeroU64",
+ "NonZeroI64",
+ "NonZeroUsize",
+ "NonZeroIsize",
+ "Wrapping",
+ ];
+
+ /// Parse `RecordType` from [Type] by looking up
+ /// the [RecordType::TYPES_FOR_VALUE] array.
+ fn parse_from_ty(ty: &Type) -> Self {
+ match ty {
+ Type::Path(TypePath { path, .. })
+ if path
+ .segments
+ .iter()
+ .last()
+ .map(|path_segment| {
+ let ident = path_segment.ident.to_string();
+ Self::TYPES_FOR_VALUE.iter().any(|&t| t == ident)
+ })
+ .unwrap_or(false) =>
+ {
+ RecordType::Value
+ }
+ Type::Reference(syn::TypeReference { elem, .. }) => RecordType::parse_from_ty(elem),
+ _ => RecordType::Debug,
+ }
+ }
+}
+
+fn param_names(pat: Pat, record_type: RecordType) -> Box<dyn Iterator<Item = (Ident, RecordType)>> {
+ match pat {
+ Pat::Ident(PatIdent { ident, .. }) => Box::new(iter::once((ident, record_type))),
+ Pat::Reference(PatReference { pat, .. }) => param_names(*pat, record_type),
+ // We can't get the concrete type of fields in the struct/tuple
+ // patterns by using `syn`. e.g. `fn foo(Foo { x, y }: Foo) {}`.
+ // Therefore, the struct/tuple patterns in the arguments will just
+ // always be recorded as `RecordType::Debug`.
+ Pat::Struct(PatStruct { fields, .. }) => Box::new(
+ fields
+ .into_iter()
+ .flat_map(|FieldPat { pat, .. }| param_names(*pat, RecordType::Debug)),
+ ),
+ Pat::Tuple(PatTuple { elems, .. }) => Box::new(
+ elems
+ .into_iter()
+ .flat_map(|p| param_names(p, RecordType::Debug)),
+ ),
+ Pat::TupleStruct(PatTupleStruct {
+ pat: PatTuple { elems, .. },
+ ..
+ }) => Box::new(
+ elems
+ .into_iter()
+ .flat_map(|p| param_names(p, RecordType::Debug)),
+ ),
+
+ // The above *should* cover all cases of irrefutable patterns,
+ // but we purposefully don't do any funny business here
+ // (such as panicking) because that would obscure rustc's
+ // much more informative error message.
+ _ => Box::new(iter::empty()),
+ }
+}
+
+/// The specific async code pattern that was detected
+enum AsyncKind<'a> {
+ /// Immediately-invoked async fn, as generated by `async-trait <= 0.1.43`:
+ /// `async fn foo<...>(...) {...}; Box::pin(foo<...>(...))`
+ Function(&'a ItemFn),
+ /// A function returning an async (move) block, optionally `Box::pin`-ed,
+ /// as generated by `async-trait >= 0.1.44`:
+ /// `Box::pin(async move { ... })`
+ Async {
+ async_expr: &'a ExprAsync,
+ pinned_box: bool,
+ },
+}
+
+pub(crate) struct AsyncInfo<'block> {
+ // statement that must be patched
+ source_stmt: &'block Stmt,
+ kind: AsyncKind<'block>,
+ self_type: Option<TypePath>,
+ input: &'block ItemFn,
+}
+
+impl<'block> AsyncInfo<'block> {
+ /// Get the AST of the inner function we need to hook, if it looks like a
+ /// manual future implementation.
+ ///
+ /// When we are given a function that returns a (pinned) future containing the
+ /// user logic, it is that (pinned) future that needs to be instrumented.
+ /// Were we to instrument its parent, we would only collect information
+ /// regarding the allocation of that future, and not its own span of execution.
+ ///
+ /// We inspect the block of the function to find if it matches any of the
+ /// following patterns:
+ ///
+ /// - Immediately-invoked async fn, as generated by `async-trait <= 0.1.43`:
+ /// `async fn foo<...>(...) {...}; Box::pin(foo<...>(...))`
+ ///
+ /// - A function returning an async (move) block, optionally `Box::pin`-ed,
+ /// as generated by `async-trait >= 0.1.44`:
+ /// `Box::pin(async move { ... })`
+ ///
+ /// We the return the statement that must be instrumented, along with some
+ /// other information.
+ /// 'gen_body' will then be able to use that information to instrument the
+ /// proper function/future.
+ ///
+ /// (this follows the approach suggested in
+ /// https://github.com/dtolnay/async-trait/issues/45#issuecomment-571245673)
+ pub(crate) fn from_fn(input: &'block ItemFn) -> Option<Self> {
+ // are we in an async context? If yes, this isn't a manual async-like pattern
+ if input.sig.asyncness.is_some() {
+ return None;
+ }
+
+ let block = &input.block;
+
+ // list of async functions declared inside the block
+ let inside_funs = block.stmts.iter().filter_map(|stmt| {
+ if let Stmt::Item(Item::Fn(fun)) = &stmt {
+ // If the function is async, this is a candidate
+ if fun.sig.asyncness.is_some() {
+ return Some((stmt, fun));
+ }
+ }
+ None
+ });
+
+ // last expression of the block: it determines the return value of the
+ // block, this is quite likely a `Box::pin` statement or an async block
+ let (last_expr_stmt, last_expr) = block.stmts.iter().rev().find_map(|stmt| {
+ if let Stmt::Expr(expr) = stmt {
+ Some((stmt, expr))
+ } else {
+ None
+ }
+ })?;
+
+ // is the last expression an async block?
+ if let Expr::Async(async_expr) = last_expr {
+ return Some(AsyncInfo {
+ source_stmt: last_expr_stmt,
+ kind: AsyncKind::Async {
+ async_expr,
+ pinned_box: false,
+ },
+ self_type: None,
+ input,
+ });
+ }
+
+ // is the last expression a function call?
+ let (outside_func, outside_args) = match last_expr {
+ Expr::Call(ExprCall { func, args, .. }) => (func, args),
+ _ => return None,
+ };
+
+ // is it a call to `Box::pin()`?
+ let path = match outside_func.as_ref() {
+ Expr::Path(path) => &path.path,
+ _ => return None,
+ };
+ if !path_to_string(path).ends_with("Box::pin") {
+ return None;
+ }
+
+ // Does the call take an argument? If it doesn't,
+ // it's not gonna compile anyway, but that's no reason
+ // to (try to) perform an out of bounds access
+ if outside_args.is_empty() {
+ return None;
+ }
+
+ // Is the argument to Box::pin an async block that
+ // captures its arguments?
+ if let Expr::Async(async_expr) = &outside_args[0] {
+ return Some(AsyncInfo {
+ source_stmt: last_expr_stmt,
+ kind: AsyncKind::Async {
+ async_expr,
+ pinned_box: true,
+ },
+ self_type: None,
+ input,
+ });
+ }
+
+ // Is the argument to Box::pin a function call itself?
+ let func = match &outside_args[0] {
+ Expr::Call(ExprCall { func, .. }) => func,
+ _ => return None,
+ };
+
+ // "stringify" the path of the function called
+ let func_name = match **func {
+ Expr::Path(ref func_path) => path_to_string(&func_path.path),
+ _ => return None,
+ };
+
+ // Was that function defined inside of the current block?
+ // If so, retrieve the statement where it was declared and the function itself
+ let (stmt_func_declaration, func) = inside_funs
+ .into_iter()
+ .find(|(_, fun)| fun.sig.ident == func_name)?;
+
+ // If "_self" is present as an argument, we store its type to be able to rewrite "Self" (the
+ // parameter type) with the type of "_self"
+ let mut self_type = None;
+ for arg in &func.sig.inputs {
+ if let FnArg::Typed(ty) = arg {
+ if let Pat::Ident(PatIdent { ref ident, .. }) = *ty.pat {
+ if ident == "_self" {
+ let mut ty = *ty.ty.clone();
+ // extract the inner type if the argument is "&self" or "&mut self"
+ if let Type::Reference(syn::TypeReference { elem, .. }) = ty {
+ ty = *elem;
+ }
+
+ if let Type::Path(tp) = ty {
+ self_type = Some(tp);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ Some(AsyncInfo {
+ source_stmt: stmt_func_declaration,
+ kind: AsyncKind::Function(func),
+ self_type,
+ input,
+ })
+ }
+
+ pub(crate) fn gen_async(
+ self,
+ args: InstrumentArgs,
+ instrumented_function_name: &str,
+ ) -> Result<proc_macro::TokenStream, syn::Error> {
+ // let's rewrite some statements!
+ let mut out_stmts: Vec<TokenStream> = self
+ .input
+ .block
+ .stmts
+ .iter()
+ .map(|stmt| stmt.to_token_stream())
+ .collect();
+
+ if let Some((iter, _stmt)) = self
+ .input
+ .block
+ .stmts
+ .iter()
+ .enumerate()
+ .find(|(_iter, stmt)| *stmt == self.source_stmt)
+ {
+ // instrument the future by rewriting the corresponding statement
+ out_stmts[iter] = match self.kind {
+ // `Box::pin(immediately_invoked_async_fn())`
+ AsyncKind::Function(fun) => {
+ let fun = MaybeItemFn::from(fun.clone());
+ gen_function(
+ fun.as_ref(),
+ args,
+ instrumented_function_name,
+ self.self_type.as_ref(),
+ )
+ }
+ // `async move { ... }`, optionally pinned
+ AsyncKind::Async {
+ async_expr,
+ pinned_box,
+ } => {
+ let instrumented_block = gen_block(
+ &async_expr.block,
+ &self.input.sig.inputs,
+ true,
+ args,
+ instrumented_function_name,
+ None,
+ );
+ let async_attrs = &async_expr.attrs;
+ if pinned_box {
+ quote! {
+ Box::pin(#(#async_attrs) * async move { #instrumented_block })
+ }
+ } else {
+ quote! {
+ #(#async_attrs) * async move { #instrumented_block }
+ }
+ }
+ }
+ };
+ }
+
+ let vis = &self.input.vis;
+ let sig = &self.input.sig;
+ let attrs = &self.input.attrs;
+ Ok(quote!(
+ #(#attrs) *
+ #vis #sig {
+ #(#out_stmts) *
+ }
+ )
+ .into())
+ }
+}
+
+// Return a path as a String
+fn path_to_string(path: &Path) -> String {
+ use std::fmt::Write;
+ // some heuristic to prevent too many allocations
+ let mut res = String::with_capacity(path.segments.len() * 5);
+ for i in 0..path.segments.len() {
+ write!(&mut res, "{}", path.segments[i].ident)
+ .expect("writing to a String should never fail");
+ if i < path.segments.len() - 1 {
+ res.push_str("::");
+ }
+ }
+ res
+}
+
+/// A visitor struct to replace idents and types in some piece
+/// of code (e.g. the "self" and "Self" tokens in user-supplied
+/// fields expressions when the function is generated by an old
+/// version of async-trait).
+struct IdentAndTypesRenamer<'a> {
+ types: Vec<(&'a str, TypePath)>,
+ idents: Vec<(Ident, Ident)>,
+}
+
+impl<'a> VisitMut for IdentAndTypesRenamer<'a> {
+ // we deliberately compare strings because we want to ignore the spans
+ // If we apply clippy's lint, the behavior changes
+ #[allow(clippy::cmp_owned)]
+ fn visit_ident_mut(&mut self, id: &mut Ident) {
+ for (old_ident, new_ident) in &self.idents {
+ if id.to_string() == old_ident.to_string() {
+ *id = new_ident.clone();
+ }
+ }
+ }
+
+ fn visit_type_mut(&mut self, ty: &mut Type) {
+ for (type_name, new_type) in &self.types {
+ if let Type::Path(TypePath { path, .. }) = ty {
+ if path_to_string(path) == *type_name {
+ *ty = Type::Path(new_type.clone());
+ }
+ }
+ }
+ }
+}
+
+// A visitor struct that replace an async block by its patched version
+struct AsyncTraitBlockReplacer<'a> {
+ block: &'a Block,
+ patched_block: Block,
+}
+
+impl<'a> VisitMut for AsyncTraitBlockReplacer<'a> {
+ fn visit_block_mut(&mut self, i: &mut Block) {
+ if i == self.block {
+ *i = self.patched_block.clone();
+ }
+ }
+}
+
+// Replaces any `impl Trait` with `_` so it can be used as the type in
+// a `let` statement's LHS.
+struct ImplTraitEraser;
+
+impl VisitMut for ImplTraitEraser {
+ fn visit_type_mut(&mut self, t: &mut Type) {
+ if let Type::ImplTrait(..) = t {
+ *t = syn::TypeInfer {
+ underscore_token: Token![_](t.span()),
+ }
+ .into();
+ } else {
+ syn::visit_mut::visit_type_mut(self, t);
+ }
+ }
+}
+
+fn erase_impl_trait(ty: &Type) -> Type {
+ let mut ty = ty.clone();
+ ImplTraitEraser.visit_type_mut(&mut ty);
+ ty
+}
diff --git a/third_party/rust/tracing-attributes/src/lib.rs b/third_party/rust/tracing-attributes/src/lib.rs
new file mode 100644
index 0000000000..f5974e4e52
--- /dev/null
+++ b/third_party/rust/tracing-attributes/src/lib.rs
@@ -0,0 +1,677 @@
+//! A procedural macro attribute for instrumenting functions with [`tracing`].
+//!
+//! [`tracing`] is a framework for instrumenting Rust programs to collect
+//! structured, event-based diagnostic information. This crate provides the
+//! [`#[instrument]`][instrument] procedural macro attribute.
+//!
+//! Note that this macro is also re-exported by the main `tracing` crate.
+//!
+//! *Compiler support: [requires `rustc` 1.49+][msrv]*
+//!
+//! [msrv]: #supported-rust-versions
+//!
+//! ## Usage
+//!
+//! First, add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! tracing-attributes = "0.1.23"
+//! ```
+//!
+//! The [`#[instrument]`][instrument] attribute can now be added to a function
+//! to automatically create and enter `tracing` [span] when that function is
+//! called. For example:
+//!
+//! ```
+//! use tracing_attributes::instrument;
+//!
+//! #[instrument]
+//! pub fn my_function(my_arg: usize) {
+//! // ...
+//! }
+//!
+//! # fn main() {}
+//! ```
+//!
+//! [`tracing`]: https://crates.io/crates/tracing
+//! [span]: https://docs.rs/tracing/latest/tracing/span/index.html
+//! [instrument]: macro@self::instrument
+//!
+//! ## Supported Rust Versions
+//!
+//! Tracing is built against the latest stable release. The minimum supported
+//! version is 1.49. The current Tracing version is not guaranteed to build on
+//! Rust versions earlier than the minimum supported version.
+//!
+//! Tracing follows the same compiler support policies as the rest of the Tokio
+//! project. The current stable Rust compiler and the three most recent minor
+//! versions before it will always be supported. For example, if the current
+//! stable compiler version is 1.45, the minimum supported version will not be
+//! increased past 1.42, three minor versions prior. Increasing the minimum
+//! supported compiler version is not considered a semver breaking change as
+//! long as doing so complies with this policy.
+//!
+#![doc(html_root_url = "https://docs.rs/tracing-attributes/0.1.23")]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
+ issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
+)]
+#![cfg_attr(docsrs, deny(rustdoc::broken_intra_doc_links))]
+#![warn(
+ missing_debug_implementations,
+ missing_docs,
+ rust_2018_idioms,
+ unreachable_pub,
+ bad_style,
+ const_err,
+ dead_code,
+ improper_ctypes,
+ non_shorthand_field_patterns,
+ no_mangle_generic_items,
+ overflowing_literals,
+ path_statements,
+ patterns_in_fns_without_body,
+ private_in_public,
+ unconditional_recursion,
+ unused_allocation,
+ unused_comparisons,
+ unused_parens,
+ while_true
+)]
+// TODO: once `tracing` bumps its MSRV to 1.42, remove this allow.
+#![allow(unused)]
+extern crate proc_macro;
+
+use proc_macro2::TokenStream;
+use quote::ToTokens;
+use syn::parse::{Parse, ParseStream};
+use syn::{Attribute, ItemFn, Signature, Visibility};
+
+mod attr;
+mod expand;
+/// Instruments a function to create and enter a `tracing` [span] every time
+/// the function is called.
+///
+/// Unless overriden, a span with the [`INFO`] [level] will be generated.
+/// The generated span's name will be the name of the function.
+/// By default, all arguments to the function are included as fields on the
+/// span. Arguments that are `tracing` [primitive types] implementing the
+/// [`Value` trait] will be recorded as fields of that type. Types which do
+/// not implement `Value` will be recorded using [`std::fmt::Debug`].
+///
+/// [primitive types]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html#foreign-impls
+/// [`Value` trait]: https://docs.rs/tracing/latest/tracing/field/trait.Value.html.
+///
+/// # Overriding Span Attributes
+///
+/// To change the [name] of the generated span, add a `name` argument to the
+/// `#[instrument]` macro, followed by an equals sign and a string literal. For
+/// example:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+///
+/// // The generated span's name will be "my_span" rather than "my_function".
+/// #[instrument(name = "my_span")]
+/// pub fn my_function() {
+/// // ... do something incredibly interesting and important ...
+/// }
+/// ```
+///
+/// To override the [target] of the generated span, add a `target` argument to
+/// the `#[instrument]` macro, followed by an equals sign and a string literal
+/// for the new target. The [module path] is still recorded separately. For
+/// example:
+///
+/// ```
+/// pub mod my_module {
+/// # use tracing_attributes::instrument;
+/// // The generated span's target will be "my_crate::some_special_target",
+/// // rather than "my_crate::my_module".
+/// #[instrument(target = "my_crate::some_special_target")]
+/// pub fn my_function() {
+/// // ... all kinds of neat code in here ...
+/// }
+/// }
+/// ```
+///
+/// Finally, to override the [level] of the generated span, add a `level`
+/// argument, followed by an equals sign and a string literal with the name of
+/// the desired level. Level names are not case sensitive. For example:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// // The span's level will be TRACE rather than INFO.
+/// #[instrument(level = "trace")]
+/// pub fn my_function() {
+/// // ... I have written a truly marvelous implementation of this function,
+/// // which this example is too narrow to contain ...
+/// }
+/// ```
+///
+/// # Skipping Fields
+///
+/// To skip recording one or more arguments to a function or method, pass
+/// the argument's name inside the `skip()` argument on the `#[instrument]`
+/// macro. This can be used when an argument to an instrumented function does
+/// not implement [`fmt::Debug`], or to exclude an argument with a verbose or
+/// costly `Debug` implementation. Note that:
+///
+/// - multiple argument names can be passed to `skip`.
+/// - arguments passed to `skip` do _not_ need to implement `fmt::Debug`.
+///
+/// You can also use `skip_all` to skip all arguments.
+///
+/// ## Examples
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// # use std::collections::HashMap;
+/// // This type doesn't implement `fmt::Debug`!
+/// struct NonDebug;
+///
+/// // `arg` will be recorded, while `non_debug` will not.
+/// #[instrument(skip(non_debug))]
+/// fn my_function(arg: usize, non_debug: NonDebug) {
+/// // ...
+/// }
+///
+/// // These arguments are huge
+/// #[instrument(skip_all)]
+/// fn my_big_data_function(large: Vec<u8>, also_large: HashMap<String, String>) {
+/// // ...
+/// }
+/// ```
+///
+/// Skipping the `self` parameter:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[derive(Debug)]
+/// struct MyType {
+/// data: Vec<u8>, // Suppose this buffer is often quite long...
+/// }
+///
+/// impl MyType {
+/// // Suppose we don't want to print an entire kilobyte of `data`
+/// // every time this is called...
+/// #[instrument(skip(self))]
+/// pub fn my_method(&mut self, an_interesting_argument: usize) {
+/// // ... do something (hopefully, using all that `data`!)
+/// }
+/// }
+/// ```
+///
+/// # Adding Fields
+///
+/// Additional fields (key-value pairs with arbitrary data) may be added to the
+/// generated span using the `fields` argument on the `#[instrument]` macro. Any
+/// Rust expression can be used as a field value in this manner. These
+/// expressions will be evaluated at the beginning of the function's body, so
+/// arguments to the function may be used in these expressions. Field names may
+/// also be specified *without* values. Doing so will result in an [empty field]
+/// whose value may be recorded later within the function body.
+///
+/// This supports the same [field syntax] as the `span!` and `event!` macros.
+///
+/// Note that overlap between the names of fields and (non-skipped) arguments
+/// will result in a compile error.
+///
+/// ## Examples
+///
+/// Adding a new field based on the value of an argument:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+///
+/// // This will record a field named "i" with the value of `i` *and* a field
+/// // named "next" with the value of `i` + 1.
+/// #[instrument(fields(next = i + 1))]
+/// pub fn my_function(i: usize) {
+/// // ...
+/// }
+/// ```
+///
+/// Recording specific properties of a struct as their own fields:
+///
+/// ```
+/// # mod http {
+/// # pub struct Error;
+/// # pub struct Response<B> { pub(super) _b: std::marker::PhantomData<B> }
+/// # pub struct Request<B> { _b: B }
+/// # impl<B> std::fmt::Debug for Request<B> {
+/// # fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+/// # f.pad("request")
+/// # }
+/// # }
+/// # impl<B> Request<B> {
+/// # pub fn uri(&self) -> &str { "fake" }
+/// # pub fn method(&self) -> &str { "GET" }
+/// # }
+/// # }
+/// # use tracing_attributes::instrument;
+///
+/// // This will record the request's URI and HTTP method as their own separate
+/// // fields.
+/// #[instrument(fields(http.uri = req.uri(), http.method = req.method()))]
+/// pub fn handle_request<B>(req: http::Request<B>) -> http::Response<B> {
+/// // ... handle the request ...
+/// # http::Response { _b: std::marker::PhantomData }
+/// }
+/// ```
+///
+/// This can be used in conjunction with `skip` or `skip_all` to record only
+/// some fields of a struct:
+/// ```
+/// # use tracing_attributes::instrument;
+/// // Remember the struct with the very large `data` field from the earlier
+/// // example? Now it also has a `name`, which we might want to include in
+/// // our span.
+/// #[derive(Debug)]
+/// struct MyType {
+/// name: &'static str,
+/// data: Vec<u8>,
+/// }
+///
+/// impl MyType {
+/// // This will skip the `data` field, but will include `self.name`,
+/// // formatted using `fmt::Display`.
+/// #[instrument(skip(self), fields(self.name = %self.name))]
+/// pub fn my_method(&mut self, an_interesting_argument: usize) {
+/// // ... do something (hopefully, using all that `data`!)
+/// }
+/// }
+/// ```
+///
+/// Adding an empty field to be recorded later:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+///
+/// // This function does a very interesting and important mathematical calculation.
+/// // Suppose we want to record both the inputs to the calculation *and* its result...
+/// #[instrument(fields(result))]
+/// pub fn do_calculation(input_1: usize, input_2: usize) -> usize {
+/// // Rerform the calculation.
+/// let result = input_1 + input_2;
+///
+/// // Record the result as part of the current span.
+/// tracing::Span::current().record("result", &result);
+///
+/// // Now, the result will also be included on this event!
+/// tracing::info!("calculation complete!");
+///
+/// // ... etc ...
+/// # 0
+/// }
+/// ```
+///
+/// # Examples
+///
+/// Instrumenting a function:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument]
+/// pub fn my_function(my_arg: usize) {
+/// // This event will be recorded inside a span named `my_function` with the
+/// // field `my_arg`.
+/// tracing::info!("inside my_function!");
+/// // ...
+/// }
+/// ```
+/// Setting the level for the generated span:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(level = "debug")]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// Overriding the generated span's name:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(name = "my_name")]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// Overriding the generated span's target:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(target = "my_target")]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// Overriding the generated span's parent:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(parent = None)]
+/// pub fn my_function() {
+/// // ...
+/// }
+/// ```
+/// ```
+/// # use tracing_attributes::instrument;
+/// // A struct which owns a span handle.
+/// struct MyStruct
+/// {
+/// span: tracing::Span
+/// }
+///
+/// impl MyStruct
+/// {
+/// // Use the struct's `span` field as the parent span
+/// #[instrument(parent = &self.span, skip(self))]
+/// fn my_method(&self) {}
+/// }
+/// ```
+/// Specifying [`follows_from`] relationships:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(follows_from = causes)]
+/// pub fn my_function(causes: &[tracing::Id]) {
+/// // ...
+/// }
+/// ```
+/// Any expression of type `impl IntoIterator<Item = impl Into<Option<Id>>>`
+/// may be provided to `follows_from`; e.g.:
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(follows_from = [cause])]
+/// pub fn my_function(cause: &tracing::span::EnteredSpan) {
+/// // ...
+/// }
+/// ```
+///
+///
+/// To skip recording an argument, pass the argument's name to the `skip`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// struct NonDebug;
+///
+/// #[instrument(skip(non_debug))]
+/// fn my_function(arg: usize, non_debug: NonDebug) {
+/// // ...
+/// }
+/// ```
+///
+/// To add an additional context to the span, pass key-value pairs to `fields`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(fields(foo="bar", id=1, show=true))]
+/// fn my_function(arg: usize) {
+/// // ...
+/// }
+/// ```
+///
+/// Adding the `ret` argument to `#[instrument]` will emit an event with the function's
+/// return value when the function returns:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(ret)]
+/// fn my_function() -> i32 {
+/// 42
+/// }
+/// ```
+/// The return value event will have the same level as the span generated by `#[instrument]`.
+/// By default, this will be [`INFO`], but if the level is overridden, the event will be at the same
+/// level.
+///
+/// **Note**: if the function returns a `Result<T, E>`, `ret` will record returned values if and
+/// only if the function returns [`Result::Ok`].
+///
+/// By default, returned values will be recorded using their [`std::fmt::Debug`] implementations.
+/// If a returned value implements [`std::fmt::Display`], it can be recorded using its `Display`
+/// implementation instead, by writing `ret(Display)`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(ret(Display))]
+/// fn my_function() -> i32 {
+/// 42
+/// }
+/// ```
+///
+/// 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)`:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(err(Debug))]
+/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
+/// Ok(())
+/// }
+/// ```
+///
+/// If a `target` is specified, both the `ret` and `err` arguments will emit outputs to
+/// the declared target (or the default channel if `target` is not specified).
+///
+/// The `ret` and `err` arguments can be combined in order to record an event if a
+/// function returns [`Result::Ok`] or [`Result::Err`]:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument(err, ret)]
+/// fn my_function(arg: usize) -> Result<(), std::io::Error> {
+/// Ok(())
+/// }
+/// ```
+///
+/// `async fn`s may also be instrumented:
+///
+/// ```
+/// # use tracing_attributes::instrument;
+/// #[instrument]
+/// pub async fn my_function() -> Result<(), ()> {
+/// // ...
+/// # Ok(())
+/// }
+/// ```
+///
+/// It also works with [async-trait](https://crates.io/crates/async-trait)
+/// (a crate that allows defining async functions in traits,
+/// something not currently possible in Rust),
+/// and hopefully most libraries that exhibit similar behaviors:
+///
+/// ```
+/// # use tracing::instrument;
+/// use async_trait::async_trait;
+///
+/// #[async_trait]
+/// pub trait Foo {
+/// async fn foo(&self, arg: usize);
+/// }
+///
+/// #[derive(Debug)]
+/// struct FooImpl(usize);
+///
+/// #[async_trait]
+/// impl Foo for FooImpl {
+/// #[instrument(fields(value = self.0, tmp = std::any::type_name::<Self>()))]
+/// async fn foo(&self, arg: usize) {}
+/// }
+/// ```
+///
+/// Note than on `async-trait` <= 0.1.43, references to the `Self`
+/// type inside the `fields` argument were only allowed when the instrumented
+/// function is a method (i.e., the function receives `self` as an argument).
+/// For example, this *used to not work* because the instrument function
+/// didn't receive `self`:
+/// ```
+/// # use tracing::instrument;
+/// use async_trait::async_trait;
+///
+/// #[async_trait]
+/// pub trait Bar {
+/// async fn bar();
+/// }
+///
+/// #[derive(Debug)]
+/// struct BarImpl(usize);
+///
+/// #[async_trait]
+/// impl Bar for BarImpl {
+/// #[instrument(fields(tmp = std::any::type_name::<Self>()))]
+/// async fn bar() {}
+/// }
+/// ```
+/// Instead, you should manually rewrite any `Self` types as the type for
+/// which you implement the trait: `#[instrument(fields(tmp = std::any::type_name::<Bar>()))]`
+/// (or maybe you can just bump `async-trait`).
+///
+/// [span]: https://docs.rs/tracing/latest/tracing/span/index.html
+/// [name]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.name
+/// [target]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.target
+/// [level]: https://docs.rs/tracing/latest/tracing/struct.Level.html
+/// [module path]: https://docs.rs/tracing/latest/tracing/struct.Metadata.html#method.module_path
+/// [`INFO`]: https://docs.rs/tracing/latest/tracing/struct.Level.html#associatedconstant.INFO
+/// [empty field]: https://docs.rs/tracing/latest/tracing/field/struct.Empty.html
+/// [field syntax]: https://docs.rs/tracing/latest/tracing/#recording-fields
+/// [`follows_from`]: https://docs.rs/tracing/latest/tracing/struct.Span.html#method.follows_from
+/// [`tracing`]: https://github.com/tokio-rs/tracing
+/// [`fmt::Debug`]: std::fmt::Debug
+#[proc_macro_attribute]
+pub fn instrument(
+ args: proc_macro::TokenStream,
+ item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+ let args = syn::parse_macro_input!(args as attr::InstrumentArgs);
+ // Cloning a `TokenStream` is cheap since it's reference counted internally.
+ instrument_precise(args.clone(), item.clone())
+ .unwrap_or_else(|_err| instrument_speculative(args, item))
+}
+
+/// Instrument the function, without parsing the function body (instead using the raw tokens).
+fn instrument_speculative(
+ args: attr::InstrumentArgs,
+ item: proc_macro::TokenStream,
+) -> proc_macro::TokenStream {
+ let input = syn::parse_macro_input!(item as MaybeItemFn);
+ let instrumented_function_name = input.sig.ident.to_string();
+ expand::gen_function(
+ input.as_ref(),
+ args,
+ instrumented_function_name.as_str(),
+ None,
+ )
+ .into()
+}
+
+/// Instrument the function, by fully parsing the function body,
+/// which allows us to rewrite some statements related to async-like patterns.
+fn instrument_precise(
+ args: attr::InstrumentArgs,
+ item: proc_macro::TokenStream,
+) -> Result<proc_macro::TokenStream, syn::Error> {
+ let input = syn::parse::<ItemFn>(item)?;
+ let instrumented_function_name = input.sig.ident.to_string();
+
+ // check for async_trait-like patterns in the block, and instrument
+ // the future instead of the wrapper
+ if let Some(async_like) = expand::AsyncInfo::from_fn(&input) {
+ return async_like.gen_async(args, instrumented_function_name.as_str());
+ }
+
+ let input = MaybeItemFn::from(input);
+
+ Ok(expand::gen_function(
+ input.as_ref(),
+ args,
+ instrumented_function_name.as_str(),
+ None,
+ )
+ .into())
+}
+
+/// This is a more flexible/imprecise `ItemFn` type,
+/// which's block is just a `TokenStream` (it may contain invalid code).
+#[derive(Debug, Clone)]
+struct MaybeItemFn {
+ outer_attrs: Vec<Attribute>,
+ inner_attrs: Vec<Attribute>,
+ vis: Visibility,
+ sig: Signature,
+ block: TokenStream,
+}
+
+impl MaybeItemFn {
+ fn as_ref(&self) -> MaybeItemFnRef<'_, TokenStream> {
+ MaybeItemFnRef {
+ outer_attrs: &self.outer_attrs,
+ inner_attrs: &self.inner_attrs,
+ vis: &self.vis,
+ sig: &self.sig,
+ block: &self.block,
+ }
+ }
+}
+
+/// This parses a `TokenStream` into a `MaybeItemFn`
+/// (just like `ItemFn`, but skips parsing the body).
+impl Parse for MaybeItemFn {
+ fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+ let outer_attrs = input.call(Attribute::parse_outer)?;
+ let vis: Visibility = input.parse()?;
+ let sig: Signature = input.parse()?;
+ let inner_attrs = input.call(Attribute::parse_inner)?;
+ let block: TokenStream = input.parse()?;
+ Ok(Self {
+ outer_attrs,
+ inner_attrs,
+ vis,
+ sig,
+ block,
+ })
+ }
+}
+
+impl From<ItemFn> for MaybeItemFn {
+ fn from(
+ ItemFn {
+ attrs,
+ vis,
+ sig,
+ block,
+ }: ItemFn,
+ ) -> Self {
+ let (outer_attrs, inner_attrs) = attrs
+ .into_iter()
+ .partition(|attr| attr.style == syn::AttrStyle::Outer);
+ Self {
+ outer_attrs,
+ inner_attrs,
+ vis,
+ sig,
+ block: block.to_token_stream(),
+ }
+ }
+}
+
+/// A generic reference type for `MaybeItemFn`,
+/// that takes a generic block type `B` that implements `ToTokens` (eg. `TokenStream`, `Block`).
+#[derive(Debug, Clone)]
+struct MaybeItemFnRef<'a, B: ToTokens> {
+ outer_attrs: &'a Vec<Attribute>,
+ inner_attrs: &'a Vec<Attribute>,
+ vis: &'a Visibility,
+ sig: &'a Signature,
+ block: &'a B,
+}
diff --git a/third_party/rust/tracing-attributes/tests/async_fn.rs b/third_party/rust/tracing-attributes/tests/async_fn.rs
new file mode 100644
index 0000000000..c89963672c
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/async_fn.rs
@@ -0,0 +1,462 @@
+use tracing_mock::*;
+
+use std::convert::Infallible;
+use std::{future::Future, pin::Pin, sync::Arc};
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+
+#[instrument]
+async fn test_async_fn(polls: usize) -> Result<(), ()> {
+ let future = PollN::new_ok(polls);
+ tracing::trace!(awaiting = true);
+ future.await
+}
+
+// Reproduces a compile error when returning an `impl Trait` from an
+// instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615)
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument]
+async fn test_ret_impl_trait(n: i32) -> Result<impl Iterator<Item = i32>, ()> {
+ let n = n;
+ Ok((0..10).filter(move |x| *x < n))
+}
+
+// Reproduces a compile error when returning an `impl Trait` from an
+// instrumented async fn (see https://github.com/tokio-rs/tracing/issues/1615)
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument(err)]
+async fn test_ret_impl_trait_err(n: i32) -> Result<impl Iterator<Item = i32>, &'static str> {
+ Ok((0..10).filter(move |x| *x < n))
+}
+
+#[instrument]
+async fn test_async_fn_empty() {}
+
+// Reproduces a compile error when an instrumented function body contains inner
+// attributes (https://github.com/tokio-rs/tracing/issues/2294).
+#[deny(unused_variables)]
+#[instrument]
+async fn repro_async_2294() {
+ #![allow(unused_variables)]
+ let i = 42;
+}
+
+// Reproduces https://github.com/tokio-rs/tracing/issues/1613
+#[instrument]
+// LOAD-BEARING `#[rustfmt::skip]`! This is necessary to reproduce the bug;
+// with the rustfmt-generated formatting, the lint will not be triggered!
+#[rustfmt::skip]
+#[deny(clippy::suspicious_else_formatting)]
+async fn repro_1613(var: bool) {
+ println!(
+ "{}",
+ if var { "true" } else { "false" }
+ );
+}
+
+// Reproduces https://github.com/tokio-rs/tracing/issues/1613
+// and https://github.com/rust-lang/rust-clippy/issues/7760
+#[instrument]
+#[deny(clippy::suspicious_else_formatting)]
+async fn repro_1613_2() {
+ // hello world
+ // else
+}
+
+// Reproduces https://github.com/tokio-rs/tracing/issues/1831
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument]
+#[deny(unused_braces)]
+fn repro_1831() -> Pin<Box<dyn Future<Output = ()>>> {
+ Box::pin(async move {})
+}
+
+// This replicates the pattern used to implement async trait methods on nightly using the
+// `type_alias_impl_trait` feature
+#[allow(dead_code)] // this is just here to test whether it compiles.
+#[instrument(ret, err)]
+#[deny(unused_braces)]
+#[allow(clippy::manual_async_fn)]
+fn repro_1831_2() -> impl Future<Output = Result<(), Infallible>> {
+ async { Ok(()) }
+}
+
+#[test]
+fn async_fn_only_enters_for_polls() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("test_async_fn"))
+ .enter(span::mock().named("test_async_fn"))
+ .event(event::mock().with_fields(field::mock("awaiting").with_value(&true)))
+ .exit(span::mock().named("test_async_fn"))
+ .enter(span::mock().named("test_async_fn"))
+ .exit(span::mock().named("test_async_fn"))
+ .drop_span(span::mock().named("test_async_fn"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ block_on_future(async { test_async_fn(2).await }).unwrap();
+ });
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_nested() {
+ #[instrument]
+ async fn test_async_fns_nested() {
+ test_async_fns_nested_other().await
+ }
+
+ #[instrument]
+ async fn test_async_fns_nested_other() {
+ tracing::trace!(nested = true);
+ }
+
+ let span = span::mock().named("test_async_fns_nested");
+ let span2 = span::mock().named("test_async_fns_nested_other");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .new_span(span2.clone())
+ .enter(span2.clone())
+ .event(event::mock().with_fields(field::mock("nested").with_value(&true)))
+ .exit(span2.clone())
+ .drop_span(span2)
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async { test_async_fns_nested().await });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_with_async_trait() {
+ use async_trait::async_trait;
+
+ // test the correctness of the metadata obtained by #[instrument]
+ // (function name, functions parameters) when async-trait is used
+ #[async_trait]
+ pub trait TestA {
+ async fn foo(&mut self, v: usize);
+ }
+
+ // test nesting of async fns with aync-trait
+ #[async_trait]
+ pub trait TestB {
+ async fn bar(&self);
+ }
+
+ // test skip(self) with async-await
+ #[async_trait]
+ pub trait TestC {
+ async fn baz(&self);
+ }
+
+ #[derive(Debug)]
+ struct TestImpl(usize);
+
+ #[async_trait]
+ impl TestA for TestImpl {
+ #[instrument]
+ async fn foo(&mut self, v: usize) {
+ self.baz().await;
+ self.0 = v;
+ self.bar().await
+ }
+ }
+
+ #[async_trait]
+ impl TestB for TestImpl {
+ #[instrument]
+ async fn bar(&self) {
+ tracing::trace!(val = self.0);
+ }
+ }
+
+ #[async_trait]
+ impl TestC for TestImpl {
+ #[instrument(skip(self))]
+ async fn baz(&self) {
+ tracing::trace!(val = self.0);
+ }
+ }
+
+ let span = span::mock().named("foo");
+ let span2 = span::mock().named("bar");
+ let span3 = span::mock().named("baz");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("self"))
+ .with_field(field::mock("v")),
+ )
+ .enter(span.clone())
+ .new_span(span3.clone())
+ .enter(span3.clone())
+ .event(event::mock().with_fields(field::mock("val").with_value(&2u64)))
+ .exit(span3.clone())
+ .drop_span(span3)
+ .new_span(span2.clone().with_field(field::mock("self")))
+ .enter(span2.clone())
+ .event(event::mock().with_fields(field::mock("val").with_value(&5u64)))
+ .exit(span2.clone())
+ .drop_span(span2)
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let mut test = TestImpl(2);
+ block_on_future(async { test.foo(5).await });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_with_async_trait_and_fields_expressions() {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Test {
+ async fn call(&mut self, v: usize);
+ }
+
+ #[derive(Clone, Debug)]
+ struct TestImpl;
+
+ impl TestImpl {
+ fn foo(&self) -> usize {
+ 42
+ }
+ }
+
+ #[async_trait]
+ impl Test for TestImpl {
+ // check that self is correctly handled, even when using async_trait
+ #[instrument(fields(val=self.foo(), val2=Self::clone(self).foo(), test=%_v+5))]
+ async fn call(&mut self, _v: usize) {}
+ }
+
+ let span = span::mock().named("call");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("_v")
+ .with_value(&5usize)
+ .and(field::mock("test").with_value(&tracing::field::debug(10)))
+ .and(field::mock("val").with_value(&42u64))
+ .and(field::mock("val2").with_value(&42u64)),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async { TestImpl.call(5).await });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn async_fn_with_async_trait_and_fields_expressions_with_generic_parameter() {
+ use async_trait::async_trait;
+
+ #[async_trait]
+ pub trait Test {
+ async fn call();
+ async fn call_with_self(&self);
+ async fn call_with_mut_self(&mut self);
+ }
+
+ #[derive(Clone, Debug)]
+ struct TestImpl;
+
+ // we also test sync functions that return futures, as they should be handled just like
+ // async-trait (>= 0.1.44) functions
+ impl TestImpl {
+ #[instrument(fields(Self=std::any::type_name::<Self>()))]
+ fn sync_fun(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
+ let val = self.clone();
+ Box::pin(async move {
+ let _ = val;
+ })
+ }
+ }
+
+ #[async_trait]
+ impl Test for TestImpl {
+ // instrumenting this is currently not possible, see https://github.com/tokio-rs/tracing/issues/864#issuecomment-667508801
+ //#[instrument(fields(Self=std::any::type_name::<Self>()))]
+ async fn call() {}
+
+ #[instrument(fields(Self=std::any::type_name::<Self>()))]
+ async fn call_with_self(&self) {
+ self.sync_fun().await;
+ }
+
+ #[instrument(fields(Self=std::any::type_name::<Self>()))]
+ async fn call_with_mut_self(&mut self) {}
+ }
+
+ //let span = span::mock().named("call");
+ let span2 = span::mock().named("call_with_self");
+ let span3 = span::mock().named("call_with_mut_self");
+ let span4 = span::mock().named("sync_fun");
+ let (subscriber, handle) = subscriber::mock()
+ /*.new_span(span.clone()
+ .with_field(
+ field::mock("Self").with_value(&"TestImpler")))
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)*/
+ .new_span(
+ span2
+ .clone()
+ .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())),
+ )
+ .enter(span2.clone())
+ .new_span(
+ span4
+ .clone()
+ .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())),
+ )
+ .enter(span4.clone())
+ .exit(span4)
+ .exit(span2.clone())
+ .drop_span(span2)
+ .new_span(
+ span3
+ .clone()
+ .with_field(field::mock("Self").with_value(&std::any::type_name::<TestImpl>())),
+ )
+ .enter(span3.clone())
+ .exit(span3.clone())
+ .drop_span(span3)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ TestImpl::call().await;
+ TestImpl.call_with_self().await;
+ TestImpl.call_with_mut_self().await
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn out_of_scope_fields() {
+ // Reproduces tokio-rs/tracing#1296
+
+ struct Thing {
+ metrics: Arc<()>,
+ }
+
+ impl Thing {
+ #[instrument(skip(self, _req), fields(app_id))]
+ fn call(&mut self, _req: ()) -> Pin<Box<dyn Future<Output = Arc<()>> + Send + Sync>> {
+ // ...
+ let metrics = self.metrics.clone();
+ // ...
+ Box::pin(async move {
+ // ...
+ metrics // cannot find value `metrics` in this scope
+ })
+ }
+ }
+
+ let span = span::mock().named("call");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ let mut my_thing = Thing {
+ metrics: Arc::new(()),
+ };
+ my_thing.call(()).await;
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn manual_impl_future() {
+ #[allow(clippy::manual_async_fn)]
+ #[instrument]
+ fn manual_impl_future() -> impl Future<Output = ()> {
+ async {
+ tracing::trace!(poll = true);
+ }
+ }
+
+ let span = span::mock().named("manual_impl_future");
+ let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true));
+
+ let (subscriber, handle) = subscriber::mock()
+ // await manual_impl_future
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(poll_event())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ manual_impl_future().await;
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn manual_box_pin() {
+ #[instrument]
+ fn manual_box_pin() -> Pin<Box<dyn Future<Output = ()>>> {
+ Box::pin(async {
+ tracing::trace!(poll = true);
+ })
+ }
+
+ let span = span::mock().named("manual_box_pin");
+ let poll_event = || event::mock().with_fields(field::mock("poll").with_value(&true));
+
+ let (subscriber, handle) = subscriber::mock()
+ // await manual_box_pin
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(poll_event())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ manual_box_pin().await;
+ });
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/destructuring.rs b/third_party/rust/tracing-attributes/tests/destructuring.rs
new file mode 100644
index 0000000000..09cf1ad534
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/destructuring.rs
@@ -0,0 +1,213 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[test]
+fn destructure_tuples() {
+ #[instrument]
+ fn my_fn((arg1, arg2): (usize, usize)) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn((1, 2));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_nested_tuples() {
+ #[instrument]
+ fn my_fn(((arg1, arg2), (arg3, arg4)): ((usize, usize), (usize, usize))) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .and(field::mock("arg3").with_value(&format_args!("3")))
+ .and(field::mock("arg4").with_value(&format_args!("4")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(((1, 2), (3, 4)));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_refs() {
+ #[instrument]
+ fn my_fn(&arg1: &usize) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("arg1").with_value(&1usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(&1);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_tuple_structs() {
+ struct Foo(usize, usize);
+
+ #[instrument]
+ fn my_fn(Foo(arg1, arg2): Foo) {}
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(Foo(1, 2));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_structs() {
+ struct Foo {
+ bar: usize,
+ baz: usize,
+ }
+
+ #[instrument]
+ fn my_fn(
+ Foo {
+ bar: arg1,
+ baz: arg2,
+ }: Foo,
+ ) {
+ let _ = (arg1, arg2);
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(Foo { bar: 1, baz: 2 });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn destructure_everything() {
+ struct Foo {
+ bar: Bar,
+ baz: (usize, usize),
+ qux: NoDebug,
+ }
+ struct Bar((usize, usize));
+ struct NoDebug;
+
+ #[instrument]
+ fn my_fn(
+ &Foo {
+ bar: Bar((arg1, arg2)),
+ baz: (arg3, arg4),
+ ..
+ }: &Foo,
+ ) {
+ let _ = (arg1, arg2, arg3, arg4);
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("1"))
+ .and(field::mock("arg2").with_value(&format_args!("2")))
+ .and(field::mock("arg3").with_value(&format_args!("3")))
+ .and(field::mock("arg4").with_value(&format_args!("4")))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = Foo {
+ bar: Bar((1, 2)),
+ baz: (3, 4),
+ qux: NoDebug,
+ };
+ let _ = foo.qux; // to eliminate unused field warning
+ my_fn(&foo);
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/err.rs b/third_party/rust/tracing-attributes/tests/err.rs
new file mode 100644
index 0000000000..9e6d6b78c3
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/err.rs
@@ -0,0 +1,233 @@
+use tracing::subscriber::with_default;
+use tracing::Level;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+use tracing_subscriber::filter::EnvFilter;
+use tracing_subscriber::layer::SubscriberExt;
+
+use std::convert::TryFrom;
+use std::num::TryFromIntError;
+
+#[instrument(err)]
+fn err() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[instrument(err)]
+fn err_suspicious_else() -> Result<u8, TryFromIntError> {
+ {}
+ u8::try_from(1234)
+}
+
+#[test]
+fn test() {
+ let span = span::mock().named("err");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err().ok());
+ handle.assert_finished();
+}
+
+#[instrument(err)]
+async fn err_async(polls: usize) -> Result<u8, TryFromIntError> {
+ let future = PollN::new_ok(polls);
+ tracing::trace!(awaiting = true);
+ future.await.ok();
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_async() {
+ let span = span::mock().named("err_async");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("awaiting").with_value(&true))
+ .at_level(Level::TRACE),
+ )
+ .exit(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ block_on_future(async { err_async(2).await }).ok();
+ });
+ handle.assert_finished();
+}
+
+#[instrument(err)]
+fn err_mut(out: &mut u8) -> Result<(), TryFromIntError> {
+ *out = u8::try_from(1234)?;
+ Ok(())
+}
+
+#[test]
+fn test_mut() {
+ let span = span::mock().named("err_mut");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err_mut(&mut 0).ok());
+ handle.assert_finished();
+}
+
+#[instrument(err)]
+async fn err_mut_async(polls: usize, out: &mut u8) -> Result<(), TryFromIntError> {
+ let future = PollN::new_ok(polls);
+ tracing::trace!(awaiting = true);
+ future.await.ok();
+ *out = u8::try_from(1234)?;
+ Ok(())
+}
+
+#[test]
+fn test_mut_async() {
+ let span = span::mock().named("err_mut_async");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("awaiting").with_value(&true))
+ .at_level(Level::TRACE),
+ )
+ .exit(span.clone())
+ .enter(span.clone())
+ .event(event::mock().at_level(Level::ERROR))
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ block_on_future(async { err_mut_async(2, &mut 0).await }).ok();
+ });
+ handle.assert_finished();
+}
+
+#[test]
+fn impl_trait_return_type() {
+ // Reproduces https://github.com/tokio-rs/tracing/issues/1227
+
+ #[instrument(err)]
+ fn returns_impl_trait(x: usize) -> Result<impl Iterator<Item = usize>, String> {
+ Ok(0..x)
+ }
+
+ let span = span::mock().named("returns_impl_trait");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("x").with_value(&10usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ for _ in returns_impl_trait(10).unwrap() {
+ // nop
+ }
+ });
+
+ handle.assert_finished();
+}
+
+#[instrument(err(Debug))]
+fn err_dbg() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_err_dbg() {
+ let span = span::mock().named("err_dbg");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock().at_level(Level::ERROR).with_fields(
+ field::mock("error")
+ // use the actual error value that will be emitted, so
+ // that this test doesn't break if the standard library
+ // changes the `fmt::Debug` output from the error type
+ // in the future.
+ .with_value(&tracing::field::debug(u8::try_from(1234).unwrap_err())),
+ ),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err_dbg().ok());
+ handle.assert_finished();
+}
+
+#[test]
+fn test_err_display_default() {
+ let span = span::mock().named("err");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock().at_level(Level::ERROR).with_fields(
+ field::mock("error")
+ // by default, errors will be emitted with their display values
+ .with_value(&tracing::field::display(u8::try_from(1234).unwrap_err())),
+ ),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || err().ok());
+ handle.assert_finished();
+}
+
+#[test]
+fn test_err_custom_target() {
+ let filter: EnvFilter = "my_target=error".parse().expect("filter should parse");
+ let span = span::mock().named("error_span").with_target("my_target");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .at_level(Level::ERROR)
+ .with_target("my_target"),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ let subscriber = subscriber.with(filter);
+
+ with_default(subscriber, || {
+ let error_span = tracing::error_span!(target: "my_target", "error_span");
+
+ {
+ let _enter = error_span.enter();
+ tracing::error!(target: "my_target", "This should display")
+ }
+ });
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/fields.rs b/third_party/rust/tracing-attributes/tests/fields.rs
new file mode 100644
index 0000000000..c178fbb3d3
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/fields.rs
@@ -0,0 +1,160 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::field::mock;
+use tracing_mock::span::NewSpan;
+use tracing_mock::*;
+
+#[instrument(fields(foo = "bar", dsa = true, num = 1))]
+fn fn_no_param() {}
+
+#[instrument(fields(foo = "bar"))]
+fn fn_param(param: u32) {}
+
+#[instrument(fields(foo = "bar", empty))]
+fn fn_empty_field() {}
+
+#[instrument(fields(len = s.len()))]
+fn fn_expr_field(s: &str) {}
+
+#[instrument(fields(s.len = s.len(), s.is_empty = s.is_empty()))]
+fn fn_two_expr_fields(s: &str) {
+ let _ = s;
+}
+
+#[instrument(fields(%s, s.len = s.len()))]
+fn fn_clashy_expr_field(s: &str) {
+ let _ = s;
+}
+
+#[instrument(fields(s = "s"))]
+fn fn_clashy_expr_field2(s: &str) {
+ let _ = s;
+}
+
+#[instrument(fields(s = &s))]
+fn fn_string(s: String) {
+ let _ = s;
+}
+
+#[derive(Debug)]
+struct HasField {
+ my_field: &'static str,
+}
+
+impl HasField {
+ #[instrument(fields(my_field = self.my_field), skip(self))]
+ fn self_expr_field(&self) {}
+}
+
+#[test]
+fn fields() {
+ let span = span::mock().with_field(
+ mock("foo")
+ .with_value(&"bar")
+ .and(mock("dsa").with_value(&true))
+ .and(mock("num").with_value(&1))
+ .only(),
+ );
+ run_test(span, || {
+ fn_no_param();
+ });
+}
+
+#[test]
+fn expr_field() {
+ let span = span::mock().with_field(
+ mock("s")
+ .with_value(&"hello world")
+ .and(mock("len").with_value(&"hello world".len()))
+ .only(),
+ );
+ run_test(span, || {
+ fn_expr_field("hello world");
+ });
+}
+
+#[test]
+fn two_expr_fields() {
+ let span = span::mock().with_field(
+ mock("s")
+ .with_value(&"hello world")
+ .and(mock("s.len").with_value(&"hello world".len()))
+ .and(mock("s.is_empty").with_value(&false))
+ .only(),
+ );
+ run_test(span, || {
+ fn_two_expr_fields("hello world");
+ });
+}
+
+#[test]
+fn clashy_expr_field() {
+ let span = span::mock().with_field(
+ // Overriding the `s` field should record `s` as a `Display` value,
+ // rather than as a `Debug` value.
+ mock("s")
+ .with_value(&tracing::field::display("hello world"))
+ .and(mock("s.len").with_value(&"hello world".len()))
+ .only(),
+ );
+ run_test(span, || {
+ fn_clashy_expr_field("hello world");
+ });
+
+ let span = span::mock().with_field(mock("s").with_value(&"s").only());
+ run_test(span, || {
+ fn_clashy_expr_field2("hello world");
+ });
+}
+
+#[test]
+fn self_expr_field() {
+ let span = span::mock().with_field(mock("my_field").with_value(&"hello world").only());
+ run_test(span, || {
+ let has_field = HasField {
+ my_field: "hello world",
+ };
+ has_field.self_expr_field();
+ });
+}
+
+#[test]
+fn parameters_with_fields() {
+ let span = span::mock().with_field(
+ mock("foo")
+ .with_value(&"bar")
+ .and(mock("param").with_value(&1u32))
+ .only(),
+ );
+ run_test(span, || {
+ fn_param(1);
+ });
+}
+
+#[test]
+fn empty_field() {
+ let span = span::mock().with_field(mock("foo").with_value(&"bar").only());
+ run_test(span, || {
+ fn_empty_field();
+ });
+}
+
+#[test]
+fn string_field() {
+ let span = span::mock().with_field(mock("s").with_value(&"hello world").only());
+ run_test(span, || {
+ fn_string(String::from("hello world"));
+ });
+}
+
+fn run_test<F: FnOnce() -> T, T>(span: NewSpan, fun: F) {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span)
+ .enter(span::mock())
+ .exit(span::mock())
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, fun);
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/follows_from.rs b/third_party/rust/tracing-attributes/tests/follows_from.rs
new file mode 100644
index 0000000000..da0eec6357
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/follows_from.rs
@@ -0,0 +1,99 @@
+use tracing::{subscriber::with_default, Id, Level, Span};
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument(follows_from = causes, skip(causes))]
+fn with_follows_from_sync(causes: impl IntoIterator<Item = impl Into<Option<Id>>>) {}
+
+#[instrument(follows_from = causes, skip(causes))]
+async fn with_follows_from_async(causes: impl IntoIterator<Item = impl Into<Option<Id>>>) {}
+
+#[instrument(follows_from = [&Span::current()])]
+fn follows_from_current() {}
+
+#[test]
+fn follows_from_sync_test() {
+ let cause_a = span::mock().named("cause_a");
+ let cause_b = span::mock().named("cause_b");
+ let cause_c = span::mock().named("cause_c");
+ let consequence = span::mock().named("with_follows_from_sync");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(cause_a.clone())
+ .new_span(cause_b.clone())
+ .new_span(cause_c.clone())
+ .new_span(consequence.clone())
+ .follows_from(consequence.clone(), cause_a)
+ .follows_from(consequence.clone(), cause_b)
+ .follows_from(consequence.clone(), cause_c)
+ .enter(consequence.clone())
+ .exit(consequence)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let cause_a = tracing::span!(Level::TRACE, "cause_a");
+ let cause_b = tracing::span!(Level::TRACE, "cause_b");
+ let cause_c = tracing::span!(Level::TRACE, "cause_c");
+
+ with_follows_from_sync(&[cause_a, cause_b, cause_c])
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn follows_from_async_test() {
+ let cause_a = span::mock().named("cause_a");
+ let cause_b = span::mock().named("cause_b");
+ let cause_c = span::mock().named("cause_c");
+ let consequence = span::mock().named("with_follows_from_async");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(cause_a.clone())
+ .new_span(cause_b.clone())
+ .new_span(cause_c.clone())
+ .new_span(consequence.clone())
+ .follows_from(consequence.clone(), cause_a)
+ .follows_from(consequence.clone(), cause_b)
+ .follows_from(consequence.clone(), cause_c)
+ .enter(consequence.clone())
+ .exit(consequence)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ block_on_future(async {
+ let cause_a = tracing::span!(Level::TRACE, "cause_a");
+ let cause_b = tracing::span!(Level::TRACE, "cause_b");
+ let cause_c = tracing::span!(Level::TRACE, "cause_c");
+
+ with_follows_from_async(&[cause_a, cause_b, cause_c]).await
+ })
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn follows_from_current_test() {
+ let cause = span::mock().named("cause");
+ let consequence = span::mock().named("follows_from_current");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(cause.clone())
+ .enter(cause.clone())
+ .new_span(consequence.clone())
+ .follows_from(consequence.clone(), cause.clone())
+ .enter(consequence.clone())
+ .exit(consequence)
+ .exit(cause)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "cause").in_scope(follows_from_current)
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/instrument.rs b/third_party/rust/tracing-attributes/tests/instrument.rs
new file mode 100644
index 0000000000..7686927488
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/instrument.rs
@@ -0,0 +1,252 @@
+use tracing::subscriber::with_default;
+use tracing::Level;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+// Reproduces a compile error when an instrumented function body contains inner
+// attributes (https://github.com/tokio-rs/tracing/issues/2294).
+#[deny(unused_variables)]
+#[instrument]
+fn repro_2294() {
+ #![allow(unused_variables)]
+ let i = 42;
+}
+
+#[test]
+fn override_everything() {
+ #[instrument(target = "my_target", level = "debug")]
+ fn my_fn() {}
+
+ #[instrument(level = "debug", target = "my_target")]
+ fn my_other_fn() {}
+
+ let span = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+ let span2 = span::mock()
+ .named("my_other_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .new_span(span2.clone())
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn();
+ my_other_fn();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn fields() {
+ #[instrument(target = "my_target", level = "debug")]
+ fn my_fn(arg1: usize, arg2: bool) {}
+
+ let span = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let span2 = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&2usize)
+ .and(field::mock("arg2").with_value(&false))
+ .only(),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .new_span(
+ span2.clone().with_field(
+ field::mock("arg1")
+ .with_value(&3usize)
+ .and(field::mock("arg2").with_value(&true))
+ .only(),
+ ),
+ )
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(2, false);
+ my_fn(3, true);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn skip() {
+ struct UnDebug(pub u32);
+
+ #[instrument(target = "my_target", level = "debug", skip(_arg2, _arg3))]
+ fn my_fn(arg1: usize, _arg2: UnDebug, _arg3: UnDebug) {}
+
+ #[instrument(target = "my_target", level = "debug", skip_all)]
+ fn my_fn2(_arg1: usize, _arg2: UnDebug, _arg3: UnDebug) {}
+
+ let span = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let span2 = span::mock()
+ .named("my_fn")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let span3 = span::mock()
+ .named("my_fn2")
+ .at_level(Level::DEBUG)
+ .with_target("my_target");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("arg1").with_value(&2usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .new_span(
+ span2
+ .clone()
+ .with_field(field::mock("arg1").with_value(&3usize).only()),
+ )
+ .enter(span2.clone())
+ .exit(span2.clone())
+ .drop_span(span2)
+ .new_span(span3.clone())
+ .enter(span3.clone())
+ .exit(span3.clone())
+ .drop_span(span3)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(2, UnDebug(0), UnDebug(1));
+ my_fn(3, UnDebug(0), UnDebug(1));
+ my_fn2(2, UnDebug(0), UnDebug(1));
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn generics() {
+ #[derive(Debug)]
+ struct Foo;
+
+ #[instrument]
+ fn my_fn<S, T: std::fmt::Debug>(arg1: S, arg2: T)
+ where
+ S: std::fmt::Debug,
+ {
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("arg1")
+ .with_value(&format_args!("Foo"))
+ .and(field::mock("arg2").with_value(&format_args!("false"))),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ my_fn(Foo, false);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn methods() {
+ #[derive(Debug)]
+ struct Foo;
+
+ impl Foo {
+ #[instrument]
+ fn my_fn(&self, arg1: usize) {}
+ }
+
+ let span = span::mock().named("my_fn");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone().with_field(
+ field::mock("self")
+ .with_value(&format_args!("Foo"))
+ .and(field::mock("arg1").with_value(&42usize)),
+ ),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = Foo;
+ foo.my_fn(42);
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn impl_trait_return_type() {
+ #[instrument]
+ fn returns_impl_trait(x: usize) -> impl Iterator<Item = usize> {
+ 0..x
+ }
+
+ let span = span::mock().named("returns_impl_trait");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span.clone()
+ .with_field(field::mock("x").with_value(&10usize).only()),
+ )
+ .enter(span.clone())
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ for _ in returns_impl_trait(10) {
+ // nop
+ }
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/levels.rs b/third_party/rust/tracing-attributes/tests/levels.rs
new file mode 100644
index 0000000000..b074ea4f28
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/levels.rs
@@ -0,0 +1,96 @@
+use tracing::subscriber::with_default;
+use tracing::Level;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[test]
+fn named_levels() {
+ #[instrument(level = "trace")]
+ fn trace() {}
+
+ #[instrument(level = "Debug")]
+ fn debug() {}
+
+ #[instrument(level = "INFO")]
+ fn info() {}
+
+ #[instrument(level = "WARn")]
+ fn warn() {}
+
+ #[instrument(level = "eRrOr")]
+ fn error() {}
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("trace").at_level(Level::TRACE))
+ .enter(span::mock().named("trace").at_level(Level::TRACE))
+ .exit(span::mock().named("trace").at_level(Level::TRACE))
+ .new_span(span::mock().named("debug").at_level(Level::DEBUG))
+ .enter(span::mock().named("debug").at_level(Level::DEBUG))
+ .exit(span::mock().named("debug").at_level(Level::DEBUG))
+ .new_span(span::mock().named("info").at_level(Level::INFO))
+ .enter(span::mock().named("info").at_level(Level::INFO))
+ .exit(span::mock().named("info").at_level(Level::INFO))
+ .new_span(span::mock().named("warn").at_level(Level::WARN))
+ .enter(span::mock().named("warn").at_level(Level::WARN))
+ .exit(span::mock().named("warn").at_level(Level::WARN))
+ .new_span(span::mock().named("error").at_level(Level::ERROR))
+ .enter(span::mock().named("error").at_level(Level::ERROR))
+ .exit(span::mock().named("error").at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ trace();
+ debug();
+ info();
+ warn();
+ error();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn numeric_levels() {
+ #[instrument(level = 1)]
+ fn trace() {}
+
+ #[instrument(level = 2)]
+ fn debug() {}
+
+ #[instrument(level = 3)]
+ fn info() {}
+
+ #[instrument(level = 4)]
+ fn warn() {}
+
+ #[instrument(level = 5)]
+ fn error() {}
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("trace").at_level(Level::TRACE))
+ .enter(span::mock().named("trace").at_level(Level::TRACE))
+ .exit(span::mock().named("trace").at_level(Level::TRACE))
+ .new_span(span::mock().named("debug").at_level(Level::DEBUG))
+ .enter(span::mock().named("debug").at_level(Level::DEBUG))
+ .exit(span::mock().named("debug").at_level(Level::DEBUG))
+ .new_span(span::mock().named("info").at_level(Level::INFO))
+ .enter(span::mock().named("info").at_level(Level::INFO))
+ .exit(span::mock().named("info").at_level(Level::INFO))
+ .new_span(span::mock().named("warn").at_level(Level::WARN))
+ .enter(span::mock().named("warn").at_level(Level::WARN))
+ .exit(span::mock().named("warn").at_level(Level::WARN))
+ .new_span(span::mock().named("error").at_level(Level::ERROR))
+ .enter(span::mock().named("error").at_level(Level::ERROR))
+ .exit(span::mock().named("error").at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ trace();
+ debug();
+ info();
+ warn();
+ error();
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/names.rs b/third_party/rust/tracing-attributes/tests/names.rs
new file mode 100644
index 0000000000..d97dece9a1
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/names.rs
@@ -0,0 +1,63 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument]
+fn default_name() {}
+
+#[instrument(name = "my_name")]
+fn custom_name() {}
+
+// XXX: it's weird that we support both of these forms, but apparently we
+// managed to release a version that accepts both syntax, so now we have to
+// support it! yay!
+#[instrument("my_other_name")]
+fn custom_name_no_equals() {}
+
+#[test]
+fn default_name_test() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("default_name"))
+ .enter(span::mock().named("default_name"))
+ .exit(span::mock().named("default_name"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ default_name();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn custom_name_test() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("my_name"))
+ .enter(span::mock().named("my_name"))
+ .exit(span::mock().named("my_name"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ custom_name();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn custom_name_no_equals_test() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("my_other_name"))
+ .enter(span::mock().named("my_other_name"))
+ .exit(span::mock().named("my_other_name"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ custom_name_no_equals();
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/parents.rs b/third_party/rust/tracing-attributes/tests/parents.rs
new file mode 100644
index 0000000000..7069b98ea5
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/parents.rs
@@ -0,0 +1,102 @@
+use tracing::{subscriber::with_default, Id, Level};
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument]
+fn with_default_parent() {}
+
+#[instrument(parent = parent_span, skip(parent_span))]
+fn with_explicit_parent<P>(parent_span: P)
+where
+ P: Into<Option<Id>>,
+{
+}
+
+#[test]
+fn default_parent_test() {
+ let contextual_parent = span::mock().named("contextual_parent");
+ let child = span::mock().named("with_default_parent");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ contextual_parent
+ .clone()
+ .with_contextual_parent(None)
+ .with_explicit_parent(None),
+ )
+ .new_span(
+ child
+ .clone()
+ .with_contextual_parent(Some("contextual_parent"))
+ .with_explicit_parent(None),
+ )
+ .enter(child.clone())
+ .exit(child.clone())
+ .enter(contextual_parent.clone())
+ .new_span(
+ child
+ .clone()
+ .with_contextual_parent(Some("contextual_parent"))
+ .with_explicit_parent(None),
+ )
+ .enter(child.clone())
+ .exit(child)
+ .exit(contextual_parent)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let contextual_parent = tracing::span!(Level::TRACE, "contextual_parent");
+
+ with_default_parent();
+
+ contextual_parent.in_scope(|| {
+ with_default_parent();
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn explicit_parent_test() {
+ let contextual_parent = span::mock().named("contextual_parent");
+ let explicit_parent = span::mock().named("explicit_parent");
+ let child = span::mock().named("with_explicit_parent");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ contextual_parent
+ .clone()
+ .with_contextual_parent(None)
+ .with_explicit_parent(None),
+ )
+ .new_span(
+ explicit_parent
+ .with_contextual_parent(None)
+ .with_explicit_parent(None),
+ )
+ .enter(contextual_parent.clone())
+ .new_span(
+ child
+ .clone()
+ .with_contextual_parent(Some("contextual_parent"))
+ .with_explicit_parent(Some("explicit_parent")),
+ )
+ .enter(child.clone())
+ .exit(child)
+ .exit(contextual_parent)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let contextual_parent = tracing::span!(Level::INFO, "contextual_parent");
+ let explicit_parent = tracing::span!(Level::INFO, "explicit_parent");
+
+ contextual_parent.in_scope(|| {
+ with_explicit_parent(&explicit_parent);
+ });
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/ret.rs b/third_party/rust/tracing-attributes/tests/ret.rs
new file mode 100644
index 0000000000..cfd2de10d3
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ret.rs
@@ -0,0 +1,255 @@
+use std::convert::TryFrom;
+use std::num::TryFromIntError;
+use tracing_mock::*;
+
+use tracing::{subscriber::with_default, Level};
+use tracing_attributes::instrument;
+use tracing_subscriber::layer::SubscriberExt;
+use tracing_subscriber::EnvFilter;
+
+#[instrument(ret)]
+fn ret() -> i32 {
+ 42
+}
+
+#[instrument(target = "my_target", ret)]
+fn ret_with_target() -> i32 {
+ 42
+}
+
+#[test]
+fn test() {
+ let span = span::mock().named("ret");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret);
+ handle.assert_finished();
+}
+
+#[test]
+fn test_custom_target() {
+ let filter: EnvFilter = "my_target=info".parse().expect("filter should parse");
+ let span = span::mock()
+ .named("ret_with_target")
+ .with_target("my_target");
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO)
+ .with_target("my_target"),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ let subscriber = subscriber.with(filter);
+
+ with_default(subscriber, ret_with_target);
+ handle.assert_finished();
+}
+
+#[instrument(level = "warn", ret)]
+fn ret_warn() -> i32 {
+ 42
+}
+
+#[test]
+fn test_warn() {
+ let span = span::mock().named("ret_warn");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::WARN),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_warn);
+ handle.assert_finished();
+}
+
+#[instrument(ret)]
+fn ret_mut(a: &mut i32) -> i32 {
+ *a *= 2;
+ tracing::info!(?a);
+ *a
+}
+
+#[test]
+fn test_mut() {
+ let span = span::mock().named("ret_mut");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("a").with_value(&tracing::field::display(2)))
+ .at_level(Level::INFO),
+ )
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(2)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || ret_mut(&mut 1));
+ handle.assert_finished();
+}
+
+#[instrument(ret)]
+async fn ret_async() -> i32 {
+ 42
+}
+
+#[test]
+fn test_async() {
+ let span = span::mock().named("ret_async");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || block_on_future(async { ret_async().await }));
+ handle.assert_finished();
+}
+
+#[instrument(ret)]
+fn ret_impl_type() -> impl Copy {
+ 42
+}
+
+#[test]
+fn test_impl_type() {
+ let span = span::mock().named("ret_impl_type");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::debug(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_impl_type);
+ handle.assert_finished();
+}
+
+#[instrument(ret(Display))]
+fn ret_display() -> i32 {
+ 42
+}
+
+#[test]
+fn test_dbg() {
+ let span = span::mock().named("ret_display");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(field::mock("return").with_value(&tracing::field::display(42)))
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, ret_display);
+ handle.assert_finished();
+}
+
+#[instrument(err, ret)]
+fn ret_and_err() -> Result<u8, TryFromIntError> {
+ u8::try_from(1234)
+}
+
+#[test]
+fn test_ret_and_err() {
+ let span = span::mock().named("ret_and_err");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(
+ field::mock("error")
+ .with_value(&tracing::field::display(u8::try_from(1234).unwrap_err()))
+ .only(),
+ )
+ .at_level(Level::ERROR),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || ret_and_err().ok());
+ handle.assert_finished();
+}
+
+#[instrument(err, ret)]
+fn ret_and_ok() -> Result<u8, TryFromIntError> {
+ u8::try_from(123)
+}
+
+#[test]
+fn test_ret_and_ok() {
+ let span = span::mock().named("ret_and_ok");
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span.clone())
+ .enter(span.clone())
+ .event(
+ event::mock()
+ .with_fields(
+ field::mock("return")
+ .with_value(&tracing::field::debug(u8::try_from(123).unwrap()))
+ .only(),
+ )
+ .at_level(Level::INFO),
+ )
+ .exit(span.clone())
+ .drop_span(span)
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || ret_and_ok().ok());
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/targets.rs b/third_party/rust/tracing-attributes/tests/targets.rs
new file mode 100644
index 0000000000..363f628f31
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/targets.rs
@@ -0,0 +1,97 @@
+use tracing::subscriber::with_default;
+use tracing_attributes::instrument;
+use tracing_mock::*;
+
+#[instrument]
+fn default_target() {}
+
+#[instrument(target = "my_target")]
+fn custom_target() {}
+
+mod my_mod {
+ use tracing_attributes::instrument;
+
+ pub const MODULE_PATH: &str = module_path!();
+
+ #[instrument]
+ pub fn default_target() {}
+
+ #[instrument(target = "my_other_target")]
+ pub fn custom_target() {}
+}
+
+#[test]
+fn default_targets() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock()
+ .named("default_target")
+ .with_target(module_path!()),
+ )
+ .enter(
+ span::mock()
+ .named("default_target")
+ .with_target(module_path!()),
+ )
+ .exit(
+ span::mock()
+ .named("default_target")
+ .with_target(module_path!()),
+ )
+ .new_span(
+ span::mock()
+ .named("default_target")
+ .with_target(my_mod::MODULE_PATH),
+ )
+ .enter(
+ span::mock()
+ .named("default_target")
+ .with_target(my_mod::MODULE_PATH),
+ )
+ .exit(
+ span::mock()
+ .named("default_target")
+ .with_target(my_mod::MODULE_PATH),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ default_target();
+ my_mod::default_target();
+ });
+
+ handle.assert_finished();
+}
+
+#[test]
+fn custom_targets() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("custom_target").with_target("my_target"))
+ .enter(span::mock().named("custom_target").with_target("my_target"))
+ .exit(span::mock().named("custom_target").with_target("my_target"))
+ .new_span(
+ span::mock()
+ .named("custom_target")
+ .with_target("my_other_target"),
+ )
+ .enter(
+ span::mock()
+ .named("custom_target")
+ .with_target("my_other_target"),
+ )
+ .exit(
+ span::mock()
+ .named("custom_target")
+ .with_target("my_other_target"),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ custom_target();
+ my_mod::custom_target();
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing-attributes/tests/ui.rs b/third_party/rust/tracing-attributes/tests/ui.rs
new file mode 100644
index 0000000000..f11cc019eb
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui.rs
@@ -0,0 +1,7 @@
+// Only test on nightly, since UI tests are bound to change over time
+#[rustversion::stable]
+#[test]
+fn async_instrument() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/async_instrument.rs");
+}
diff --git a/third_party/rust/tracing-attributes/tests/ui/async_instrument.rs b/third_party/rust/tracing-attributes/tests/ui/async_instrument.rs
new file mode 100644
index 0000000000..5b245746a6
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui/async_instrument.rs
@@ -0,0 +1,46 @@
+#![allow(unreachable_code)]
+
+#[tracing::instrument]
+async fn unit() {
+ ""
+}
+
+#[tracing::instrument]
+async fn simple_mismatch() -> String {
+ ""
+}
+
+// FIXME: this span is still pretty poor
+#[tracing::instrument]
+async fn opaque_unsatisfied() -> impl std::fmt::Display {
+ ("",)
+}
+
+struct Wrapper<T>(T);
+
+#[tracing::instrument]
+async fn mismatch_with_opaque() -> Wrapper<impl std::fmt::Display> {
+ ""
+}
+
+#[tracing::instrument]
+async fn early_return_unit() {
+ if true {
+ return "";
+ }
+}
+
+#[tracing::instrument]
+async fn early_return() -> String {
+ if true {
+ return "";
+ }
+ String::new()
+}
+
+#[tracing::instrument]
+async fn extra_semicolon() -> i32 {
+ 1;
+}
+
+fn main() {}
diff --git a/third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr b/third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr
new file mode 100644
index 0000000000..db6f6b4343
--- /dev/null
+++ b/third_party/rust/tracing-attributes/tests/ui/async_instrument.stderr
@@ -0,0 +1,98 @@
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:5:5
+ |
+5 | ""
+ | ^^ expected `()`, found `&str`
+ |
+note: return type inferred to be `()` here
+ --> tests/ui/async_instrument.rs:4:10
+ |
+4 | async fn unit() {
+ | ^^^^
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:10:5
+ |
+10 | ""
+ | ^^- help: try using a conversion method: `.to_string()`
+ | |
+ | expected struct `String`, found `&str`
+ |
+note: return type inferred to be `String` here
+ --> tests/ui/async_instrument.rs:9:31
+ |
+9 | async fn simple_mismatch() -> String {
+ | ^^^^^^
+
+error[E0277]: `(&str,)` doesn't implement `std::fmt::Display`
+ --> tests/ui/async_instrument.rs:14:1
+ |
+14 | #[tracing::instrument]
+ | ^^^^^^^^^^^^^^^^^^^^^^ `(&str,)` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `(&str,)`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+ = note: this error originates in the attribute macro `tracing::instrument` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0277]: `(&str,)` doesn't implement `std::fmt::Display`
+ --> tests/ui/async_instrument.rs:15:34
+ |
+15 | async fn opaque_unsatisfied() -> impl std::fmt::Display {
+ | ^^^^^^^^^^^^^^^^^^^^^^ `(&str,)` cannot be formatted with the default formatter
+ |
+ = help: the trait `std::fmt::Display` is not implemented for `(&str,)`
+ = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:23:5
+ |
+23 | ""
+ | ^^ expected struct `Wrapper`, found `&str`
+ |
+ = note: expected struct `Wrapper<_>`
+ found reference `&'static str`
+note: return type inferred to be `Wrapper<_>` here
+ --> tests/ui/async_instrument.rs:22:36
+ |
+22 | async fn mismatch_with_opaque() -> Wrapper<impl std::fmt::Display> {
+ | ^^^^^^^
+help: try wrapping the expression in `Wrapper`
+ |
+23 | Wrapper("")
+ | ++++++++ +
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:29:16
+ |
+29 | return "";
+ | ^^ expected `()`, found `&str`
+ |
+note: return type inferred to be `()` here
+ --> tests/ui/async_instrument.rs:27:10
+ |
+27 | async fn early_return_unit() {
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:36:16
+ |
+36 | return "";
+ | ^^- help: try using a conversion method: `.to_string()`
+ | |
+ | expected struct `String`, found `&str`
+ |
+note: return type inferred to be `String` here
+ --> tests/ui/async_instrument.rs:34:28
+ |
+34 | async fn early_return() -> String {
+ | ^^^^^^
+
+error[E0308]: mismatched types
+ --> tests/ui/async_instrument.rs:42:35
+ |
+42 | async fn extra_semicolon() -> i32 {
+ | ___________________________________^
+43 | | 1;
+ | | - help: remove this semicolon
+44 | | }
+ | |_^ expected `i32`, found `()`
diff --git a/third_party/rust/tracing-core/.cargo-checksum.json b/third_party/rust/tracing-core/.cargo-checksum.json
new file mode 100644
index 0000000000..6a9cec13f3
--- /dev/null
+++ b/third_party/rust/tracing-core/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"93400b6ed3661b8f238549f19e55b0482da163a4504080785fefdcdc8b719198","Cargo.toml":"798de58e851a5cc16f76850f08ab381628c3858a438c31a3fa3e35c06e60992c","LICENSE":"898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1","README.md":"5f5e27d08d3c5ae5f8cc304fcd71ecc61f0c61b27e4bd983c89558805353479d","src/callsite.rs":"479f3b3809afff20ac2a4652f11ec1adc8dd59bd90c608e4e248de4a43c5a43c","src/dispatcher.rs":"16c0ceb3e9de5b7c1365d1c8cc010d12048569d3e9b1146b99b3ea3f0f582ba8","src/event.rs":"f2673bf5d266972e567e521c9cd92fb33f28b0c7e010937e3bc2bf9eb483087f","src/field.rs":"4ec913012ffcf05d3feba2a5ea2ba99c35e2072dabfa2db75614c0e122961b7e","src/lazy.rs":"318e3558e4446abf26294287167c0788e343044a28072f9217bd985929809087","src/lib.rs":"088b29ecce4bdb5b68df9cbe3984f4b22d7124988866d5aace0e7029ea033d58","src/metadata.rs":"1a79326aee210b9e20eb08d5baa22133390f2b1e868cf4dc72a3e9bc9a37d17f","src/parent.rs":"5d5ad733343280a64a1feb6a008e186c39305ec554f14279012b8d7915821471","src/span.rs":"dcf2135e4ca158c1be45007f0be25426c375a4081f8f3c5a4d7f7382d8a950a4","src/spin/LICENSE":"58545fed1565e42d687aecec6897d35c6d37ccb71479a137c0deb2203e125c79","src/spin/mod.rs":"c458ce5e875acb7fbfb279f23254f4924d7c6d6fee419b740800d2e8087d1524","src/spin/mutex.rs":"4d30ff2b59b18fd7909f016e1abdf9aa0c04aa11d047a46e98cffe1319e32dad","src/spin/once.rs":"3781fd4eae0db04d80c03a039906c99b1e01d1583b29ac0144e6fbbd5a0fef0b","src/stdlib.rs":"698693062b8109cace3ffea02e9c2372b7d5b5d43c0b11cb4800b0e7b1a69971","src/subscriber.rs":"baef1454ccf5f552b0a7ba6840eeeca19f7edf21e0303607b86e9e5ffc989a38","tests/common/mod.rs":"0bbb217baa17df0f96cc1ff57dfa74ccc5a959e7f66b15bb7d25d5f43358a278","tests/dispatch.rs":"d3f000fab43734a854c82a7783142910c5e79f806cbd3f8ec5eded598c59ddb1","tests/global_dispatch.rs":"cdc05d77e448ee8b50bfb930abafa3f19b4c6f922b7bebc7797fa1dbdaa1d398","tests/macros.rs":"b1603d888b349c8d103794deceec3b1ae4538b8d3eba805f3f561899e8ad0dd2"},"package":"24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"} \ No newline at end of file
diff --git a/third_party/rust/tracing-core/CHANGELOG.md b/third_party/rust/tracing-core/CHANGELOG.md
new file mode 100644
index 0000000000..cf0d8e3b95
--- /dev/null
+++ b/third_party/rust/tracing-core/CHANGELOG.md
@@ -0,0 +1,495 @@
+# 0.1.30 (October 6, 2022)
+
+This release of `tracing-core` adds a new `on_register_dispatch` method to the
+`Subscriber` trait to allow the `Subscriber` to perform initialization after
+being registered as a `Dispatch`, and a `WeakDispatch` type to allow a
+`Subscriber` to store its own `Dispatch` without creating reference count
+cycles.
+
+### Added
+
+- `Subscriber::on_register_dispatch` method ([#2269])
+- `WeakDispatch` type and `Dispatch::downgrade()` function ([#2293])
+
+Thanks to @jswrenn for contributing to this release!
+
+[#2269]: https://github.com/tokio-rs/tracing/pull/2269
+[#2293]: https://github.com/tokio-rs/tracing/pull/2293
+
+# 0.1.29 (July 29, 2022)
+
+This release of `tracing-core` adds `PartialEq` and `Eq` implementations for
+metadata types, and improves error messages when setting the global default
+subscriber fails.
+
+### Added
+
+- `PartialEq` and `Eq` implementations for `Metadata` ([#2229])
+- `PartialEq` and `Eq` implementations for `FieldSet` ([#2229])
+
+### Fixed
+
+- Fixed unhelpful `fmt::Debug` output for `dispatcher::SetGlobalDefaultError`
+ ([#2250])
+- Fixed compilation with `-Z minimal-versions` ([#2246])
+
+Thanks to @jswrenn and @CAD97 for contributing to this release!
+
+[#2229]: https://github.com/tokio-rs/tracing/pull/2229
+[#2246]: https://github.com/tokio-rs/tracing/pull/2246
+[#2250]: https://github.com/tokio-rs/tracing/pull/2250
+
+# 0.1.28 (June 23, 2022)
+
+This release of `tracing-core` adds new `Value` implementations, including one
+for `String`, to allow recording `&String` as a value without having to call
+`as_str()` or similar, and for 128-bit integers (`i128` and `u128`). In
+addition, it adds new methods and trait implementations for `Subscriber`s.
+
+### Added
+
+- `Value` implementation for `String` ([#2164])
+- `Value` implementation for `u128` and `i28` ([#2166])
+- `downcast_ref` and `is` methods for `dyn Subscriber + Sync`,
+ `dyn Subscriber + Send`, and `dyn Subscriber + Send + Sync` ([#2160])
+- `Subscriber::event_enabled` method to enable filtering based on `Event` field
+ values ([#2008])
+- `Subscriber` implementation for `Box<S: Subscriber + ?Sized>` and
+ `Arc<S: Subscriber + ?Sized>` ([#2161])
+
+Thanks to @jswrenn and @CAD97 for contributing to this release!
+
+[#2164]: https://github.com/tokio-rs/tracing/pull/2164
+[#2166]: https://github.com/tokio-rs/tracing/pull/2166
+[#2160]: https://github.com/tokio-rs/tracing/pull/2160
+[#2008]: https://github.com/tokio-rs/tracing/pull/2008
+[#2161]: https://github.com/tokio-rs/tracing/pull/2161
+
+# 0.1.27 (June 7, 2022)
+
+This release of `tracing-core` introduces a new `DefaultCallsite` type, which
+can be used by instrumentation crates rather than implementing their own
+callsite types. Using `DefaultCallsite` may offer reduced overhead from callsite
+registration.
+
+### Added
+
+- `DefaultCallsite`, a pre-written `Callsite` implementation for use in
+ instrumentation crates ([#2083])
+- `ValueSet::len` and `Record::len` methods returning the number of fields in a
+ `ValueSet` or `Record` ([#2152])
+
+### Changed
+
+- Replaced `lazy_static` dependency with `once_cell` ([#2147])
+
+### Documented
+
+- Added documentation to the `callsite` module ([#2088], [#2149])
+
+Thanks to new contributors @jamesmunns and @james7132 for contributing to this
+release!
+
+[#2083]: https://github.com/tokio-rs/tracing/pull/2083
+[#2152]: https://github.com/tokio-rs/tracing/pull/2152
+[#2147]: https://github.com/tokio-rs/tracing/pull/2147
+[#2088]: https://github.com/tokio-rs/tracing/pull/2088
+[#2149]: https://github.com/tokio-rs/tracing/pull/2149
+
+# 0.1.26 (April 14, 2022)
+
+This release adds a `Value` implementation for `Box<T: Value>` to allow
+recording boxed values more conveniently. In particular, this should improve
+the ergonomics of the implementations for `dyn std::error::Error` trait objects,
+including those added in [v0.1.25].
+
+### Added
+
+- `Value` implementation for `Box<T> where T: Value` ([#2071])
+
+### Fixed
+
+- Broken documentation links ([#2068])
+
+Thanks to new contributor @ben0x539 for contributing to this release!
+
+
+[v0.1.25]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.25
+[#2071]: https://github.com/tokio-rs/tracing/pull/2071
+[#2068]: https://github.com/tokio-rs/tracing/pull/2068
+
+# 0.1.25 (April 12, 2022)
+
+This release adds additional `Value` implementations for `std::error::Error`
+trait objects with auto trait bounds (`Send` and `Sync`), as Rust will not
+auto-coerce trait objects. Additionally, it fixes a bug when setting scoped
+dispatchers that was introduced in the previous release ([v0.1.24]).
+
+### Added
+
+- `Value` implementations for `dyn Error + Send + 'static`, `dyn Error + Send +
+ Sync + 'static`, `dyn Error + Sync + 'static` ([#2066])
+
+### Fixed
+
+- Failure to use the global default dispatcher if a thread has set a scoped
+ default prior to setting the global default, and unset the scoped default
+ after setting the global default ([#2065])
+
+Thanks to @lilyball for contributing to this release!
+
+[v0.1.24]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.24
+[#2066]: https://github.com/tokio-rs/tracing/pull/2066
+[#2065]: https://github.com/tokio-rs/tracing/pull/2065
+
+# 0.1.24 (April 1, 2022)
+
+This release fixes a bug where setting `NoSubscriber` as the local default would
+not disable the global default subscriber locally.
+
+### Fixed
+
+- Setting `NoSubscriber` as the local default now correctly disables the global
+ default subscriber ([#2001])
+- Fixed compilation warnings with the "std" feature disabled ([#2022])
+
+### Changed
+
+- Removed unnecessary use of `write!` and `format_args!` macros ([#1988])
+
+[#1988]: https://github.com/tokio-rs/tracing/pull/1988
+[#2001]: https://github.com/tokio-rs/tracing/pull/2001
+[#2022]: https://github.com/tokio-rs/tracing/pull/2022
+
+# 0.1.23 (March 8, 2022)
+
+### Changed
+
+- Removed `#[inline]` attributes from some `Dispatch` methods whose
+ callers are now inlined ([#1974])
+- Bumped minimum supported Rust version (MSRV) to Rust 1.49.0 ([#1913])
+
+[#1913]: https://github.com/tokio-rs/tracing/pull/1913
+[#1974]: https://github.com/tokio-rs/tracing/pull/1974
+
+# 0.1.22 (February 3, 2022)
+
+This release adds *experimental* support for recording structured field values
+using the [`valuable`] crate. See [this blog post][post] for details on
+`valuable`.
+
+Note that `valuable` support currently requires `--cfg tracing_unstable`. See
+the documentation for details.
+
+### Added
+
+- **field**: Experimental support for recording field values using the
+ [`valuable`] crate ([#1608], [#1888], [#1887])
+- **field**: Added `ValueSet::record` method ([#1823])
+- **subscriber**: `Default` impl for `NoSubscriber` ([#1785])
+- **metadata**: New `Kind::HINT` to support the `enabled!` macro in `tracing`
+ ([#1883], [#1891])
+### Fixed
+
+- Fixed a number of documentation issues ([#1665], [#1692], [#1737])
+
+Thanks to @xd009642, @Skepfyr, @guswynn, @Folyd, and @mbergkvist for
+contributing to this release!
+
+[`valuable`]: https://crates.io/crates/valuable
+[post]: https://tokio.rs/blog/2021-05-valuable
+[#1608]: https://github.com/tokio-rs/tracing/pull/1608
+[#1888]: https://github.com/tokio-rs/tracing/pull/1888
+[#1887]: https://github.com/tokio-rs/tracing/pull/1887
+[#1823]: https://github.com/tokio-rs/tracing/pull/1823
+[#1785]: https://github.com/tokio-rs/tracing/pull/1785
+[#1883]: https://github.com/tokio-rs/tracing/pull/1883
+[#1891]: https://github.com/tokio-rs/tracing/pull/1891
+[#1665]: https://github.com/tokio-rs/tracing/pull/1665
+[#1692]: https://github.com/tokio-rs/tracing/pull/1692
+[#1737]: https://github.com/tokio-rs/tracing/pull/1737
+
+# 0.1.21 (October 1, 2021)
+
+This release adds support for recording `Option<T> where T: Value` as typed
+`tracing` field values.
+
+### Added
+
+- **field**: `Value` impl for `Option<T> where T: Value` ([#1585])
+
+### Fixed
+
+- Fixed deprecation warnings when building with `default-features` disabled
+ ([#1603], [#1606])
+- Documentation fixes and improvements ([#1595], [#1601])
+
+Thanks to @brianburgers, @DCjanus, and @matklad for contributing to this
+release!
+
+[#1585]: https://github.com/tokio-rs/tracing/pull/1585
+[#1595]: https://github.com/tokio-rs/tracing/pull/1595
+[#1601]: https://github.com/tokio-rs/tracing/pull/1601
+[#1603]: https://github.com/tokio-rs/tracing/pull/1603
+[#1606]: https://github.com/tokio-rs/tracing/pull/1606
+
+# 0.1.20 (September 12, 2021)
+
+This release adds support for `f64` as one of the `tracing-core`
+primitive field values, allowing floating-point values to be recorded as
+typed values rather than with `fmt::Debug`. Additionally, it adds
+`NoSubscriber`, a `Subscriber` implementation that does nothing.
+
+### Added
+
+- **subscriber**: `NoSubscriber`, a no-op `Subscriber` implementation
+ ([#1549])
+- **field**: Added `Visit::record_f64` and support for recording
+ floating-point values ([#1507])
+
+Thanks to new contributors @jsgf and @maxburke for contributing to this
+release!
+
+[#1549]: https://github.com/tokio-rs/tracing/pull/1549
+[#1507]: https://github.com/tokio-rs/tracing/pull/1507
+
+# 0.1.19 (August 17, 2021)
+### Added
+
+- `Level::as_str` ([#1413])
+- `Hash` implementation for `Level` and `LevelFilter` ([#1456])
+- `Value` implementation for `&mut T where T: Value` ([#1385])
+- Multiple documentation fixes and improvements ([#1435], [#1446])
+
+Thanks to @Folyd, @teozkr, and @dvdplm for contributing to this release!
+
+[#1413]: https://github.com/tokio-rs/tracing/pull/1413
+[#1456]: https://github.com/tokio-rs/tracing/pull/1456
+[#1385]: https://github.com/tokio-rs/tracing/pull/1385
+[#1435]: https://github.com/tokio-rs/tracing/pull/1435
+[#1446]: https://github.com/tokio-rs/tracing/pull/1446
+
+# 0.1.18 (April 30, 2021)
+
+### Added
+
+- `Subscriber` impl for `Box<dyn Subscriber + Send + Sync + 'static>` ([#1358])
+- `Subscriber` impl for `Arc<dyn Subscriber + Send + Sync + 'static>` ([#1374])
+- Symmetric `From` impls for existing `Into` impls on `Current` and `Option<Id>`
+ ([#1335])
+- `Attributes::fields` accessor that returns the set of fields defined on a
+ span's `Attributes` ([#1331])
+
+
+Thanks to @Folyd for contributing to this release!
+
+[#1358]: https://github.com/tokio-rs/tracing/pull/1358
+[#1374]: https://github.com/tokio-rs/tracing/pull/1374
+[#1335]: https://github.com/tokio-rs/tracing/pull/1335
+[#1331]: https://github.com/tokio-rs/tracing/pull/1331
+
+# 0.1.17 (September 28, 2020)
+
+### Fixed
+
+- Incorrect inlining of `Event::dispatch` and `Event::child_of`, which could
+ result in `dispatcher::get_default` being inlined at the callsite ([#994])
+
+### Added
+
+- `Copy` implementations for `Level` and `LevelFilter` ([#992])
+
+Thanks to new contributors @jyn514 and @TaKO8Ki for contributing to this
+release!
+
+[#994]: https://github.com/tokio-rs/tracing/pull/994
+[#992]: https://github.com/tokio-rs/tracing/pull/992
+
+# 0.1.16 (September 8, 2020)
+
+### Fixed
+
+- Added a conversion from `Option<Level>` to `LevelFilter`. This resolves a
+ previously unreported regression where `Option<Level>` was no longer
+ a valid LevelFilter. ([#966](https://github.com/tokio-rs/tracing/pull/966))
+
+# 0.1.15 (August 22, 2020)
+
+### Fixed
+
+- When combining `Interest` from multiple subscribers, if the interests differ,
+ the current subscriber is now always asked if a callsite should be enabled
+ (#927)
+
+## Added
+
+- Internal API changes to support optimizations in the `tracing` crate (#943)
+- **docs**: Multiple fixes and improvements (#913, #941)
+
+# 0.1.14 (August 10, 2020)
+
+### Fixed
+
+- Incorrect calculation of global max level filter which could result in fast
+ filtering paths not being taken (#908)
+
+# 0.1.13 (August 4, 2020)
+
+### Fixed
+
+- Missing `fmt::Display` impl for `field::DisplayValue` causing a compilation
+ failure when the "log" feature is enabled (#887)
+
+Thanks to @d-e-s-o for contributing to this release!
+
+# 0.1.12 (July 31, 2020)
+
+### Added
+
+- `LevelFilter` type and `LevelFilter::current()` for returning the highest level
+ that any subscriber will enable (#853)
+- `Subscriber::max_level_hint` optional trait method, for setting the value
+ returned by `LevelFilter::current()` (#853)
+
+### Fixed
+
+- **docs**: Removed outdated reference to a Tokio API that no longer exists
+ (#857)
+
+Thanks to new contributor @dignati for contributing to this release!
+
+# 0.1.11 (June 8, 2020)
+
+### Changed
+
+- Replaced use of `inner_local_macros` with `$crate::` (#729)
+
+### Added
+
+- `must_use` warning to guards returned by `dispatcher::set_default` (#686)
+- `fmt::Debug` impl to `dyn Value`s (#696)
+- Functions to convert between `span::Id` and `NonZeroU64` (#770)
+- More obvious warnings in documentation (#769)
+
+### Fixed
+
+- Compiler error when `tracing-core/std` feature is enabled but `tracing/std` is
+ not (#760)
+- Clippy warning on vtable address comparison in `callsite::Identifier` (#749)
+- Documentation formatting issues (#715, #771)
+
+Thanks to @bkchr, @majecty, @taiki-e, @nagisa, and @nvzqz for contributing to
+this release!
+
+# 0.1.10 (January 24, 2020)
+
+### Added
+
+- `field::Empty` type for declaring empty fields whose values will be recorded
+ later (#548)
+- `field::Value` implementations for `Wrapping` and `NonZero*` numbers (#538)
+
+### Fixed
+
+- Broken and unresolvable links in RustDoc (#595)
+
+Thanks to @oli-cosmian for contributing to this release!
+
+# 0.1.9 (January 10, 2020)
+
+### Added
+
+- API docs now show what feature flags are required to enable each item (#523)
+
+### Fixed
+
+- A panic when the current default subscriber subscriber calls
+ `dispatcher::with_default` as it is being dropped (#522)
+- Incorrect documentation for `Subscriber::drop_span` (#524)
+
+# 0.1.8 (December 20, 2019)
+
+### Added
+
+- `Default` impl for `Dispatch` (#411)
+
+### Fixed
+
+- Removed duplicate `lazy_static` dependencies (#424)
+- Fixed no-std dependencies being enabled even when `std` feature flag is set
+ (#424)
+- Broken link to `Metadata` in `Event` docs (#461)
+
+# 0.1.7 (October 18, 2019)
+
+### Added
+
+- Added `dispatcher::set_default` API which returns a drop guard (#388)
+
+### Fixed
+
+- Added missing `Value` impl for `u8` (#392)
+- Broken links in docs.
+
+# 0.1.6 (September 12, 2019)
+
+### Added
+
+- Internal APIs to support performance optimizations (#326)
+
+### Fixed
+
+- Clarified wording in `field::display` documentation (#340)
+
+# 0.1.5 (August 16, 2019)
+
+### Added
+
+- `std::error::Error` as a new primitive `Value` type (#277)
+- `Event::new` and `Event::new_child_of` to manually construct `Event`s (#281)
+
+# 0.1.4 (August 9, 2019)
+
+### Added
+
+- Support for `no-std` + `liballoc` (#256)
+
+### Fixed
+
+- Broken links in RustDoc (#259)
+
+# 0.1.3 (August 8, 2019)
+
+### Added
+
+- `std::fmt::Display` implementation for `Level` (#194)
+- `std::str::FromStr` implementation for `Level` (#195)
+
+# 0.1.2 (July 10, 2019)
+
+### Deprecated
+
+- `Subscriber::drop_span` in favor of new `Subscriber::try_close` (#168)
+
+### Added
+
+- `Into<Option<&Id>>`, `Into<Option<Id>>`, and
+ `Into<Option<&'static Metadata<'static>>>` impls for `span::Current` (#170)
+- `Subscriber::try_close` method (#153)
+- Improved documentation for `dispatcher` (#171)
+
+# 0.1.1 (July 6, 2019)
+
+### Added
+
+- `Subscriber::current_span` API to return the current span (#148).
+- `span::Current` type, representing the `Subscriber`'s view of the current
+ span (#148).
+
+### Fixed
+
+- Typos and broken links in documentation (#123, #124, #128, #154)
+
+# 0.1.0 (June 27, 2019)
+
+- Initial release
diff --git a/third_party/rust/tracing-core/Cargo.toml b/third_party/rust/tracing-core/Cargo.toml
new file mode 100644
index 0000000000..806006141b
--- /dev/null
+++ b/third_party/rust/tracing-core/Cargo.toml
@@ -0,0 +1,66 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.49.0"
+name = "tracing-core"
+version = "0.1.30"
+authors = ["Tokio Contributors <team@tokio.rs>"]
+description = """
+Core primitives for application-level tracing.
+"""
+homepage = "https://tokio.rs"
+readme = "README.md"
+keywords = [
+ "logging",
+ "tracing",
+ "profiling",
+]
+categories = [
+ "development-tools::debugging",
+ "development-tools::profiling",
+ "asynchronous",
+]
+license = "MIT"
+repository = "https://github.com/tokio-rs/tracing"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+ "--cfg",
+ "tracing_unstable",
+]
+rustc-args = [
+ "--cfg",
+ "tracing_unstable",
+]
+
+[dependencies.once_cell]
+version = "1.13.0"
+optional = true
+
+[features]
+default = [
+ "std",
+ "valuable/std",
+]
+std = ["once_cell"]
+
+[target."cfg(tracing_unstable)".dependencies.valuable]
+version = "0.1.0"
+optional = true
+default-features = false
+
+[badges.maintenance]
+status = "actively-developed"
diff --git a/third_party/rust/tracing-core/LICENSE b/third_party/rust/tracing-core/LICENSE
new file mode 100644
index 0000000000..cdb28b4b56
--- /dev/null
+++ b/third_party/rust/tracing-core/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2019 Tokio Contributors
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/tracing-core/README.md b/third_party/rust/tracing-core/README.md
new file mode 100644
index 0000000000..f06c760593
--- /dev/null
+++ b/third_party/rust/tracing-core/README.md
@@ -0,0 +1,121 @@
+![Tracing — Structured, application-level diagnostics][splash]
+
+[splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg
+
+# tracing-core
+
+Core primitives for application-level tracing.
+
+[![Crates.io][crates-badge]][crates-url]
+[![Documentation][docs-badge]][docs-url]
+[![Documentation (master)][docs-master-badge]][docs-master-url]
+[![MIT licensed][mit-badge]][mit-url]
+[![Build Status][actions-badge]][actions-url]
+[![Discord chat][discord-badge]][discord-url]
+
+[Documentation][docs-url] | [Chat][discord-url]
+
+[crates-badge]: https://img.shields.io/crates/v/tracing-core.svg
+[crates-url]: https://crates.io/crates/tracing-core/0.1.30
+[docs-badge]: https://docs.rs/tracing-core/badge.svg
+[docs-url]: https://docs.rs/tracing-core/0.1.30
+[docs-master-badge]: https://img.shields.io/badge/docs-master-blue
+[docs-master-url]: https://tracing-rs.netlify.com/tracing_core
+[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
+[mit-url]: LICENSE
+[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg
+[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI
+[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white
+[discord-url]: https://discord.gg/EeF3cQw
+
+## Overview
+
+[`tracing`] is a framework for instrumenting Rust programs to collect
+structured, event-based diagnostic information. This crate defines the core
+primitives of `tracing`.
+
+The crate provides:
+
+* [`span::Id`] identifies a span within the execution of a program.
+
+* [`Event`] represents a single event within a trace.
+
+* [`Subscriber`], the trait implemented to collect trace data.
+
+* [`Metadata`] and [`Callsite`] provide information describing spans and
+ events.
+
+* [`Field`], [`FieldSet`], [`Value`], and [`ValueSet`] represent the
+ structured data attached to spans and events.
+
+* [`Dispatch`] allows spans and events to be dispatched to `Subscriber`s.
+
+In addition, it defines the global callsite registry and per-thread current
+dispatcher which other components of the tracing system rely on.
+
+*Compiler support: [requires `rustc` 1.49+][msrv]*
+
+[msrv]: #supported-rust-versions
+
+## Usage
+
+Application authors will typically not use this crate directly. Instead, they
+will use the [`tracing`] crate, which provides a much more fully-featured
+API. However, this crate's API will change very infrequently, so it may be used
+when dependencies must be very stable.
+
+`Subscriber` implementations may depend on `tracing-core` rather than `tracing`,
+as the additional APIs provided by `tracing` are primarily useful for
+instrumenting libraries and applications, and are generally not necessary for
+`Subscriber` implementations.
+
+### Crate Feature Flags
+
+The following crate feature flags are available:
+
+* `std`: Depend on the Rust standard library (enabled by default).
+
+ `no_std` users may disable this feature with `default-features = false`:
+
+ ```toml
+ [dependencies]
+ tracing-core = { version = "0.1.30", default-features = false }
+ ```
+
+ **Note**:`tracing-core`'s `no_std` support requires `liballoc`.
+
+[`tracing`]: ../tracing
+[`span::Id`]: https://docs.rs/tracing-core/0.1.30/tracing_core/span/struct.Id.html
+[`Event`]: https://docs.rs/tracing-core/0.1.30/tracing_core/event/struct.Event.html
+[`Subscriber`]: https://docs.rs/tracing-core/0.1.30/tracing_core/subscriber/trait.Subscriber.html
+[`Metadata`]: https://docs.rs/tracing-core/0.1.30/tracing_core/metadata/struct.Metadata.html
+[`Callsite`]: https://docs.rs/tracing-core/0.1.30/tracing_core/callsite/trait.Callsite.html
+[`Field`]: https://docs.rs/tracing-core/0.1.30/tracing_core/field/struct.Field.html
+[`FieldSet`]: https://docs.rs/tracing-core/0.1.30/tracing_core/field/struct.FieldSet.html
+[`Value`]: https://docs.rs/tracing-core/0.1.30/tracing_core/field/trait.Value.html
+[`ValueSet`]: https://docs.rs/tracing-core/0.1.30/tracing_core/field/struct.ValueSet.html
+[`Dispatch`]: https://docs.rs/tracing-core/0.1.30/tracing_core/dispatcher/struct.Dispatch.html
+
+## Supported Rust Versions
+
+Tracing is built against the latest stable release. The minimum supported
+version is 1.49. The current Tracing version is not guaranteed to build on Rust
+versions earlier than the minimum supported version.
+
+Tracing follows the same compiler support policies as the rest of the Tokio
+project. The current stable Rust compiler and the three most recent minor
+versions before it will always be supported. For example, if the current stable
+compiler version is 1.45, the minimum supported version will not be increased
+past 1.42, three minor versions prior. Increasing the minimum supported compiler
+version is not considered a semver breaking change as long as doing so complies
+with this policy.
+
+## License
+
+This project is licensed under the [MIT license](LICENSE).
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Tokio by you, shall be licensed as MIT, without any additional
+terms or conditions.
diff --git a/third_party/rust/tracing-core/src/callsite.rs b/third_party/rust/tracing-core/src/callsite.rs
new file mode 100644
index 0000000000..f887132364
--- /dev/null
+++ b/third_party/rust/tracing-core/src/callsite.rs
@@ -0,0 +1,621 @@
+//! Callsites represent the source locations from which spans or events
+//! originate.
+//!
+//! # What Are Callsites?
+//!
+//! Every span or event in `tracing` is associated with a [`Callsite`]. A
+//! callsite is a small `static` value that is responsible for the following:
+//!
+//! * Storing the span or event's [`Metadata`],
+//! * Uniquely [identifying](Identifier) the span or event definition,
+//! * Caching the subscriber's [`Interest`][^1] in that span or event, to avoid
+//! re-evaluating filters,
+//! * Storing a [`Registration`] that allows the callsite to be part of a global
+//! list of all callsites in the program.
+//!
+//! # Registering Callsites
+//!
+//! When a span or event is recorded for the first time, its callsite
+//! [`register`]s itself with the global callsite registry. Registering a
+//! callsite calls the [`Subscriber::register_callsite`][`register_callsite`]
+//! method with that callsite's [`Metadata`] on every currently active
+//! subscriber. This serves two primary purposes: informing subscribers of the
+//! callsite's existence, and performing static filtering.
+//!
+//! ## Callsite Existence
+//!
+//! If a [`Subscriber`] implementation wishes to allocate storage for each
+//! unique span/event location in the program, or pre-compute some value
+//! that will be used to record that span or event in the future, it can
+//! do so in its [`register_callsite`] method.
+//!
+//! ## Performing Static Filtering
+//!
+//! The [`register_callsite`] method returns an [`Interest`] value,
+//! which indicates that the subscriber either [always] wishes to record
+//! that span or event, [sometimes] wishes to record it based on a
+//! dynamic filter evaluation, or [never] wishes to record it.
+//!
+//! When registering a new callsite, the [`Interest`]s returned by every
+//! currently active subscriber are combined, and the result is stored at
+//! each callsite. This way, when the span or event occurs in the
+//! future, the cached [`Interest`] value can be checked efficiently
+//! to determine if the span or event should be recorded, without
+//! needing to perform expensive filtering (i.e. calling the
+//! [`Subscriber::enabled`] method every time a span or event occurs).
+//!
+//! ### Rebuilding Cached Interest
+//!
+//! When a new [`Dispatch`] is created (i.e. a new subscriber becomes
+//! active), any previously cached [`Interest`] values are re-evaluated
+//! for all callsites in the program. This way, if the new subscriber
+//! will enable a callsite that was not previously enabled, the
+//! [`Interest`] in that callsite is updated. Similarly, when a
+//! subscriber is dropped, the interest cache is also re-evaluated, so
+//! that any callsites enabled only by that subscriber are disabled.
+//!
+//! In addition, the [`rebuild_interest_cache`] function in this module can be
+//! used to manually invalidate all cached interest and re-register those
+//! callsites. This function is useful in situations where a subscriber's
+//! interest can change, but it does so relatively infrequently. The subscriber
+//! may wish for its interest to be cached most of the time, and return
+//! [`Interest::always`][always] or [`Interest::never`][never] in its
+//! [`register_callsite`] method, so that its [`Subscriber::enabled`] method
+//! doesn't need to be evaluated every time a span or event is recorded.
+//! However, when the configuration changes, the subscriber can call
+//! [`rebuild_interest_cache`] to re-evaluate the entire interest cache with its
+//! new configuration. This is a relatively costly operation, but if the
+//! configuration changes infrequently, it may be more efficient than calling
+//! [`Subscriber::enabled`] frequently.
+//!
+//! # Implementing Callsites
+//!
+//! In most cases, instrumenting code using `tracing` should *not* require
+//! implementing the [`Callsite`] trait directly. When using the [`tracing`
+//! crate's macros][macros] or the [`#[instrument]` attribute][instrument], a
+//! `Callsite` is automatically generated.
+//!
+//! However, code which provides alternative forms of `tracing` instrumentation
+//! may need to interact with the callsite system directly. If
+//! instrumentation-side code needs to produce a `Callsite` to emit spans or
+//! events, the [`DefaultCallsite`] struct provided in this module is a
+//! ready-made `Callsite` implementation that is suitable for most uses. When
+//! possible, the use of `DefaultCallsite` should be preferred over implementing
+//! [`Callsite`] for user types, as `DefaultCallsite` may benefit from
+//! additional performance optimizations.
+//!
+//! [^1]: Returned by the [`Subscriber::register_callsite`][`register_callsite`]
+//! method.
+//!
+//! [`Metadata`]: crate::metadata::Metadata
+//! [`Interest`]: crate::subscriber::Interest
+//! [`Subscriber`]: crate::subscriber::Subscriber
+//! [`register_callsite`]: crate::subscriber::Subscriber::register_callsite
+//! [`Subscriber::enabled`]: crate::subscriber::Subscriber::enabled
+//! [always]: crate::subscriber::Interest::always
+//! [sometimes]: crate::subscriber::Interest::sometimes
+//! [never]: crate::subscriber::Interest::never
+//! [`Dispatch`]: crate::dispatch::Dispatch
+//! [macros]: https://docs.rs/tracing/latest/tracing/#macros
+//! [instrument]: https://docs.rs/tracing/latest/tracing/attr.instrument.html
+use crate::stdlib::{
+ any::TypeId,
+ fmt,
+ hash::{Hash, Hasher},
+ ptr,
+ sync::{
+ atomic::{AtomicBool, AtomicPtr, AtomicU8, Ordering},
+ Mutex,
+ },
+ vec::Vec,
+};
+use crate::{
+ dispatcher::Dispatch,
+ lazy::Lazy,
+ metadata::{LevelFilter, Metadata},
+ subscriber::Interest,
+};
+
+use self::dispatchers::Dispatchers;
+
+/// Trait implemented by callsites.
+///
+/// These functions are only intended to be called by the callsite registry, which
+/// correctly handles determining the common interest between all subscribers.
+///
+/// See the [module-level documentation](crate::callsite) for details on
+/// callsites.
+pub trait Callsite: Sync {
+ /// Sets the [`Interest`] for this callsite.
+ ///
+ /// See the [documentation on callsite interest caching][cache-docs] for
+ /// details.
+ ///
+ /// [`Interest`]: super::subscriber::Interest
+ /// [cache-docs]: crate::callsite#performing-static-filtering
+ fn set_interest(&self, interest: Interest);
+
+ /// Returns the [metadata] associated with the callsite.
+ ///
+ /// <div class="example-wrap" style="display:inline-block">
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ ///
+ /// **Note:** Implementations of this method should not produce [`Metadata`]
+ /// that share the same callsite [`Identifier`] but otherwise differ in any
+ /// way (e.g., have different `name`s).
+ ///
+ /// </pre></div>
+ ///
+ /// [metadata]: super::metadata::Metadata
+ fn metadata(&self) -> &Metadata<'_>;
+
+ /// This method is an *internal implementation detail* of `tracing-core`. It
+ /// is *not* intended to be called or overridden from downstream code.
+ ///
+ /// The `Private` type can only be constructed from within `tracing-core`.
+ /// Because this method takes a `Private` as an argument, it cannot be
+ /// called from (safe) code external to `tracing-core`. Because it must
+ /// *return* a `Private`, the only valid implementation possible outside of
+ /// `tracing-core` would have to always unconditionally panic.
+ ///
+ /// THIS IS BY DESIGN. There is currently no valid reason for code outside
+ /// of `tracing-core` to override this method.
+ // TODO(eliza): this could be used to implement a public downcasting API
+ // for `&dyn Callsite`s in the future.
+ #[doc(hidden)]
+ #[inline]
+ fn private_type_id(&self, _: private::Private<()>) -> private::Private<TypeId>
+ where
+ Self: 'static,
+ {
+ private::Private(TypeId::of::<Self>())
+ }
+}
+
+/// Uniquely identifies a [`Callsite`]
+///
+/// Two `Identifier`s are equal if they both refer to the same callsite.
+///
+/// [`Callsite`]: super::callsite::Callsite
+#[derive(Clone)]
+pub struct Identifier(
+ /// **Warning**: The fields on this type are currently `pub` because it must
+ /// be able to be constructed statically by macros. However, when `const
+ /// fn`s are available on stable Rust, this will no longer be necessary.
+ /// Thus, these fields are *not* considered stable public API, and they may
+ /// change warning. Do not rely on any fields on `Identifier`. When
+ /// constructing new `Identifier`s, use the `identify_callsite!` macro
+ /// instead.
+ #[doc(hidden)]
+ pub &'static dyn Callsite,
+);
+
+/// A default [`Callsite`] implementation.
+#[derive(Debug)]
+pub struct DefaultCallsite {
+ interest: AtomicU8,
+ registration: AtomicU8,
+ meta: &'static Metadata<'static>,
+ next: AtomicPtr<Self>,
+}
+
+/// Clear and reregister interest on every [`Callsite`]
+///
+/// This function is intended for runtime reconfiguration of filters on traces
+/// when the filter recalculation is much less frequent than trace events are.
+/// The alternative is to have the [`Subscriber`] that supports runtime
+/// reconfiguration of filters always return [`Interest::sometimes()`] so that
+/// [`enabled`] is evaluated for every event.
+///
+/// This function will also re-compute the global maximum level as determined by
+/// the [`max_level_hint`] method. If a [`Subscriber`]
+/// implementation changes the value returned by its `max_level_hint`
+/// implementation at runtime, then it **must** call this function after that
+/// value changes, in order for the change to be reflected.
+///
+/// See the [documentation on callsite interest caching][cache-docs] for
+/// additional information on this function's usage.
+///
+/// [`max_level_hint`]: super::subscriber::Subscriber::max_level_hint
+/// [`Callsite`]: super::callsite::Callsite
+/// [`enabled`]: super::subscriber::Subscriber#tymethod.enabled
+/// [`Interest::sometimes()`]: super::subscriber::Interest::sometimes
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [cache-docs]: crate::callsite#rebuilding-cached-interest
+pub fn rebuild_interest_cache() {
+ CALLSITES.rebuild_interest(DISPATCHERS.rebuilder());
+}
+
+/// Register a new [`Callsite`] with the global registry.
+///
+/// This should be called once per callsite after the callsite has been
+/// constructed.
+///
+/// See the [documentation on callsite registration][reg-docs] for details
+/// on the global callsite registry.
+///
+/// [`Callsite`]: crate::callsite::Callsite
+/// [reg-docs]: crate::callsite#registering-callsites
+pub fn register(callsite: &'static dyn Callsite) {
+ rebuild_callsite_interest(callsite, &DISPATCHERS.rebuilder());
+
+ // Is this a `DefaultCallsite`? If so, use the fancy linked list!
+ if callsite.private_type_id(private::Private(())).0 == TypeId::of::<DefaultCallsite>() {
+ let callsite = unsafe {
+ // Safety: the pointer cast is safe because the type id of the
+ // provided callsite matches that of the target type for the cast
+ // (`DefaultCallsite`). Because user implementations of `Callsite`
+ // cannot override `private_type_id`, we can trust that the callsite
+ // is not lying about its type ID.
+ &*(callsite as *const dyn Callsite as *const DefaultCallsite)
+ };
+ CALLSITES.push_default(callsite);
+ return;
+ }
+
+ CALLSITES.push_dyn(callsite);
+}
+
+static CALLSITES: Callsites = Callsites {
+ list_head: AtomicPtr::new(ptr::null_mut()),
+ has_locked_callsites: AtomicBool::new(false),
+};
+
+static DISPATCHERS: Dispatchers = Dispatchers::new();
+
+static LOCKED_CALLSITES: Lazy<Mutex<Vec<&'static dyn Callsite>>> = Lazy::new(Default::default);
+
+struct Callsites {
+ list_head: AtomicPtr<DefaultCallsite>,
+ has_locked_callsites: AtomicBool,
+}
+
+// === impl DefaultCallsite ===
+
+impl DefaultCallsite {
+ const UNREGISTERED: u8 = 0;
+ const REGISTERING: u8 = 1;
+ const REGISTERED: u8 = 2;
+
+ const INTEREST_NEVER: u8 = 0;
+ const INTEREST_SOMETIMES: u8 = 1;
+ const INTEREST_ALWAYS: u8 = 2;
+
+ /// Returns a new `DefaultCallsite` with the specified `Metadata`.
+ pub const fn new(meta: &'static Metadata<'static>) -> Self {
+ Self {
+ interest: AtomicU8::new(0xFF),
+ meta,
+ next: AtomicPtr::new(ptr::null_mut()),
+ registration: AtomicU8::new(Self::UNREGISTERED),
+ }
+ }
+
+ /// Registers this callsite with the global callsite registry.
+ ///
+ /// If the callsite is already registered, this does nothing. When using
+ /// [`DefaultCallsite`], this method should be preferred over
+ /// [`tracing_core::callsite::register`], as it ensures that the callsite is
+ /// only registered a single time.
+ ///
+ /// Other callsite implementations will generally ensure that
+ /// callsites are not re-registered through another mechanism.
+ ///
+ /// See the [documentation on callsite registration][reg-docs] for details
+ /// on the global callsite registry.
+ ///
+ /// [`Callsite`]: crate::callsite::Callsite
+ /// [reg-docs]: crate::callsite#registering-callsites
+ #[inline(never)]
+ // This only happens once (or if the cached interest value was corrupted).
+ #[cold]
+ pub fn register(&'static self) -> Interest {
+ // Attempt to advance the registration state to `REGISTERING`...
+ match self.registration.compare_exchange(
+ Self::UNREGISTERED,
+ Self::REGISTERING,
+ Ordering::AcqRel,
+ Ordering::Acquire,
+ ) {
+ Ok(_) => {
+ // Okay, we advanced the state, try to register the callsite.
+ rebuild_callsite_interest(self, &DISPATCHERS.rebuilder());
+ CALLSITES.push_default(self);
+ self.registration.store(Self::REGISTERED, Ordering::Release);
+ }
+ // Great, the callsite is already registered! Just load its
+ // previous cached interest.
+ Err(Self::REGISTERED) => {}
+ // Someone else is registering...
+ Err(_state) => {
+ debug_assert_eq!(
+ _state,
+ Self::REGISTERING,
+ "weird callsite registration state"
+ );
+ // Just hit `enabled` this time.
+ return Interest::sometimes();
+ }
+ }
+
+ match self.interest.load(Ordering::Relaxed) {
+ Self::INTEREST_NEVER => Interest::never(),
+ Self::INTEREST_ALWAYS => Interest::always(),
+ _ => Interest::sometimes(),
+ }
+ }
+
+ /// Returns the callsite's cached `Interest`, or registers it for the
+ /// first time if it has not yet been registered.
+ #[inline]
+ pub fn interest(&'static self) -> Interest {
+ match self.interest.load(Ordering::Relaxed) {
+ Self::INTEREST_NEVER => Interest::never(),
+ Self::INTEREST_SOMETIMES => Interest::sometimes(),
+ Self::INTEREST_ALWAYS => Interest::always(),
+ _ => self.register(),
+ }
+ }
+}
+
+impl Callsite for DefaultCallsite {
+ fn set_interest(&self, interest: Interest) {
+ let interest = match () {
+ _ if interest.is_never() => Self::INTEREST_NEVER,
+ _ if interest.is_always() => Self::INTEREST_ALWAYS,
+ _ => Self::INTEREST_SOMETIMES,
+ };
+ self.interest.store(interest, Ordering::SeqCst);
+ }
+
+ #[inline(always)]
+ fn metadata(&self) -> &Metadata<'static> {
+ self.meta
+ }
+}
+
+// ===== impl Identifier =====
+
+impl PartialEq for Identifier {
+ fn eq(&self, other: &Identifier) -> bool {
+ core::ptr::eq(
+ self.0 as *const _ as *const (),
+ other.0 as *const _ as *const (),
+ )
+ }
+}
+
+impl Eq for Identifier {}
+
+impl fmt::Debug for Identifier {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "Identifier({:p})", self.0)
+ }
+}
+
+impl Hash for Identifier {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ (self.0 as *const dyn Callsite).hash(state)
+ }
+}
+
+// === impl Callsites ===
+
+impl Callsites {
+ /// Rebuild `Interest`s for all callsites in the registry.
+ ///
+ /// This also re-computes the max level hint.
+ fn rebuild_interest(&self, dispatchers: dispatchers::Rebuilder<'_>) {
+ let mut max_level = LevelFilter::OFF;
+ dispatchers.for_each(|dispatch| {
+ // If the subscriber did not provide a max level hint, assume
+ // that it may enable every level.
+ let level_hint = dispatch.max_level_hint().unwrap_or(LevelFilter::TRACE);
+ if level_hint > max_level {
+ max_level = level_hint;
+ }
+ });
+
+ self.for_each(|callsite| {
+ rebuild_callsite_interest(callsite, &dispatchers);
+ });
+ LevelFilter::set_max(max_level);
+ }
+
+ /// Push a `dyn Callsite` trait object to the callsite registry.
+ ///
+ /// This will attempt to lock the callsites vector.
+ fn push_dyn(&self, callsite: &'static dyn Callsite) {
+ let mut lock = LOCKED_CALLSITES.lock().unwrap();
+ self.has_locked_callsites.store(true, Ordering::Release);
+ lock.push(callsite);
+ }
+
+ /// Push a `DefaultCallsite` to the callsite registry.
+ ///
+ /// If we know the callsite being pushed is a `DefaultCallsite`, we can push
+ /// it to the linked list without having to acquire a lock.
+ fn push_default(&self, callsite: &'static DefaultCallsite) {
+ let mut head = self.list_head.load(Ordering::Acquire);
+
+ loop {
+ callsite.next.store(head, Ordering::Release);
+
+ assert_ne!(
+ callsite as *const _, head,
+ "Attempted to register a `DefaultCallsite` that already exists! \
+ This will cause an infinite loop when attempting to read from the \
+ callsite cache. This is likely a bug! You should only need to call \
+ `DefaultCallsite::register` once per `DefaultCallsite`."
+ );
+
+ match self.list_head.compare_exchange(
+ head,
+ callsite as *const _ as *mut _,
+ Ordering::AcqRel,
+ Ordering::Acquire,
+ ) {
+ Ok(_) => {
+ break;
+ }
+ Err(current) => head = current,
+ }
+ }
+ }
+
+ /// Invokes the provided closure `f` with each callsite in the registry.
+ fn for_each(&self, mut f: impl FnMut(&'static dyn Callsite)) {
+ let mut head = self.list_head.load(Ordering::Acquire);
+
+ while let Some(cs) = unsafe { head.as_ref() } {
+ f(cs);
+
+ head = cs.next.load(Ordering::Acquire);
+ }
+
+ if self.has_locked_callsites.load(Ordering::Acquire) {
+ let locked = LOCKED_CALLSITES.lock().unwrap();
+ for &cs in locked.iter() {
+ f(cs);
+ }
+ }
+ }
+}
+
+pub(crate) fn register_dispatch(dispatch: &Dispatch) {
+ let dispatchers = DISPATCHERS.register_dispatch(dispatch);
+ dispatch.subscriber().on_register_dispatch(dispatch);
+ CALLSITES.rebuild_interest(dispatchers);
+}
+
+fn rebuild_callsite_interest(
+ callsite: &'static dyn Callsite,
+ dispatchers: &dispatchers::Rebuilder<'_>,
+) {
+ let meta = callsite.metadata();
+
+ let mut interest = None;
+ dispatchers.for_each(|dispatch| {
+ let this_interest = dispatch.register_callsite(meta);
+ interest = match interest.take() {
+ None => Some(this_interest),
+ Some(that_interest) => Some(that_interest.and(this_interest)),
+ }
+ });
+
+ let interest = interest.unwrap_or_else(Interest::never);
+ callsite.set_interest(interest)
+}
+
+mod private {
+ /// Don't call this function, it's private.
+ #[allow(missing_debug_implementations)]
+ pub struct Private<T>(pub(crate) T);
+}
+
+#[cfg(feature = "std")]
+mod dispatchers {
+ use crate::{dispatcher, lazy::Lazy};
+ use std::sync::{
+ atomic::{AtomicBool, Ordering},
+ RwLock, RwLockReadGuard, RwLockWriteGuard,
+ };
+
+ pub(super) struct Dispatchers {
+ has_just_one: AtomicBool,
+ }
+
+ static LOCKED_DISPATCHERS: Lazy<RwLock<Vec<dispatcher::Registrar>>> =
+ Lazy::new(Default::default);
+
+ pub(super) enum Rebuilder<'a> {
+ JustOne,
+ Read(RwLockReadGuard<'a, Vec<dispatcher::Registrar>>),
+ Write(RwLockWriteGuard<'a, Vec<dispatcher::Registrar>>),
+ }
+
+ impl Dispatchers {
+ pub(super) const fn new() -> Self {
+ Self {
+ has_just_one: AtomicBool::new(true),
+ }
+ }
+
+ pub(super) fn rebuilder(&self) -> Rebuilder<'_> {
+ if self.has_just_one.load(Ordering::SeqCst) {
+ return Rebuilder::JustOne;
+ }
+ Rebuilder::Read(LOCKED_DISPATCHERS.read().unwrap())
+ }
+
+ pub(super) fn register_dispatch(&self, dispatch: &dispatcher::Dispatch) -> Rebuilder<'_> {
+ let mut dispatchers = LOCKED_DISPATCHERS.write().unwrap();
+ dispatchers.retain(|d| d.upgrade().is_some());
+ dispatchers.push(dispatch.registrar());
+ self.has_just_one
+ .store(dispatchers.len() <= 1, Ordering::SeqCst);
+ Rebuilder::Write(dispatchers)
+ }
+ }
+
+ impl Rebuilder<'_> {
+ pub(super) fn for_each(&self, mut f: impl FnMut(&dispatcher::Dispatch)) {
+ let iter = match self {
+ Rebuilder::JustOne => {
+ dispatcher::get_default(f);
+ return;
+ }
+ Rebuilder::Read(vec) => vec.iter(),
+ Rebuilder::Write(vec) => vec.iter(),
+ };
+ iter.filter_map(dispatcher::Registrar::upgrade)
+ .for_each(|dispatch| f(&dispatch))
+ }
+ }
+}
+
+#[cfg(not(feature = "std"))]
+mod dispatchers {
+ use crate::dispatcher;
+
+ pub(super) struct Dispatchers(());
+ pub(super) struct Rebuilder<'a>(Option<&'a dispatcher::Dispatch>);
+
+ impl Dispatchers {
+ pub(super) const fn new() -> Self {
+ Self(())
+ }
+
+ pub(super) fn rebuilder(&self) -> Rebuilder<'_> {
+ Rebuilder(None)
+ }
+
+ pub(super) fn register_dispatch<'dispatch>(
+ &self,
+ dispatch: &'dispatch dispatcher::Dispatch,
+ ) -> Rebuilder<'dispatch> {
+ // nop; on no_std, there can only ever be one dispatcher
+ Rebuilder(Some(dispatch))
+ }
+ }
+
+ impl Rebuilder<'_> {
+ #[inline]
+ pub(super) fn for_each(&self, mut f: impl FnMut(&dispatcher::Dispatch)) {
+ if let Some(dispatch) = self.0 {
+ // we are rebuilding the interest cache because a new dispatcher
+ // is about to be set. on `no_std`, this should only happen
+ // once, because the new dispatcher will be the global default.
+ f(dispatch)
+ } else {
+ // otherwise, we are rebuilding the cache because the subscriber
+ // configuration changed, so use the global default.
+ // on no_std, there can only ever be one dispatcher
+ dispatcher::get_default(f)
+ }
+ }
+ }
+}
diff --git a/third_party/rust/tracing-core/src/dispatcher.rs b/third_party/rust/tracing-core/src/dispatcher.rs
new file mode 100644
index 0000000000..36b3cfd85f
--- /dev/null
+++ b/third_party/rust/tracing-core/src/dispatcher.rs
@@ -0,0 +1,1008 @@
+//! Dispatches trace events to [`Subscriber`]s.
+//!
+//! The _dispatcher_ is the component of the tracing system which is responsible
+//! for forwarding trace data from the instrumentation points that generate it
+//! to the subscriber that collects it.
+//!
+//! # Using the Trace Dispatcher
+//!
+//! Every thread in a program using `tracing` has a _default subscriber_. When
+//! events occur, or spans are created, they are dispatched to the thread's
+//! current subscriber.
+//!
+//! ## Setting the Default Subscriber
+//!
+//! By default, the current subscriber is an empty implementation that does
+//! nothing. To use a subscriber implementation, it must be set as the default.
+//! There are two methods for doing so: [`with_default`] and
+//! [`set_global_default`]. `with_default` sets the default subscriber for the
+//! duration of a scope, while `set_global_default` sets a default subscriber
+//! for the entire process.
+//!
+//! To use either of these functions, we must first wrap our subscriber in a
+//! [`Dispatch`], a cloneable, type-erased reference to a subscriber. For
+//! example:
+//! ```rust
+//! # pub struct FooSubscriber;
+//! # use tracing_core::{
+//! # dispatcher, Event, Metadata,
+//! # span::{Attributes, Id, Record}
+//! # };
+//! # impl tracing_core::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
+//! use dispatcher::Dispatch;
+//!
+//! let my_subscriber = FooSubscriber::new();
+//! let my_dispatch = Dispatch::new(my_subscriber);
+//! ```
+//! Then, we can use [`with_default`] to set our `Dispatch` as the default for
+//! the duration of a block:
+//! ```rust
+//! # pub struct FooSubscriber;
+//! # use tracing_core::{
+//! # dispatcher, Event, Metadata,
+//! # span::{Attributes, Id, Record}
+//! # };
+//! # impl tracing_core::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
+//! # let my_subscriber = FooSubscriber::new();
+//! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber);
+//! // no default subscriber
+//!
+//! # #[cfg(feature = "std")]
+//! dispatcher::with_default(&my_dispatch, || {
+//! // my_subscriber is the default
+//! });
+//!
+//! // no default subscriber again
+//! ```
+//! It's important to note that `with_default` will not propagate the current
+//! thread's default subscriber to any threads spawned within the `with_default`
+//! block. To propagate the default subscriber to new threads, either use
+//! `with_default` from the new thread, or use `set_global_default`.
+//!
+//! As an alternative to `with_default`, we can use [`set_global_default`] to
+//! set a `Dispatch` as the default for all threads, for the lifetime of the
+//! program. For example:
+//! ```rust
+//! # pub struct FooSubscriber;
+//! # use tracing_core::{
+//! # dispatcher, Event, Metadata,
+//! # span::{Attributes, Id, Record}
+//! # };
+//! # impl tracing_core::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
+//! # let my_subscriber = FooSubscriber::new();
+//! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber);
+//! // no default subscriber
+//!
+//! dispatcher::set_global_default(my_dispatch)
+//! // `set_global_default` will return an error if the global default
+//! // subscriber has already been set.
+//! .expect("global default was already set!");
+//!
+//! // `my_subscriber` is now the default
+//! ```
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>:the thread-local scoped dispatcher
+//! (<a href="#fn.with_default"><code>with_default</code></a>) requires the
+//! Rust standard library. <code>no_std</code> users should use
+//! <a href="#fn.set_global_default"><code>set_global_default</code></a>
+//! instead.
+//! </pre>
+//!
+//! ## Accessing the Default Subscriber
+//!
+//! A thread's current default subscriber can be accessed using the
+//! [`get_default`] function, which executes a closure with a reference to the
+//! currently default `Dispatch`. This is used primarily by `tracing`
+//! instrumentation.
+//!
+use crate::{
+ callsite, span,
+ subscriber::{self, NoSubscriber, Subscriber},
+ Event, LevelFilter, Metadata,
+};
+
+use crate::stdlib::{
+ any::Any,
+ fmt,
+ sync::{
+ atomic::{AtomicBool, AtomicUsize, Ordering},
+ Arc, Weak,
+ },
+};
+
+#[cfg(feature = "std")]
+use crate::stdlib::{
+ cell::{Cell, RefCell, RefMut},
+ error,
+};
+
+#[cfg(feature = "alloc")]
+use alloc::sync::{Arc, Weak};
+
+#[cfg(feature = "alloc")]
+use core::ops::Deref;
+
+/// `Dispatch` trace data to a [`Subscriber`].
+#[derive(Clone)]
+pub struct Dispatch {
+ subscriber: Arc<dyn Subscriber + Send + Sync>,
+}
+
+/// `WeakDispatch` is a version of [`Dispatch`] that holds a non-owning reference
+/// to a [`Subscriber`].
+///
+/// The Subscriber` may be accessed by calling [`WeakDispatch::upgrade`],
+/// which returns an `Option<Dispatch>`. If all [`Dispatch`] clones that point
+/// at the `Subscriber` have been dropped, [`WeakDispatch::upgrade`] will return
+/// `None`. Otherwise, it will return `Some(Dispatch)`.
+///
+/// A `WeakDispatch` may be created from a [`Dispatch`] by calling the
+/// [`Dispatch::downgrade`] method. The primary use for creating a
+/// [`WeakDispatch`] is to allow a Subscriber` to hold a cyclical reference to
+/// itself without creating a memory leak. See [here] for details.
+///
+/// This type is analogous to the [`std::sync::Weak`] type, but for a
+/// [`Dispatch`] rather than an [`Arc`].
+///
+/// [`Arc`]: std::sync::Arc
+/// [here]: Subscriber#avoiding-memory-leaks
+#[derive(Clone)]
+pub struct WeakDispatch {
+ subscriber: Weak<dyn Subscriber + Send + Sync>,
+}
+
+#[cfg(feature = "alloc")]
+#[derive(Clone)]
+enum Kind<T> {
+ Global(&'static (dyn Collect + Send + Sync)),
+ Scoped(T),
+}
+
+#[cfg(feature = "std")]
+thread_local! {
+ static CURRENT_STATE: State = State {
+ default: RefCell::new(None),
+ can_enter: Cell::new(true),
+ };
+}
+
+static EXISTS: AtomicBool = AtomicBool::new(false);
+static GLOBAL_INIT: AtomicUsize = AtomicUsize::new(UNINITIALIZED);
+
+const UNINITIALIZED: usize = 0;
+const INITIALIZING: usize = 1;
+const INITIALIZED: usize = 2;
+
+static mut GLOBAL_DISPATCH: Option<Dispatch> = None;
+
+/// The dispatch state of a thread.
+#[cfg(feature = "std")]
+struct State {
+ /// This thread's current default dispatcher.
+ default: RefCell<Option<Dispatch>>,
+ /// Whether or not we can currently begin dispatching a trace event.
+ ///
+ /// This is set to `false` when functions such as `enter`, `exit`, `event`,
+ /// and `new_span` are called on this thread's default dispatcher, to
+ /// prevent further trace events triggered inside those functions from
+ /// creating an infinite recursion. When we finish handling a dispatch, this
+ /// is set back to `true`.
+ can_enter: Cell<bool>,
+}
+
+/// While this guard is active, additional calls to subscriber functions on
+/// the default dispatcher will not be able to access the dispatch context.
+/// Dropping the guard will allow the dispatch context to be re-entered.
+#[cfg(feature = "std")]
+struct Entered<'a>(&'a State);
+
+/// A guard that resets the current default dispatcher to the prior
+/// default dispatcher when dropped.
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[derive(Debug)]
+pub struct DefaultGuard(Option<Dispatch>);
+
+/// Sets this dispatch as the default for the duration of a closure.
+///
+/// The default dispatcher is used when creating a new [span] or
+/// [`Event`].
+///
+/// <pre class="ignore" style="white-space:normal;font:inherit;">
+/// <strong>Note</strong>: This function required the Rust standard library.
+/// <code>no_std</code> users should use <a href="../fn.set_global_default.html">
+/// <code>set_global_default</code></a> instead.
+/// </pre>
+///
+/// [span]: super::span
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [`Event`]: super::event::Event
+/// [`set_global_default`]: super::set_global_default
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub fn with_default<T>(dispatcher: &Dispatch, f: impl FnOnce() -> T) -> T {
+ // When this guard is dropped, the default dispatcher will be reset to the
+ // prior default. Using this (rather than simply resetting after calling
+ // `f`) ensures that we always reset to the prior dispatcher even if `f`
+ // panics.
+ let _guard = set_default(dispatcher);
+ f()
+}
+
+/// Sets the dispatch as the default dispatch for the duration of the lifetime
+/// of the returned DefaultGuard
+///
+/// <pre class="ignore" style="white-space:normal;font:inherit;">
+/// <strong>Note</strong>: This function required the Rust standard library.
+/// <code>no_std</code> users should use <a href="../fn.set_global_default.html">
+/// <code>set_global_default</code></a> instead.
+/// </pre>
+///
+/// [`set_global_default`]: super::set_global_default
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[must_use = "Dropping the guard unregisters the dispatcher."]
+pub fn set_default(dispatcher: &Dispatch) -> DefaultGuard {
+ // When this guard is dropped, the default dispatcher will be reset to the
+ // prior default. Using this ensures that we always reset to the prior
+ // dispatcher even if the thread calling this function panics.
+ State::set_default(dispatcher.clone())
+}
+
+/// Sets this dispatch as the global default for the duration of the entire program.
+/// Will be used as a fallback if no thread-local dispatch has been set in a thread
+/// (using `with_default`.)
+///
+/// Can only be set once; subsequent attempts to set the global default will fail.
+/// Returns `Err` if the global default has already been set.
+///
+/// <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
+/// <strong>Warning</strong>: In general, libraries should <em>not</em> call
+/// <code>set_global_default()</code>! Doing so will cause conflicts when
+/// executables that depend on the library try to set the default later.
+/// </pre></div>
+///
+/// [span]: super::span
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [`Event`]: super::event::Event
+pub fn set_global_default(dispatcher: Dispatch) -> Result<(), SetGlobalDefaultError> {
+ // if `compare_exchange` returns Result::Ok(_), then `new` has been set and
+ // `current`—now the prior value—has been returned in the `Ok()` branch.
+ if GLOBAL_INIT
+ .compare_exchange(
+ UNINITIALIZED,
+ INITIALIZING,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ )
+ .is_ok()
+ {
+ unsafe {
+ GLOBAL_DISPATCH = Some(dispatcher);
+ }
+ GLOBAL_INIT.store(INITIALIZED, Ordering::SeqCst);
+ EXISTS.store(true, Ordering::Release);
+ Ok(())
+ } else {
+ Err(SetGlobalDefaultError { _no_construct: () })
+ }
+}
+
+/// Returns true if a `tracing` dispatcher has ever been set.
+///
+/// This may be used to completely elide trace points if tracing is not in use
+/// at all or has yet to be initialized.
+#[doc(hidden)]
+#[inline(always)]
+pub fn has_been_set() -> bool {
+ EXISTS.load(Ordering::Relaxed)
+}
+
+/// Returned if setting the global dispatcher fails.
+pub struct SetGlobalDefaultError {
+ _no_construct: (),
+}
+
+impl fmt::Debug for SetGlobalDefaultError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("SetGlobalDefaultError")
+ .field(&Self::MESSAGE)
+ .finish()
+ }
+}
+
+impl fmt::Display for SetGlobalDefaultError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad(Self::MESSAGE)
+ }
+}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl error::Error for SetGlobalDefaultError {}
+
+impl SetGlobalDefaultError {
+ const MESSAGE: &'static str = "a global default trace dispatcher has already been set";
+}
+
+/// Executes a closure with a reference to this thread's current [dispatcher].
+///
+/// Note that calls to `get_default` should not be nested; if this function is
+/// called while inside of another `get_default`, that closure will be provided
+/// with `Dispatch::none` rather than the previously set dispatcher.
+///
+/// [dispatcher]: super::dispatcher::Dispatch
+#[cfg(feature = "std")]
+pub fn get_default<T, F>(mut f: F) -> T
+where
+ F: FnMut(&Dispatch) -> T,
+{
+ CURRENT_STATE
+ .try_with(|state| {
+ if let Some(entered) = state.enter() {
+ return f(&*entered.current());
+ }
+
+ f(&Dispatch::none())
+ })
+ .unwrap_or_else(|_| f(&Dispatch::none()))
+}
+
+/// Executes a closure with a reference to this thread's current [dispatcher].
+///
+/// Note that calls to `get_default` should not be nested; if this function is
+/// called while inside of another `get_default`, that closure will be provided
+/// with `Dispatch::none` rather than the previously set dispatcher.
+///
+/// [dispatcher]: super::dispatcher::Dispatch
+#[cfg(feature = "std")]
+#[doc(hidden)]
+#[inline(never)]
+pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> {
+ CURRENT_STATE
+ .try_with(|state| {
+ let entered = state.enter()?;
+ Some(f(&*entered.current()))
+ })
+ .ok()?
+}
+
+/// Executes a closure with a reference to the current [dispatcher].
+///
+/// [dispatcher]: super::dispatcher::Dispatch
+#[cfg(not(feature = "std"))]
+#[doc(hidden)]
+pub fn get_current<T>(f: impl FnOnce(&Dispatch) -> T) -> Option<T> {
+ let dispatch = get_global()?;
+ Some(f(&dispatch))
+}
+
+/// Executes a closure with a reference to the current [dispatcher].
+///
+/// [dispatcher]: super::dispatcher::Dispatch
+#[cfg(not(feature = "std"))]
+pub fn get_default<T, F>(mut f: F) -> T
+where
+ F: FnMut(&Dispatch) -> T,
+{
+ if let Some(d) = get_global() {
+ f(d)
+ } else {
+ f(&Dispatch::none())
+ }
+}
+
+fn get_global() -> Option<&'static Dispatch> {
+ if GLOBAL_INIT.load(Ordering::SeqCst) != INITIALIZED {
+ return None;
+ }
+ unsafe {
+ // This is safe given the invariant that setting the global dispatcher
+ // also sets `GLOBAL_INIT` to `INITIALIZED`.
+ Some(GLOBAL_DISPATCH.as_ref().expect(
+ "invariant violated: GLOBAL_DISPATCH must be initialized before GLOBAL_INIT is set",
+ ))
+ }
+}
+
+#[cfg(feature = "std")]
+pub(crate) struct Registrar(Weak<dyn Subscriber + Send + Sync>);
+
+impl Dispatch {
+ /// Returns a new `Dispatch` that discards events and spans.
+ #[inline]
+ pub fn none() -> Self {
+ Dispatch {
+ subscriber: Arc::new(NoSubscriber::default()),
+ }
+ }
+
+ /// Returns a `Dispatch` that forwards to the given [`Subscriber`].
+ ///
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ pub fn new<S>(subscriber: S) -> Self
+ where
+ S: Subscriber + Send + Sync + 'static,
+ {
+ let me = Dispatch {
+ subscriber: Arc::new(subscriber),
+ };
+ callsite::register_dispatch(&me);
+ me
+ }
+
+ #[cfg(feature = "std")]
+ pub(crate) fn registrar(&self) -> Registrar {
+ Registrar(Arc::downgrade(&self.subscriber))
+ }
+
+ /// Creates a [`WeakDispatch`] from this `Dispatch`.
+ ///
+ /// A [`WeakDispatch`] is similar to a [`Dispatch`], but it does not prevent
+ /// the underlying [`Subscriber`] from being dropped. Instead, it only permits
+ /// access while other references to the `Subscriber` exist. This is equivalent
+ /// to the standard library's [`Arc::downgrade`] method, but for `Dispatch`
+ /// rather than `Arc`.
+ ///
+ /// The primary use for creating a [`WeakDispatch`] is to allow a `Subscriber`
+ /// to hold a cyclical reference to itself without creating a memory leak.
+ /// See [here] for details.
+ ///
+ /// [`Arc::downgrade`]: std::sync::Arc::downgrade
+ /// [here]: Subscriber#avoiding-memory-leaks
+ pub fn downgrade(&self) -> WeakDispatch {
+ WeakDispatch {
+ subscriber: Arc::downgrade(&self.subscriber),
+ }
+ }
+
+ #[inline(always)]
+ #[cfg(not(feature = "alloc"))]
+ pub(crate) fn subscriber(&self) -> &(dyn Subscriber + Send + Sync) {
+ &self.subscriber
+ }
+
+ /// Registers a new callsite with this collector, returning whether or not
+ /// the collector is interested in being notified about the callsite.
+ ///
+ /// This calls the [`register_callsite`] function on the [`Subscriber`]
+ /// that this `Dispatch` forwards to.
+ ///
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`register_callsite`]: super::subscriber::Subscriber::register_callsite
+ #[inline]
+ pub fn register_callsite(&self, metadata: &'static Metadata<'static>) -> subscriber::Interest {
+ self.subscriber.register_callsite(metadata)
+ }
+
+ /// Returns the highest [verbosity level][level] that this [`Subscriber`] will
+ /// enable, or `None`, if the subscriber does not implement level-based
+ /// filtering or chooses not to implement this method.
+ ///
+ /// This calls the [`max_level_hint`] function on the [`Subscriber`]
+ /// that this `Dispatch` forwards to.
+ ///
+ /// [level]: super::Level
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`register_callsite`]: super::subscriber::Subscriber::max_level_hint
+ // TODO(eliza): consider making this a public API?
+ #[inline]
+ pub(crate) fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.subscriber.max_level_hint()
+ }
+
+ /// Record the construction of a new span, returning a new [ID] for the
+ /// span being constructed.
+ ///
+ /// This calls the [`new_span`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [ID]: super::span::Id
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`new_span`]: super::subscriber::Subscriber::new_span
+ #[inline]
+ pub fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
+ self.subscriber.new_span(span)
+ }
+
+ /// Record a set of values on a span.
+ ///
+ /// This calls the [`record`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`record`]: super::subscriber::Subscriber::record
+ #[inline]
+ pub fn record(&self, span: &span::Id, values: &span::Record<'_>) {
+ self.subscriber.record(span, values)
+ }
+
+ /// Adds an indication that `span` follows from the span with the id
+ /// `follows`.
+ ///
+ /// This calls the [`record_follows_from`] function on the [`Subscriber`]
+ /// that this `Dispatch` forwards to.
+ ///
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`record_follows_from`]: super::subscriber::Subscriber::record_follows_from
+ #[inline]
+ pub fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
+ self.subscriber.record_follows_from(span, follows)
+ }
+
+ /// Returns true if a span with the specified [metadata] would be
+ /// recorded.
+ ///
+ /// This calls the [`enabled`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [metadata]: super::metadata::Metadata
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`enabled`]: super::subscriber::Subscriber::enabled
+ #[inline]
+ pub fn enabled(&self, metadata: &Metadata<'_>) -> bool {
+ self.subscriber.enabled(metadata)
+ }
+
+ /// Records that an [`Event`] has occurred.
+ ///
+ /// This calls the [`event`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [`Event`]: super::event::Event
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`event`]: super::subscriber::Subscriber::event
+ #[inline]
+ pub fn event(&self, event: &Event<'_>) {
+ if self.subscriber.event_enabled(event) {
+ self.subscriber.event(event);
+ }
+ }
+
+ /// Records that a span has been can_enter.
+ ///
+ /// This calls the [`enter`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`enter`]: super::subscriber::Subscriber::enter
+ pub fn enter(&self, span: &span::Id) {
+ self.subscriber.enter(span);
+ }
+
+ /// Records that a span has been exited.
+ ///
+ /// This calls the [`exit`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`exit`]: super::subscriber::Subscriber::exit
+ pub fn exit(&self, span: &span::Id) {
+ self.subscriber.exit(span);
+ }
+
+ /// Notifies the subscriber that a [span ID] has been cloned.
+ ///
+ /// This function must only be called with span IDs that were returned by
+ /// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds
+ /// this guarantee and any other libraries implementing instrumentation APIs
+ /// must as well.
+ ///
+ /// This calls the [`clone_span`] function on the `Subscriber` that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [span ID]: super::span::Id
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`clone_span`]: super::subscriber::Subscriber::clone_span
+ /// [`new_span`]: super::subscriber::Subscriber::new_span
+ #[inline]
+ pub fn clone_span(&self, id: &span::Id) -> span::Id {
+ self.subscriber.clone_span(id)
+ }
+
+ /// Notifies the subscriber that a [span ID] has been dropped.
+ ///
+ /// This function must only be called with span IDs that were returned by
+ /// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds
+ /// this guarantee and any other libraries implementing instrumentation APIs
+ /// must as well.
+ ///
+ /// This calls the [`drop_span`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// <pre class="compile_fail" style="white-space:normal;font:inherit;">
+ /// <strong>Deprecated</strong>: The <a href="#method.try_close"><code>
+ /// try_close</code></a> method is functionally identical, but returns
+ /// <code>true</code> if the span is now closed. It should be used
+ /// instead of this method.
+ /// </pre>
+ ///
+ /// [span ID]: super::span::Id
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`drop_span`]: super::subscriber::Subscriber::drop_span
+ /// [`new_span`]: super::subscriber::Subscriber::new_span
+ /// [`try_close`]: Entered::try_close()
+ #[inline]
+ #[deprecated(since = "0.1.2", note = "use `Dispatch::try_close` instead")]
+ pub fn drop_span(&self, id: span::Id) {
+ #[allow(deprecated)]
+ self.subscriber.drop_span(id);
+ }
+
+ /// Notifies the subscriber that a [span ID] has been dropped, and returns
+ /// `true` if there are now 0 IDs referring to that span.
+ ///
+ /// This function must only be called with span IDs that were returned by
+ /// this `Dispatch`'s [`new_span`] function. The `tracing` crate upholds
+ /// this guarantee and any other libraries implementing instrumentation APIs
+ /// must as well.
+ ///
+ /// This calls the [`try_close`] function on the [`Subscriber`] that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [span ID]: super::span::Id
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [`try_close`]: super::subscriber::Subscriber::try_close
+ /// [`new_span`]: super::subscriber::Subscriber::new_span
+ pub fn try_close(&self, id: span::Id) -> bool {
+ self.subscriber.try_close(id)
+ }
+
+ /// Returns a type representing this subscriber's view of the current span.
+ ///
+ /// This calls the [`current`] function on the `Subscriber` that this
+ /// `Dispatch` forwards to.
+ ///
+ /// [`current`]: super::subscriber::Subscriber::current_span
+ #[inline]
+ pub fn current_span(&self) -> span::Current {
+ self.subscriber.current_span()
+ }
+
+ /// Returns `true` if this `Dispatch` forwards to a `Subscriber` of type
+ /// `T`.
+ #[inline]
+ pub fn is<T: Any>(&self) -> bool {
+ <dyn Subscriber>::is::<T>(&self.subscriber)
+ }
+
+ /// Returns some reference to the `Subscriber` this `Dispatch` forwards to
+ /// if it is of type `T`, or `None` if it isn't.
+ #[inline]
+ pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+ <dyn Subscriber>::downcast_ref(&self.subscriber)
+ }
+}
+
+impl Default for Dispatch {
+ /// Returns the current default dispatcher
+ fn default() -> Self {
+ get_default(|default| default.clone())
+ }
+}
+
+impl fmt::Debug for Dispatch {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_tuple("Dispatch")
+ .field(&format_args!("{:p}", self.subscriber))
+ .finish()
+ }
+}
+
+impl<S> From<S> for Dispatch
+where
+ S: Subscriber + Send + Sync + 'static,
+{
+ #[inline]
+ fn from(subscriber: S) -> Self {
+ Dispatch::new(subscriber)
+ }
+}
+
+// === impl WeakDispatch ===
+
+impl WeakDispatch {
+ /// Attempts to upgrade this `WeakDispatch` to a [`Dispatch`].
+ ///
+ /// Returns `None` if the referenced `Dispatch` has already been dropped.
+ ///
+ /// ## Examples
+ ///
+ /// ```
+ /// # use tracing_core::subscriber::NoSubscriber;
+ /// # use tracing_core::dispatcher::Dispatch;
+ /// let strong = Dispatch::new(NoSubscriber::default());
+ /// let weak = strong.downgrade();
+ ///
+ /// // The strong here keeps it alive, so we can still access the object.
+ /// assert!(weak.upgrade().is_some());
+ ///
+ /// drop(strong); // But not any more.
+ /// assert!(weak.upgrade().is_none());
+ /// ```
+ pub fn upgrade(&self) -> Option<Dispatch> {
+ self.subscriber
+ .upgrade()
+ .map(|subscriber| Dispatch { subscriber })
+ }
+}
+
+impl fmt::Debug for WeakDispatch {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut tuple = f.debug_tuple("WeakDispatch");
+ match self.subscriber.upgrade() {
+ Some(subscriber) => tuple.field(&format_args!("Some({:p})", subscriber)),
+ None => tuple.field(&format_args!("None")),
+ };
+ tuple.finish()
+ }
+}
+
+#[cfg(feature = "std")]
+impl Registrar {
+ pub(crate) fn upgrade(&self) -> Option<Dispatch> {
+ self.0.upgrade().map(|subscriber| Dispatch { subscriber })
+ }
+}
+
+// ===== impl State =====
+
+#[cfg(feature = "std")]
+impl State {
+ /// Replaces the current default dispatcher on this thread with the provided
+ /// dispatcher.Any
+ ///
+ /// Dropping the returned `ResetGuard` will reset the default dispatcher to
+ /// the previous value.
+ #[inline]
+ fn set_default(new_dispatch: Dispatch) -> DefaultGuard {
+ let prior = CURRENT_STATE
+ .try_with(|state| {
+ state.can_enter.set(true);
+ state.default.replace(Some(new_dispatch))
+ })
+ .ok()
+ .flatten();
+ EXISTS.store(true, Ordering::Release);
+ DefaultGuard(prior)
+ }
+
+ #[inline]
+ fn enter(&self) -> Option<Entered<'_>> {
+ if self.can_enter.replace(false) {
+ Some(Entered(self))
+ } else {
+ None
+ }
+ }
+}
+
+// ===== impl Entered =====
+
+#[cfg(feature = "std")]
+impl<'a> Entered<'a> {
+ #[inline]
+ fn current(&self) -> RefMut<'a, Dispatch> {
+ let default = self.0.default.borrow_mut();
+ RefMut::map(default, |default| {
+ default.get_or_insert_with(|| get_global().cloned().unwrap_or_else(Dispatch::none))
+ })
+ }
+}
+
+#[cfg(feature = "std")]
+impl<'a> Drop for Entered<'a> {
+ #[inline]
+ fn drop(&mut self) {
+ self.0.can_enter.set(true);
+ }
+}
+
+// ===== impl DefaultGuard =====
+
+#[cfg(feature = "std")]
+impl Drop for DefaultGuard {
+ #[inline]
+ fn drop(&mut self) {
+ // Replace the dispatcher and then drop the old one outside
+ // of the thread-local context. Dropping the dispatch may
+ // lead to the drop of a subscriber which, in the process,
+ // could then also attempt to access the same thread local
+ // state -- causing a clash.
+ let prev = CURRENT_STATE.try_with(|state| state.default.replace(self.0.take()));
+ drop(prev)
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ #[cfg(feature = "std")]
+ use crate::stdlib::sync::atomic::{AtomicUsize, Ordering};
+ use crate::{
+ callsite::Callsite,
+ metadata::{Kind, Level, Metadata},
+ subscriber::Interest,
+ };
+
+ #[test]
+ fn dispatch_is() {
+ let dispatcher = Dispatch::new(NoSubscriber::default());
+ assert!(dispatcher.is::<NoSubscriber>());
+ }
+
+ #[test]
+ fn dispatch_downcasts() {
+ let dispatcher = Dispatch::new(NoSubscriber::default());
+ assert!(dispatcher.downcast_ref::<NoSubscriber>().is_some());
+ }
+
+ struct TestCallsite;
+ static TEST_CALLSITE: TestCallsite = TestCallsite;
+ static TEST_META: Metadata<'static> = metadata! {
+ name: "test",
+ target: module_path!(),
+ level: Level::DEBUG,
+ fields: &[],
+ callsite: &TEST_CALLSITE,
+ kind: Kind::EVENT
+ };
+
+ impl Callsite for TestCallsite {
+ fn set_interest(&self, _: Interest) {}
+ fn metadata(&self) -> &Metadata<'_> {
+ &TEST_META
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn events_dont_infinite_loop() {
+ // This test ensures that an event triggered within a subscriber
+ // won't cause an infinite loop of events.
+ struct TestSubscriber;
+ impl Subscriber for TestSubscriber {
+ fn enabled(&self, _: &Metadata<'_>) -> bool {
+ true
+ }
+
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ span::Id::from_u64(0xAAAA)
+ }
+
+ fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
+
+ fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
+
+ fn event(&self, _: &Event<'_>) {
+ static EVENTS: AtomicUsize = AtomicUsize::new(0);
+ assert_eq!(
+ EVENTS.fetch_add(1, Ordering::Relaxed),
+ 0,
+ "event method called twice!"
+ );
+ Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[]))
+ }
+
+ fn enter(&self, _: &span::Id) {}
+
+ fn exit(&self, _: &span::Id) {}
+ }
+
+ with_default(&Dispatch::new(TestSubscriber), || {
+ Event::dispatch(&TEST_META, &TEST_META.fields().value_set(&[]))
+ })
+ }
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn spans_dont_infinite_loop() {
+ // This test ensures that a span created within a subscriber
+ // won't cause an infinite loop of new spans.
+
+ fn mk_span() {
+ get_default(|current| {
+ current.new_span(&span::Attributes::new(
+ &TEST_META,
+ &TEST_META.fields().value_set(&[]),
+ ))
+ });
+ }
+
+ struct TestSubscriber;
+ impl Subscriber for TestSubscriber {
+ fn enabled(&self, _: &Metadata<'_>) -> bool {
+ true
+ }
+
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ static NEW_SPANS: AtomicUsize = AtomicUsize::new(0);
+ assert_eq!(
+ NEW_SPANS.fetch_add(1, Ordering::Relaxed),
+ 0,
+ "new_span method called twice!"
+ );
+ mk_span();
+ span::Id::from_u64(0xAAAA)
+ }
+
+ fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
+
+ fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
+
+ fn event(&self, _: &Event<'_>) {}
+
+ fn enter(&self, _: &span::Id) {}
+
+ fn exit(&self, _: &span::Id) {}
+ }
+
+ with_default(&Dispatch::new(TestSubscriber), mk_span)
+ }
+
+ #[test]
+ fn default_no_subscriber() {
+ let default_dispatcher = Dispatch::default();
+ assert!(default_dispatcher.is::<NoSubscriber>());
+ }
+
+ #[cfg(feature = "std")]
+ #[test]
+ fn default_dispatch() {
+ struct TestSubscriber;
+ impl Subscriber for TestSubscriber {
+ fn enabled(&self, _: &Metadata<'_>) -> bool {
+ true
+ }
+
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ span::Id::from_u64(0xAAAA)
+ }
+
+ fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
+
+ fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
+
+ fn event(&self, _: &Event<'_>) {}
+
+ fn enter(&self, _: &span::Id) {}
+
+ fn exit(&self, _: &span::Id) {}
+ }
+ let guard = set_default(&Dispatch::new(TestSubscriber));
+ let default_dispatcher = Dispatch::default();
+ assert!(default_dispatcher.is::<TestSubscriber>());
+
+ drop(guard);
+ let default_dispatcher = Dispatch::default();
+ assert!(default_dispatcher.is::<NoSubscriber>());
+ }
+}
diff --git a/third_party/rust/tracing-core/src/event.rs b/third_party/rust/tracing-core/src/event.rs
new file mode 100644
index 0000000000..6e25437629
--- /dev/null
+++ b/third_party/rust/tracing-core/src/event.rs
@@ -0,0 +1,128 @@
+//! Events represent single points in time during the execution of a program.
+use crate::parent::Parent;
+use crate::span::Id;
+use crate::{field, Metadata};
+
+/// `Event`s represent single points in time where something occurred during the
+/// execution of a program.
+///
+/// An `Event` can be compared to a log record in unstructured logging, but with
+/// two key differences:
+/// - `Event`s exist _within the context of a [span]_. Unlike log lines, they
+/// may be located within the trace tree, allowing visibility into the
+/// _temporal_ context in which the event occurred, as well as the source
+/// code location.
+/// - Like spans, `Event`s have structured key-value data known as _[fields]_,
+/// which may include textual message. In general, a majority of the data
+/// associated with an event should be in the event's fields rather than in
+/// the textual message, as the fields are more structured.
+///
+/// [span]: super::span
+/// [fields]: super::field
+#[derive(Debug)]
+pub struct Event<'a> {
+ fields: &'a field::ValueSet<'a>,
+ metadata: &'static Metadata<'static>,
+ parent: Parent,
+}
+
+impl<'a> Event<'a> {
+ /// Constructs a new `Event` with the specified metadata and set of values,
+ /// and observes it with the current subscriber.
+ pub fn dispatch(metadata: &'static Metadata<'static>, fields: &'a field::ValueSet<'_>) {
+ let event = Event::new(metadata, fields);
+ crate::dispatcher::get_default(|current| {
+ current.event(&event);
+ });
+ }
+
+ /// Returns a new `Event` in the current span, with the specified metadata
+ /// and set of values.
+ #[inline]
+ pub fn new(metadata: &'static Metadata<'static>, fields: &'a field::ValueSet<'a>) -> Self {
+ Event {
+ fields,
+ metadata,
+ parent: Parent::Current,
+ }
+ }
+
+ /// Returns a new `Event` as a child of the specified span, with the
+ /// provided metadata and set of values.
+ #[inline]
+ pub fn new_child_of(
+ parent: impl Into<Option<Id>>,
+ metadata: &'static Metadata<'static>,
+ fields: &'a field::ValueSet<'a>,
+ ) -> Self {
+ let parent = match parent.into() {
+ Some(p) => Parent::Explicit(p),
+ None => Parent::Root,
+ };
+ Event {
+ fields,
+ metadata,
+ parent,
+ }
+ }
+
+ /// Constructs a new `Event` with the specified metadata and set of values,
+ /// and observes it with the current subscriber and an explicit parent.
+ pub fn child_of(
+ parent: impl Into<Option<Id>>,
+ metadata: &'static Metadata<'static>,
+ fields: &'a field::ValueSet<'_>,
+ ) {
+ let event = Self::new_child_of(parent, metadata, fields);
+ crate::dispatcher::get_default(|current| {
+ current.event(&event);
+ });
+ }
+
+ /// Visits all the fields on this `Event` with the specified [visitor].
+ ///
+ /// [visitor]: super::field::Visit
+ #[inline]
+ pub fn record(&self, visitor: &mut dyn field::Visit) {
+ self.fields.record(visitor);
+ }
+
+ /// Returns an iterator over the set of values on this `Event`.
+ pub fn fields(&self) -> field::Iter {
+ self.fields.field_set().iter()
+ }
+
+ /// Returns [metadata] describing this `Event`.
+ ///
+ /// [metadata]: super::Metadata
+ pub fn metadata(&self) -> &'static Metadata<'static> {
+ self.metadata
+ }
+
+ /// Returns true if the new event should be a root.
+ pub fn is_root(&self) -> bool {
+ matches!(self.parent, Parent::Root)
+ }
+
+ /// Returns true if the new event's parent should be determined based on the
+ /// current context.
+ ///
+ /// If this is true and the current thread is currently inside a span, then
+ /// that span should be the new event's parent. Otherwise, if the current
+ /// thread is _not_ inside a span, then the new event will be the root of its
+ /// own trace tree.
+ pub fn is_contextual(&self) -> bool {
+ matches!(self.parent, Parent::Current)
+ }
+
+ /// Returns the new event's explicitly-specified parent, if there is one.
+ ///
+ /// Otherwise (if the new event is a root or is a child of the current span),
+ /// returns `None`.
+ pub fn parent(&self) -> Option<&Id> {
+ match self.parent {
+ Parent::Explicit(ref p) => Some(p),
+ _ => None,
+ }
+ }
+}
diff --git a/third_party/rust/tracing-core/src/field.rs b/third_party/rust/tracing-core/src/field.rs
new file mode 100644
index 0000000000..e103c75a9d
--- /dev/null
+++ b/third_party/rust/tracing-core/src/field.rs
@@ -0,0 +1,1263 @@
+//! `Span` and `Event` key-value data.
+//!
+//! Spans and events may be annotated with key-value data, referred to as known
+//! as _fields_. These fields consist of a mapping from a key (corresponding to
+//! a `&str` but represented internally as an array index) to a [`Value`].
+//!
+//! # `Value`s and `Subscriber`s
+//!
+//! `Subscriber`s consume `Value`s as fields attached to [span]s or [`Event`]s.
+//! The set of field keys on a given span or is defined on its [`Metadata`].
+//! When a span is created, it provides [`Attributes`] to the `Subscriber`'s
+//! [`new_span`] method, containing any fields whose values were provided when
+//! the span was created; and may call the `Subscriber`'s [`record`] method
+//! with additional [`Record`]s if values are added for more of its fields.
+//! Similarly, the [`Event`] type passed to the subscriber's [`event`] method
+//! will contain any fields attached to each event.
+//!
+//! `tracing` represents values as either one of a set of Rust primitives
+//! (`i64`, `u64`, `f64`, `i128`, `u128`, `bool`, and `&str`) or using a
+//! `fmt::Display` or `fmt::Debug` implementation. `Subscriber`s are provided
+//! these primitive value types as `dyn Value` trait objects.
+//!
+//! These trait objects can be formatted using `fmt::Debug`, but may also be
+//! recorded as typed data by calling the [`Value::record`] method on these
+//! trait objects with a _visitor_ implementing the [`Visit`] trait. This trait
+//! represents the behavior used to record values of various types. For example,
+//! an implementation of `Visit` might record integers by incrementing counters
+//! for their field names rather than printing them.
+//!
+//!
+//! # Using `valuable`
+//!
+//! `tracing`'s [`Value`] trait is intentionally minimalist: it supports only a small
+//! number of Rust primitives as typed values, and only permits recording
+//! user-defined types with their [`fmt::Debug`] or [`fmt::Display`]
+//! implementations. However, there are some cases where it may be useful to record
+//! nested values (such as arrays, `Vec`s, or `HashMap`s containing values), or
+//! user-defined `struct` and `enum` types without having to format them as
+//! unstructured text.
+//!
+//! To address `Value`'s limitations, `tracing` offers experimental support for
+//! the [`valuable`] crate, which provides object-safe inspection of structured
+//! values. User-defined types can implement the [`valuable::Valuable`] trait,
+//! and be recorded as a `tracing` field by calling their [`as_value`] method.
+//! If the [`Subscriber`] also supports the `valuable` crate, it can
+//! then visit those types fields as structured values using `valuable`.
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>: <code>valuable</code> support is an
+//! <a href = "../index.html#unstable-features">unstable feature</a>. See
+//! the documentation on unstable features for details on how to enable it.
+//! </pre>
+//!
+//! For example:
+//! ```ignore
+//! // Derive `Valuable` for our types:
+//! use valuable::Valuable;
+//!
+//! #[derive(Clone, Debug, Valuable)]
+//! struct User {
+//! name: String,
+//! age: u32,
+//! address: Address,
+//! }
+//!
+//! #[derive(Clone, Debug, Valuable)]
+//! struct Address {
+//! country: String,
+//! city: String,
+//! street: String,
+//! }
+//!
+//! let user = User {
+//! name: "Arwen Undomiel".to_string(),
+//! age: 3000,
+//! address: Address {
+//! country: "Middle Earth".to_string(),
+//! city: "Rivendell".to_string(),
+//! street: "leafy lane".to_string(),
+//! },
+//! };
+//!
+//! // Recording `user` as a `valuable::Value` will allow the `tracing` subscriber
+//! // to traverse its fields as a nested, typed structure:
+//! tracing::info!(current_user = user.as_value());
+//! ```
+//!
+//! Alternatively, the [`valuable()`] function may be used to convert a type
+//! implementing [`Valuable`] into a `tracing` field value.
+//!
+//! When the `valuable` feature is enabled, the [`Visit`] trait will include an
+//! optional [`record_value`] method. `Visit` implementations that wish to
+//! record `valuable` values can implement this method with custom behavior.
+//! If a visitor does not implement `record_value`, the [`valuable::Value`] will
+//! be forwarded to the visitor's [`record_debug`] method.
+//!
+//! [`valuable`]: https://crates.io/crates/valuable
+//! [`as_value`]: valuable::Valuable::as_value
+//! [`Subscriber`]: crate::Subscriber
+//! [`record_value`]: Visit::record_value
+//! [`record_debug`]: Visit::record_debug
+//!
+//! [span]: super::span
+//! [`Event`]: super::event::Event
+//! [`Metadata`]: super::metadata::Metadata
+//! [`Attributes`]: super::span::Attributes
+//! [`Record`]: super::span::Record
+//! [`new_span`]: super::subscriber::Subscriber::new_span
+//! [`record`]: super::subscriber::Subscriber::record
+//! [`event`]: super::subscriber::Subscriber::event
+//! [`Value::record`]: Value::record
+use crate::callsite;
+use crate::stdlib::{
+ borrow::Borrow,
+ fmt,
+ hash::{Hash, Hasher},
+ num,
+ ops::Range,
+ string::String,
+};
+
+use self::private::ValidLen;
+
+/// An opaque key allowing _O_(1) access to a field in a `Span`'s key-value
+/// data.
+///
+/// As keys are defined by the _metadata_ of a span, rather than by an
+/// individual instance of a span, a key may be used to access the same field
+/// across all instances of a given span with the same metadata. Thus, when a
+/// subscriber observes a new span, it need only access a field by name _once_,
+/// and use the key for that name for all other accesses.
+#[derive(Debug)]
+pub struct Field {
+ i: usize,
+ fields: FieldSet,
+}
+
+/// An empty field.
+///
+/// This can be used to indicate that the value of a field is not currently
+/// present but will be recorded later.
+///
+/// When a field's value is `Empty`. it will not be recorded.
+#[derive(Debug, Eq, PartialEq)]
+pub struct Empty;
+
+/// Describes the fields present on a span.
+///
+/// ## Equality
+///
+/// In well-behaved applications, two `FieldSet`s [initialized] with equal
+/// [callsite identifiers] will have identical fields. Consequently, in release
+/// builds, [`FieldSet::eq`] *only* checks that its arguments have equal
+/// callsites. However, the equality of field names is checked in debug builds.
+///
+/// [initialized]: Self::new
+/// [callsite identifiers]: callsite::Identifier
+pub struct FieldSet {
+ /// The names of each field on the described span.
+ names: &'static [&'static str],
+ /// The callsite where the described span originates.
+ callsite: callsite::Identifier,
+}
+
+/// A set of fields and values for a span.
+pub struct ValueSet<'a> {
+ values: &'a [(&'a Field, Option<&'a (dyn Value + 'a)>)],
+ fields: &'a FieldSet,
+}
+
+/// An iterator over a set of fields.
+#[derive(Debug)]
+pub struct Iter {
+ idxs: Range<usize>,
+ fields: FieldSet,
+}
+
+/// Visits typed values.
+///
+/// An instance of `Visit` ("a visitor") represents the logic necessary to
+/// record field values of various types. When an implementor of [`Value`] is
+/// [recorded], it calls the appropriate method on the provided visitor to
+/// indicate the type that value should be recorded as.
+///
+/// When a [`Subscriber`] implementation [records an `Event`] or a
+/// [set of `Value`s added to a `Span`], it can pass an `&mut Visit` to the
+/// `record` method on the provided [`ValueSet`] or [`Event`]. This visitor
+/// will then be used to record all the field-value pairs present on that
+/// `Event` or `ValueSet`.
+///
+/// # Examples
+///
+/// A simple visitor that writes to a string might be implemented like so:
+/// ```
+/// # extern crate tracing_core as tracing;
+/// use std::fmt::{self, Write};
+/// use tracing::field::{Value, Visit, Field};
+/// pub struct StringVisitor<'a> {
+/// string: &'a mut String,
+/// }
+///
+/// impl<'a> Visit for StringVisitor<'a> {
+/// fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+/// write!(self.string, "{} = {:?}; ", field.name(), value).unwrap();
+/// }
+/// }
+/// ```
+/// This visitor will format each recorded value using `fmt::Debug`, and
+/// append the field name and formatted value to the provided string,
+/// regardless of the type of the recorded value. When all the values have
+/// been recorded, the `StringVisitor` may be dropped, allowing the string
+/// to be printed or stored in some other data structure.
+///
+/// The `Visit` trait provides default implementations for `record_i64`,
+/// `record_u64`, `record_bool`, `record_str`, and `record_error`, which simply
+/// forward the recorded value to `record_debug`. Thus, `record_debug` is the
+/// only method which a `Visit` implementation *must* implement. However,
+/// visitors may override the default implementations of these functions in
+/// order to implement type-specific behavior.
+///
+/// Additionally, when a visitor receives a value of a type it does not care
+/// about, it is free to ignore those values completely. For example, a
+/// visitor which only records numeric data might look like this:
+///
+/// ```
+/// # extern crate tracing_core as tracing;
+/// # use std::fmt::{self, Write};
+/// # use tracing::field::{Value, Visit, Field};
+/// pub struct SumVisitor {
+/// sum: i64,
+/// }
+///
+/// impl Visit for SumVisitor {
+/// fn record_i64(&mut self, _field: &Field, value: i64) {
+/// self.sum += value;
+/// }
+///
+/// fn record_u64(&mut self, _field: &Field, value: u64) {
+/// self.sum += value as i64;
+/// }
+///
+/// fn record_debug(&mut self, _field: &Field, _value: &fmt::Debug) {
+/// // Do nothing
+/// }
+/// }
+/// ```
+///
+/// This visitor (which is probably not particularly useful) keeps a running
+/// sum of all the numeric values it records, and ignores all other values. A
+/// more practical example of recording typed values is presented in
+/// `examples/counters.rs`, which demonstrates a very simple metrics system
+/// implemented using `tracing`.
+///
+/// <div class="example-wrap" style="display:inline-block">
+/// <pre class="ignore" style="white-space:normal;font:inherit;">
+/// <strong>Note</strong>: The <code>record_error</code> trait method is only
+/// available when the Rust standard library is present, as it requires the
+/// <code>std::error::Error</code> trait.
+/// </pre></div>
+///
+/// [recorded]: Value::record
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [records an `Event`]: super::subscriber::Subscriber::event
+/// [set of `Value`s added to a `Span`]: super::subscriber::Subscriber::record
+/// [`Event`]: super::event::Event
+pub trait Visit {
+ /// Visits an arbitrary type implementing the [`valuable`] crate's `Valuable` trait.
+ ///
+ /// [`valuable`]: https://docs.rs/valuable
+ #[cfg(all(tracing_unstable, feature = "valuable"))]
+ #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+ fn record_value(&mut self, field: &Field, value: valuable::Value<'_>) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a double-precision floating point value.
+ fn record_f64(&mut self, field: &Field, value: f64) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a signed 64-bit integer value.
+ fn record_i64(&mut self, field: &Field, value: i64) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit an unsigned 64-bit integer value.
+ fn record_u64(&mut self, field: &Field, value: u64) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a signed 128-bit integer value.
+ fn record_i128(&mut self, field: &Field, value: i128) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit an unsigned 128-bit integer value.
+ fn record_u128(&mut self, field: &Field, value: u128) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a boolean value.
+ fn record_bool(&mut self, field: &Field, value: bool) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a string value.
+ fn record_str(&mut self, field: &Field, value: &str) {
+ self.record_debug(field, &value)
+ }
+
+ /// Records a type implementing `Error`.
+ ///
+ /// <div class="example-wrap" style="display:inline-block">
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ /// <strong>Note</strong>: This is only enabled when the Rust standard library is
+ /// present.
+ /// </pre>
+ #[cfg(feature = "std")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+ fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
+ self.record_debug(field, &DisplayValue(value))
+ }
+
+ /// Visit a value implementing `fmt::Debug`.
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug);
+}
+
+/// A field value of an erased type.
+///
+/// Implementors of `Value` may call the appropriate typed recording methods on
+/// the [visitor] passed to their `record` method in order to indicate how
+/// their data should be recorded.
+///
+/// [visitor]: Visit
+pub trait Value: crate::sealed::Sealed {
+ /// Visits this value with the given `Visitor`.
+ fn record(&self, key: &Field, visitor: &mut dyn Visit);
+}
+
+/// A `Value` which serializes using `fmt::Display`.
+///
+/// Uses `record_debug` in the `Value` implementation to
+/// avoid an unnecessary evaluation.
+#[derive(Clone)]
+pub struct DisplayValue<T: fmt::Display>(T);
+
+/// A `Value` which serializes as a string using `fmt::Debug`.
+#[derive(Clone)]
+pub struct DebugValue<T: fmt::Debug>(T);
+
+/// Wraps a type implementing `fmt::Display` as a `Value` that can be
+/// recorded using its `Display` implementation.
+pub fn display<T>(t: T) -> DisplayValue<T>
+where
+ T: fmt::Display,
+{
+ DisplayValue(t)
+}
+
+/// Wraps a type implementing `fmt::Debug` as a `Value` that can be
+/// recorded using its `Debug` implementation.
+pub fn debug<T>(t: T) -> DebugValue<T>
+where
+ T: fmt::Debug,
+{
+ DebugValue(t)
+}
+
+/// Wraps a type implementing [`Valuable`] as a `Value` that
+/// can be recorded using its `Valuable` implementation.
+///
+/// [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+pub fn valuable<T>(t: &T) -> valuable::Value<'_>
+where
+ T: valuable::Valuable,
+{
+ t.as_value()
+}
+
+// ===== impl Visit =====
+
+impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ self.field(field.name(), value);
+ }
+}
+
+impl<'a, 'b> Visit for fmt::DebugMap<'a, 'b> {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ self.entry(&format_args!("{}", field), value);
+ }
+}
+
+impl<F> Visit for F
+where
+ F: FnMut(&Field, &dyn fmt::Debug),
+{
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ (self)(field, value)
+ }
+}
+
+// ===== impl Value =====
+
+macro_rules! impl_values {
+ ( $( $record:ident( $( $whatever:tt)+ ) ),+ ) => {
+ $(
+ impl_value!{ $record( $( $whatever )+ ) }
+ )+
+ }
+}
+
+macro_rules! ty_to_nonzero {
+ (u8) => {
+ NonZeroU8
+ };
+ (u16) => {
+ NonZeroU16
+ };
+ (u32) => {
+ NonZeroU32
+ };
+ (u64) => {
+ NonZeroU64
+ };
+ (u128) => {
+ NonZeroU128
+ };
+ (usize) => {
+ NonZeroUsize
+ };
+ (i8) => {
+ NonZeroI8
+ };
+ (i16) => {
+ NonZeroI16
+ };
+ (i32) => {
+ NonZeroI32
+ };
+ (i64) => {
+ NonZeroI64
+ };
+ (i128) => {
+ NonZeroI128
+ };
+ (isize) => {
+ NonZeroIsize
+ };
+}
+
+macro_rules! impl_one_value {
+ (f32, $op:expr, $record:ident) => {
+ impl_one_value!(normal, f32, $op, $record);
+ };
+ (f64, $op:expr, $record:ident) => {
+ impl_one_value!(normal, f64, $op, $record);
+ };
+ (bool, $op:expr, $record:ident) => {
+ impl_one_value!(normal, bool, $op, $record);
+ };
+ ($value_ty:tt, $op:expr, $record:ident) => {
+ impl_one_value!(normal, $value_ty, $op, $record);
+ impl_one_value!(nonzero, $value_ty, $op, $record);
+ };
+ (normal, $value_ty:tt, $op:expr, $record:ident) => {
+ impl $crate::sealed::Sealed for $value_ty {}
+ impl $crate::field::Value for $value_ty {
+ fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
+ visitor.$record(key, $op(*self))
+ }
+ }
+ };
+ (nonzero, $value_ty:tt, $op:expr, $record:ident) => {
+ // This `use num::*;` is reported as unused because it gets emitted
+ // for every single invocation of this macro, so there are multiple `use`s.
+ // All but the first are useless indeed.
+ // We need this import because we can't write a path where one part is
+ // the `ty_to_nonzero!($value_ty)` invocation.
+ #[allow(clippy::useless_attribute, unused)]
+ use num::*;
+ impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {}
+ impl $crate::field::Value for ty_to_nonzero!($value_ty) {
+ fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
+ visitor.$record(key, $op(self.get()))
+ }
+ }
+ };
+}
+
+macro_rules! impl_value {
+ ( $record:ident( $( $value_ty:tt ),+ ) ) => {
+ $(
+ impl_one_value!($value_ty, |this: $value_ty| this, $record);
+ )+
+ };
+ ( $record:ident( $( $value_ty:tt ),+ as $as_ty:ty) ) => {
+ $(
+ impl_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record);
+ )+
+ };
+}
+
+// ===== impl Value =====
+
+impl_values! {
+ record_u64(u64),
+ record_u64(usize, u32, u16, u8 as u64),
+ record_i64(i64),
+ record_i64(isize, i32, i16, i8 as i64),
+ record_u128(u128),
+ record_i128(i128),
+ record_bool(bool),
+ record_f64(f64, f32 as f64)
+}
+
+impl<T: crate::sealed::Sealed> crate::sealed::Sealed for Wrapping<T> {}
+impl<T: crate::field::Value> crate::field::Value for Wrapping<T> {
+ fn record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit) {
+ self.0.record(key, visitor)
+ }
+}
+
+impl crate::sealed::Sealed for str {}
+
+impl Value for str {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_str(key, self)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_error(key, self)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + Send + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + Send + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (self as &dyn std::error::Error).record(key, visitor)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + Sync + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + Sync + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (self as &dyn std::error::Error).record(key, visitor)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + Send + Sync + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + Send + Sync + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (self as &dyn std::error::Error).record(key, visitor)
+ }
+}
+
+impl<'a, T: ?Sized> crate::sealed::Sealed for &'a T where T: Value + crate::sealed::Sealed + 'a {}
+
+impl<'a, T: ?Sized> Value for &'a T
+where
+ T: Value + 'a,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (*self).record(key, visitor)
+ }
+}
+
+impl<'a, T: ?Sized> crate::sealed::Sealed for &'a mut T where T: Value + crate::sealed::Sealed + 'a {}
+
+impl<'a, T: ?Sized> Value for &'a mut T
+where
+ T: Value + 'a,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ // Don't use `(*self).record(key, visitor)`, otherwise would
+ // cause stack overflow due to `unconditional_recursion`.
+ T::record(self, key, visitor)
+ }
+}
+
+impl<'a> crate::sealed::Sealed for fmt::Arguments<'a> {}
+
+impl<'a> Value for fmt::Arguments<'a> {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_debug(key, self)
+ }
+}
+
+impl<T: ?Sized> crate::sealed::Sealed for crate::stdlib::boxed::Box<T> where T: Value {}
+
+impl<T: ?Sized> Value for crate::stdlib::boxed::Box<T>
+where
+ T: Value,
+{
+ #[inline]
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ self.as_ref().record(key, visitor)
+ }
+}
+
+impl crate::sealed::Sealed for String {}
+impl Value for String {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_str(key, self.as_str())
+ }
+}
+
+impl fmt::Debug for dyn Value {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // We are only going to be recording the field value, so we don't
+ // actually care about the field name here.
+ struct NullCallsite;
+ static NULL_CALLSITE: NullCallsite = NullCallsite;
+ impl crate::callsite::Callsite for NullCallsite {
+ fn set_interest(&self, _: crate::subscriber::Interest) {
+ unreachable!("you somehow managed to register the null callsite?")
+ }
+
+ fn metadata(&self) -> &crate::Metadata<'_> {
+ unreachable!("you somehow managed to access the null callsite?")
+ }
+ }
+
+ static FIELD: Field = Field {
+ i: 0,
+ fields: FieldSet::new(&[], crate::identify_callsite!(&NULL_CALLSITE)),
+ };
+
+ let mut res = Ok(());
+ self.record(&FIELD, &mut |_: &Field, val: &dyn fmt::Debug| {
+ res = write!(f, "{:?}", val);
+ });
+ res
+ }
+}
+
+impl fmt::Display for dyn Value {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(self, f)
+ }
+}
+
+// ===== impl DisplayValue =====
+
+impl<T: fmt::Display> crate::sealed::Sealed for DisplayValue<T> {}
+
+impl<T> Value for DisplayValue<T>
+where
+ T: fmt::Display,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_debug(key, self)
+ }
+}
+
+impl<T: fmt::Display> fmt::Debug for DisplayValue<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl<T: fmt::Display> fmt::Display for DisplayValue<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+// ===== impl DebugValue =====
+
+impl<T: fmt::Debug> crate::sealed::Sealed for DebugValue<T> {}
+
+impl<T> Value for DebugValue<T>
+where
+ T: fmt::Debug,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_debug(key, &self.0)
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for DebugValue<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+// ===== impl ValuableValue =====
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+impl crate::sealed::Sealed for valuable::Value<'_> {}
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+impl Value for valuable::Value<'_> {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_value(key, *self)
+ }
+}
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+impl crate::sealed::Sealed for &'_ dyn valuable::Valuable {}
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+impl Value for &'_ dyn valuable::Valuable {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_value(key, self.as_value())
+ }
+}
+
+impl crate::sealed::Sealed for Empty {}
+impl Value for Empty {
+ #[inline]
+ fn record(&self, _: &Field, _: &mut dyn Visit) {}
+}
+
+impl<T: Value> crate::sealed::Sealed for Option<T> {}
+
+impl<T: Value> Value for Option<T> {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ if let Some(v) = &self {
+ v.record(key, visitor)
+ }
+ }
+}
+
+// ===== impl Field =====
+
+impl Field {
+ /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
+ /// which defines this field.
+ ///
+ /// [`Identifier`]: super::callsite::Identifier
+ /// [`Callsite`]: super::callsite::Callsite
+ #[inline]
+ pub fn callsite(&self) -> callsite::Identifier {
+ self.fields.callsite()
+ }
+
+ /// Returns a string representing the name of the field.
+ pub fn name(&self) -> &'static str {
+ self.fields.names[self.i]
+ }
+}
+
+impl fmt::Display for Field {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad(self.name())
+ }
+}
+
+impl AsRef<str> for Field {
+ fn as_ref(&self) -> &str {
+ self.name()
+ }
+}
+
+impl PartialEq for Field {
+ fn eq(&self, other: &Self) -> bool {
+ self.callsite() == other.callsite() && self.i == other.i
+ }
+}
+
+impl Eq for Field {}
+
+impl Hash for Field {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.callsite().hash(state);
+ self.i.hash(state);
+ }
+}
+
+impl Clone for Field {
+ fn clone(&self) -> Self {
+ Field {
+ i: self.i,
+ fields: FieldSet {
+ names: self.fields.names,
+ callsite: self.fields.callsite(),
+ },
+ }
+ }
+}
+
+// ===== impl FieldSet =====
+
+impl FieldSet {
+ /// Constructs a new `FieldSet` with the given array of field names and callsite.
+ pub const fn new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self {
+ Self { names, callsite }
+ }
+
+ /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
+ /// which defines this set of fields..
+ ///
+ /// [`Identifier`]: super::callsite::Identifier
+ /// [`Callsite`]: super::callsite::Callsite
+ pub(crate) fn callsite(&self) -> callsite::Identifier {
+ callsite::Identifier(self.callsite.0)
+ }
+
+ /// Returns the [`Field`] named `name`, or `None` if no such field exists.
+ ///
+ /// [`Field`]: super::Field
+ pub fn field<Q: ?Sized>(&self, name: &Q) -> Option<Field>
+ where
+ Q: Borrow<str>,
+ {
+ let name = &name.borrow();
+ self.names.iter().position(|f| f == name).map(|i| Field {
+ i,
+ fields: FieldSet {
+ names: self.names,
+ callsite: self.callsite(),
+ },
+ })
+ }
+
+ /// Returns `true` if `self` contains the given `field`.
+ ///
+ /// <div class="example-wrap" style="display:inline-block">
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ /// <strong>Note</strong>: If <code>field</code> shares a name with a field
+ /// in this <code>FieldSet</code>, but was created by a <code>FieldSet</code>
+ /// with a different callsite, this <code>FieldSet</code> does <em>not</em>
+ /// contain it. This is so that if two separate span callsites define a field
+ /// named "foo", the <code>Field</code> corresponding to "foo" for each
+ /// of those callsites are not equivalent.
+ /// </pre></div>
+ pub fn contains(&self, field: &Field) -> bool {
+ field.callsite() == self.callsite() && field.i <= self.len()
+ }
+
+ /// Returns an iterator over the `Field`s in this `FieldSet`.
+ pub fn iter(&self) -> Iter {
+ let idxs = 0..self.len();
+ Iter {
+ idxs,
+ fields: FieldSet {
+ names: self.names,
+ callsite: self.callsite(),
+ },
+ }
+ }
+
+ /// Returns a new `ValueSet` with entries for this `FieldSet`'s values.
+ ///
+ /// Note that a `ValueSet` may not be constructed with arrays of over 32
+ /// elements.
+ #[doc(hidden)]
+ pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v>
+ where
+ V: ValidLen<'v>,
+ {
+ ValueSet {
+ fields: self,
+ values: values.borrow(),
+ }
+ }
+
+ /// Returns the number of fields in this `FieldSet`.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.names.len()
+ }
+
+ /// Returns whether or not this `FieldSet` has fields.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.names.is_empty()
+ }
+}
+
+impl<'a> IntoIterator for &'a FieldSet {
+ type IntoIter = Iter;
+ type Item = Field;
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl fmt::Debug for FieldSet {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FieldSet")
+ .field("names", &self.names)
+ .field("callsite", &self.callsite)
+ .finish()
+ }
+}
+
+impl fmt::Display for FieldSet {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_set()
+ .entries(self.names.iter().map(display))
+ .finish()
+ }
+}
+
+impl Eq for FieldSet {}
+
+impl PartialEq for FieldSet {
+ fn eq(&self, other: &Self) -> bool {
+ if core::ptr::eq(&self, &other) {
+ true
+ } else if cfg!(not(debug_assertions)) {
+ // In a well-behaving application, two `FieldSet`s can be assumed to
+ // be totally equal so long as they share the same callsite.
+ self.callsite == other.callsite
+ } else {
+ // However, when debug-assertions are enabled, do NOT assume that
+ // the application is well-behaving; check every the field names of
+ // each `FieldSet` for equality.
+
+ // `FieldSet` is destructured here to ensure a compile-error if the
+ // fields of `FieldSet` change.
+ let Self {
+ names: lhs_names,
+ callsite: lhs_callsite,
+ } = self;
+
+ let Self {
+ names: rhs_names,
+ callsite: rhs_callsite,
+ } = &other;
+
+ // Check callsite equality first, as it is probably cheaper to do
+ // than str equality.
+ lhs_callsite == rhs_callsite && lhs_names == rhs_names
+ }
+ }
+}
+
+// ===== impl Iter =====
+
+impl Iterator for Iter {
+ type Item = Field;
+ fn next(&mut self) -> Option<Field> {
+ let i = self.idxs.next()?;
+ Some(Field {
+ i,
+ fields: FieldSet {
+ names: self.fields.names,
+ callsite: self.fields.callsite(),
+ },
+ })
+ }
+}
+
+// ===== impl ValueSet =====
+
+impl<'a> ValueSet<'a> {
+ /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
+ /// defining the fields this `ValueSet` refers to.
+ ///
+ /// [`Identifier`]: super::callsite::Identifier
+ /// [`Callsite`]: super::callsite::Callsite
+ #[inline]
+ pub fn callsite(&self) -> callsite::Identifier {
+ self.fields.callsite()
+ }
+
+ /// Visits all the fields in this `ValueSet` with the provided [visitor].
+ ///
+ /// [visitor]: Visit
+ pub fn record(&self, visitor: &mut dyn Visit) {
+ let my_callsite = self.callsite();
+ for (field, value) in self.values {
+ if field.callsite() != my_callsite {
+ continue;
+ }
+ if let Some(value) = value {
+ value.record(field, visitor);
+ }
+ }
+ }
+
+ /// Returns the number of fields in this `ValueSet` that would be visited
+ /// by a given [visitor] to the [`ValueSet::record()`] method.
+ ///
+ /// [visitor]: Visit
+ /// [`ValueSet::record()`]: ValueSet::record()
+ pub fn len(&self) -> usize {
+ let my_callsite = self.callsite();
+ self.values
+ .iter()
+ .filter(|(field, _)| field.callsite() == my_callsite)
+ .count()
+ }
+
+ /// Returns `true` if this `ValueSet` contains a value for the given `Field`.
+ pub(crate) fn contains(&self, field: &Field) -> bool {
+ field.callsite() == self.callsite()
+ && self
+ .values
+ .iter()
+ .any(|(key, val)| *key == field && val.is_some())
+ }
+
+ /// Returns true if this `ValueSet` contains _no_ values.
+ pub fn is_empty(&self) -> bool {
+ let my_callsite = self.callsite();
+ self.values
+ .iter()
+ .all(|(key, val)| val.is_none() || key.callsite() != my_callsite)
+ }
+
+ pub(crate) fn field_set(&self) -> &FieldSet {
+ self.fields
+ }
+}
+
+impl<'a> fmt::Debug for ValueSet<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.values
+ .iter()
+ .fold(&mut f.debug_struct("ValueSet"), |dbg, (key, v)| {
+ if let Some(val) = v {
+ val.record(key, dbg);
+ }
+ dbg
+ })
+ .field("callsite", &self.callsite())
+ .finish()
+ }
+}
+
+impl<'a> fmt::Display for ValueSet<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.values
+ .iter()
+ .fold(&mut f.debug_map(), |dbg, (key, v)| {
+ if let Some(val) = v {
+ val.record(key, dbg);
+ }
+ dbg
+ })
+ .finish()
+ }
+}
+
+// ===== impl ValidLen =====
+
+mod private {
+ use super::*;
+
+ /// Marker trait implemented by arrays which are of valid length to
+ /// construct a `ValueSet`.
+ ///
+ /// `ValueSet`s may only be constructed from arrays containing 32 or fewer
+ /// elements, to ensure the array is small enough to always be allocated on the
+ /// stack. This trait is only implemented by arrays of an appropriate length,
+ /// ensuring that the correct size arrays are used at compile-time.
+ pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {}
+}
+
+macro_rules! impl_valid_len {
+ ( $( $len:tt ),+ ) => {
+ $(
+ impl<'a> private::ValidLen<'a> for
+ [(&'a Field, Option<&'a (dyn Value + 'a)>); $len] {}
+ )+
+ }
+}
+
+impl_valid_len! {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::metadata::{Kind, Level, Metadata};
+ use crate::stdlib::{borrow::ToOwned, string::String};
+
+ struct TestCallsite1;
+ static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1;
+ static TEST_META_1: Metadata<'static> = metadata! {
+ name: "field_test1",
+ target: module_path!(),
+ level: Level::INFO,
+ fields: &["foo", "bar", "baz"],
+ callsite: &TEST_CALLSITE_1,
+ kind: Kind::SPAN,
+ };
+
+ impl crate::callsite::Callsite for TestCallsite1 {
+ fn set_interest(&self, _: crate::subscriber::Interest) {
+ unimplemented!()
+ }
+
+ fn metadata(&self) -> &Metadata<'_> {
+ &TEST_META_1
+ }
+ }
+
+ struct TestCallsite2;
+ static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2;
+ static TEST_META_2: Metadata<'static> = metadata! {
+ name: "field_test2",
+ target: module_path!(),
+ level: Level::INFO,
+ fields: &["foo", "bar", "baz"],
+ callsite: &TEST_CALLSITE_2,
+ kind: Kind::SPAN,
+ };
+
+ impl crate::callsite::Callsite for TestCallsite2 {
+ fn set_interest(&self, _: crate::subscriber::Interest) {
+ unimplemented!()
+ }
+
+ fn metadata(&self) -> &Metadata<'_> {
+ &TEST_META_2
+ }
+ }
+
+ #[test]
+ fn value_set_with_no_values_is_empty() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), None),
+ (&fields.field("bar").unwrap(), None),
+ (&fields.field("baz").unwrap(), None),
+ ];
+ let valueset = fields.value_set(values);
+ assert!(valueset.is_empty());
+ }
+
+ #[test]
+ fn empty_value_set_is_empty() {
+ let fields = TEST_META_1.fields();
+ let valueset = fields.value_set(&[]);
+ assert!(valueset.is_empty());
+ }
+
+ #[test]
+ fn value_sets_with_fields_from_other_callsites_are_empty() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
+ ];
+ let valueset = TEST_META_2.fields().value_set(values);
+ assert!(valueset.is_empty())
+ }
+
+ #[test]
+ fn sparse_value_sets_are_not_empty() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), None),
+ (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
+ (&fields.field("baz").unwrap(), None),
+ ];
+ let valueset = fields.value_set(values);
+ assert!(!valueset.is_empty());
+ }
+
+ #[test]
+ fn fields_from_other_callsets_are_skipped() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), None),
+ (
+ &TEST_META_2.fields().field("bar").unwrap(),
+ Some(&57 as &dyn Value),
+ ),
+ (&fields.field("baz").unwrap(), None),
+ ];
+
+ struct MyVisitor;
+ impl Visit for MyVisitor {
+ fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
+ assert_eq!(field.callsite(), TEST_META_1.callsite())
+ }
+ }
+ let valueset = fields.value_set(values);
+ valueset.record(&mut MyVisitor);
+ }
+
+ #[test]
+ fn empty_fields_are_skipped() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&Empty as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
+ ];
+
+ struct MyVisitor;
+ impl Visit for MyVisitor {
+ fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
+ assert_eq!(field.name(), "bar")
+ }
+ }
+ let valueset = fields.value_set(values);
+ valueset.record(&mut MyVisitor);
+ }
+
+ #[test]
+ fn record_debug_fn() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
+ ];
+ let valueset = fields.value_set(values);
+ let mut result = String::new();
+ valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
+ use crate::stdlib::fmt::Write;
+ write!(&mut result, "{:?}", value).unwrap();
+ });
+ assert_eq!(result, "123".to_owned());
+ }
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn record_error() {
+ let fields = TEST_META_1.fields();
+ let err: Box<dyn std::error::Error + Send + Sync + 'static> =
+ std::io::Error::new(std::io::ErrorKind::Other, "lol").into();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&err as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&Empty as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
+ ];
+ let valueset = fields.value_set(values);
+ let mut result = String::new();
+ valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
+ use core::fmt::Write;
+ write!(&mut result, "{:?}", value).unwrap();
+ });
+ assert_eq!(result, format!("{}", err));
+ }
+}
diff --git a/third_party/rust/tracing-core/src/lazy.rs b/third_party/rust/tracing-core/src/lazy.rs
new file mode 100644
index 0000000000..4f004e6364
--- /dev/null
+++ b/third_party/rust/tracing-core/src/lazy.rs
@@ -0,0 +1,76 @@
+#[cfg(feature = "std")]
+pub(crate) use once_cell::sync::Lazy;
+
+#[cfg(not(feature = "std"))]
+pub(crate) use self::spin::Lazy;
+
+#[cfg(not(feature = "std"))]
+mod spin {
+ //! This is the `once_cell::sync::Lazy` type, but modified to use our
+ //! `spin::Once` type rather than `OnceCell`. This is used to replace
+ //! `once_cell::sync::Lazy` on `no-std` builds.
+ use crate::spin::Once;
+ use core::{cell::Cell, fmt, ops::Deref};
+
+ /// Re-implementation of `once_cell::sync::Lazy` on top of `spin::Once`
+ /// rather than `OnceCell`.
+ ///
+ /// This is used when the standard library is disabled.
+ pub(crate) struct Lazy<T, F = fn() -> T> {
+ cell: Once<T>,
+ init: Cell<Option<F>>,
+ }
+
+ impl<T: fmt::Debug, F> fmt::Debug for Lazy<T, F> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Lazy")
+ .field("cell", &self.cell)
+ .field("init", &"..")
+ .finish()
+ }
+ }
+
+ // We never create a `&F` from a `&Lazy<T, F>` so it is fine to not impl
+ // `Sync` for `F`. We do create a `&mut Option<F>` in `force`, but this is
+ // properly synchronized, so it only happens once so it also does not
+ // contribute to this impl.
+ unsafe impl<T, F: Send> Sync for Lazy<T, F> where Once<T>: Sync {}
+ // auto-derived `Send` impl is OK.
+
+ impl<T, F> Lazy<T, F> {
+ /// Creates a new lazy value with the given initializing function.
+ pub(crate) const fn new(init: F) -> Lazy<T, F> {
+ Lazy {
+ cell: Once::new(),
+ init: Cell::new(Some(init)),
+ }
+ }
+ }
+
+ impl<T, F: FnOnce() -> T> Lazy<T, F> {
+ /// Forces the evaluation of this lazy value and returns a reference to
+ /// the result.
+ ///
+ /// This is equivalent to the `Deref` impl, but is explicit.
+ pub(crate) fn force(this: &Lazy<T, F>) -> &T {
+ this.cell.call_once(|| match this.init.take() {
+ Some(f) => f(),
+ None => panic!("Lazy instance has previously been poisoned"),
+ })
+ }
+ }
+
+ impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
+ type Target = T;
+ fn deref(&self) -> &T {
+ Lazy::force(self)
+ }
+ }
+
+ impl<T: Default> Default for Lazy<T> {
+ /// Creates a new lazy value using `Default` as the initializing function.
+ fn default() -> Lazy<T> {
+ Lazy::new(T::default)
+ }
+ }
+}
diff --git a/third_party/rust/tracing-core/src/lib.rs b/third_party/rust/tracing-core/src/lib.rs
new file mode 100644
index 0000000000..c1f87b22f0
--- /dev/null
+++ b/third_party/rust/tracing-core/src/lib.rs
@@ -0,0 +1,295 @@
+//! Core primitives for `tracing`.
+//!
+//! [`tracing`] is a framework for instrumenting Rust programs to collect
+//! structured, event-based diagnostic information. This crate defines the core
+//! primitives of `tracing`.
+//!
+//! This crate provides:
+//!
+//! * [`span::Id`] identifies a span within the execution of a program.
+//!
+//! * [`Event`] represents a single event within a trace.
+//!
+//! * [`Subscriber`], the trait implemented to collect trace data.
+//!
+//! * [`Metadata`] and [`Callsite`] provide information describing spans and
+//! `Event`s.
+//!
+//! * [`Field`], [`FieldSet`], [`Value`], and [`ValueSet`] represent the
+//! structured data attached to a span.
+//!
+//! * [`Dispatch`] allows spans and events to be dispatched to `Subscriber`s.
+//!
+//! In addition, it defines the global callsite registry and per-thread current
+//! dispatcher which other components of the tracing system rely on.
+//!
+//! *Compiler support: [requires `rustc` 1.49+][msrv]*
+//!
+//! [msrv]: #supported-rust-versions
+//!
+//! ## Usage
+//!
+//! Application authors will typically not use this crate directly. Instead,
+//! they will use the [`tracing`] crate, which provides a much more
+//! fully-featured API. However, this crate's API will change very infrequently,
+//! so it may be used when dependencies must be very stable.
+//!
+//! `Subscriber` implementations may depend on `tracing-core` rather than
+//! `tracing`, as the additional APIs provided by `tracing` are primarily useful
+//! for instrumenting libraries and applications, and are generally not
+//! necessary for `Subscriber` implementations.
+//!
+//! The [`tokio-rs/tracing`] repository contains less stable crates designed to
+//! be used with the `tracing` ecosystem. It includes a collection of
+//! `Subscriber` implementations, as well as utility and adapter crates.
+//!
+//! ## Crate Feature Flags
+//!
+//! The following crate [feature flags] are available:
+//!
+//! * `std`: Depend on the Rust standard library (enabled by default).
+//!
+//! `no_std` users may disable this feature with `default-features = false`:
+//!
+//! ```toml
+//! [dependencies]
+//! tracing-core = { version = "0.1.22", default-features = false }
+//! ```
+//!
+//! **Note**:`tracing-core`'s `no_std` support requires `liballoc`.
+//!
+//! ### Unstable Features
+//!
+//! These feature flags enable **unstable** features. The public API may break in 0.1.x
+//! releases. To enable these features, the `--cfg tracing_unstable` must be passed to
+//! `rustc` when compiling.
+//!
+//! The following unstable feature flags are currently available:
+//!
+//! * `valuable`: Enables support for recording [field values] using the
+//! [`valuable`] crate.
+//!
+//! #### Enabling Unstable Features
+//!
+//! The easiest way to set the `tracing_unstable` cfg is to use the `RUSTFLAGS`
+//! env variable when running `cargo` commands:
+//!
+//! ```shell
+//! RUSTFLAGS="--cfg tracing_unstable" cargo build
+//! ```
+//! Alternatively, the following can be added to the `.cargo/config` file in a
+//! project to automatically enable the cfg flag for that project:
+//!
+//! ```toml
+//! [build]
+//! rustflags = ["--cfg", "tracing_unstable"]
+//! ```
+//!
+//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
+//! [field values]: crate::field
+//! [`valuable`]: https://crates.io/crates/valuable
+//!
+//! ## Supported Rust Versions
+//!
+//! Tracing is built against the latest stable release. The minimum supported
+//! version is 1.49. The current Tracing version is not guaranteed to build on
+//! Rust versions earlier than the minimum supported version.
+//!
+//! Tracing follows the same compiler support policies as the rest of the Tokio
+//! project. The current stable Rust compiler and the three most recent minor
+//! versions before it will always be supported. For example, if the current
+//! stable compiler version is 1.45, the minimum supported version will not be
+//! increased past 1.42, three minor versions prior. Increasing the minimum
+//! supported compiler version is not considered a semver breaking change as
+//! long as doing so complies with this policy.
+//!
+//!
+//! [`span::Id`]: span::Id
+//! [`Event`]: event::Event
+//! [`Subscriber`]: subscriber::Subscriber
+//! [`Metadata`]: metadata::Metadata
+//! [`Callsite`]: callsite::Callsite
+//! [`Field`]: field::Field
+//! [`FieldSet`]: field::FieldSet
+//! [`Value`]: field::Value
+//! [`ValueSet`]: field::ValueSet
+//! [`Dispatch`]: dispatcher::Dispatch
+//! [`tokio-rs/tracing`]: https://github.com/tokio-rs/tracing
+//! [`tracing`]: https://crates.io/crates/tracing
+#![doc(html_root_url = "https://docs.rs/tracing-core/0.1.22")]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
+ issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
+)]
+#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
+#![warn(
+ missing_debug_implementations,
+ missing_docs,
+ rust_2018_idioms,
+ unreachable_pub,
+ bad_style,
+ const_err,
+ dead_code,
+ improper_ctypes,
+ non_shorthand_field_patterns,
+ no_mangle_generic_items,
+ overflowing_literals,
+ path_statements,
+ patterns_in_fns_without_body,
+ private_in_public,
+ unconditional_recursion,
+ unused,
+ unused_allocation,
+ unused_comparisons,
+ unused_parens,
+ while_true
+)]
+#[cfg(not(feature = "std"))]
+extern crate alloc;
+
+/// Statically constructs an [`Identifier`] for the provided [`Callsite`].
+///
+/// This may be used in contexts such as static initializers.
+///
+/// For example:
+/// ```rust
+/// use tracing_core::{callsite, identify_callsite};
+/// # use tracing_core::{Metadata, subscriber::Interest};
+/// # fn main() {
+/// pub struct MyCallsite {
+/// // ...
+/// }
+/// impl callsite::Callsite for MyCallsite {
+/// # fn set_interest(&self, _: Interest) { unimplemented!() }
+/// # fn metadata(&self) -> &Metadata { unimplemented!() }
+/// // ...
+/// }
+///
+/// static CALLSITE: MyCallsite = MyCallsite {
+/// // ...
+/// };
+///
+/// static CALLSITE_ID: callsite::Identifier = identify_callsite!(&CALLSITE);
+/// # }
+/// ```
+///
+/// [`Identifier`]: callsite::Identifier
+/// [`Callsite`]: callsite::Callsite
+#[macro_export]
+macro_rules! identify_callsite {
+ ($callsite:expr) => {
+ $crate::callsite::Identifier($callsite)
+ };
+}
+
+/// Statically constructs new span [metadata].
+///
+/// /// For example:
+/// ```rust
+/// # use tracing_core::{callsite::Callsite, subscriber::Interest};
+/// use tracing_core::metadata;
+/// use tracing_core::metadata::{Kind, Level, Metadata};
+/// # fn main() {
+/// # pub struct MyCallsite { }
+/// # impl Callsite for MyCallsite {
+/// # fn set_interest(&self, _: Interest) { unimplemented!() }
+/// # fn metadata(&self) -> &Metadata { unimplemented!() }
+/// # }
+/// #
+/// static FOO_CALLSITE: MyCallsite = MyCallsite {
+/// // ...
+/// };
+///
+/// static FOO_METADATA: Metadata = metadata!{
+/// name: "foo",
+/// target: module_path!(),
+/// level: Level::DEBUG,
+/// fields: &["bar", "baz"],
+/// callsite: &FOO_CALLSITE,
+/// kind: Kind::SPAN,
+/// };
+/// # }
+/// ```
+///
+/// [metadata]: metadata::Metadata
+/// [`Metadata::new`]: metadata::Metadata::new
+#[macro_export]
+macro_rules! metadata {
+ (
+ name: $name:expr,
+ target: $target:expr,
+ level: $level:expr,
+ fields: $fields:expr,
+ callsite: $callsite:expr,
+ kind: $kind:expr
+ ) => {
+ $crate::metadata! {
+ name: $name,
+ target: $target,
+ level: $level,
+ fields: $fields,
+ callsite: $callsite,
+ kind: $kind,
+ }
+ };
+ (
+ name: $name:expr,
+ target: $target:expr,
+ level: $level:expr,
+ fields: $fields:expr,
+ callsite: $callsite:expr,
+ kind: $kind:expr,
+ ) => {
+ $crate::metadata::Metadata::new(
+ $name,
+ $target,
+ $level,
+ Some(file!()),
+ Some(line!()),
+ Some(module_path!()),
+ $crate::field::FieldSet::new($fields, $crate::identify_callsite!($callsite)),
+ $kind,
+ )
+ };
+}
+
+pub(crate) mod lazy;
+
+// Trimmed-down vendored version of spin 0.5.2 (0387621)
+// Dependency of no_std lazy_static, not required in a std build
+#[cfg(not(feature = "std"))]
+pub(crate) mod spin;
+
+#[cfg(not(feature = "std"))]
+#[doc(hidden)]
+pub type Once = self::spin::Once<()>;
+
+#[cfg(feature = "std")]
+pub use stdlib::sync::Once;
+
+pub mod callsite;
+pub mod dispatcher;
+pub mod event;
+pub mod field;
+pub mod metadata;
+mod parent;
+pub mod span;
+pub(crate) mod stdlib;
+pub mod subscriber;
+
+#[doc(inline)]
+pub use self::{
+ callsite::Callsite,
+ dispatcher::Dispatch,
+ event::Event,
+ field::Field,
+ metadata::{Level, LevelFilter, Metadata},
+ subscriber::Subscriber,
+};
+
+pub use self::{metadata::Kind, subscriber::Interest};
+
+mod sealed {
+ pub trait Sealed {}
+}
diff --git a/third_party/rust/tracing-core/src/metadata.rs b/third_party/rust/tracing-core/src/metadata.rs
new file mode 100644
index 0000000000..a154419a74
--- /dev/null
+++ b/third_party/rust/tracing-core/src/metadata.rs
@@ -0,0 +1,1114 @@
+//! Metadata describing trace data.
+use super::{callsite, field};
+use crate::stdlib::{
+ cmp, fmt,
+ str::FromStr,
+ sync::atomic::{AtomicUsize, Ordering},
+};
+
+/// Metadata describing a [span] or [event].
+///
+/// All spans and events have the following metadata:
+/// - A [name], represented as a static string.
+/// - A [target], a string that categorizes part of the system where the span
+/// or event occurred. The `tracing` macros default to using the module
+/// path where the span or event originated as the target, but it may be
+/// overridden.
+/// - A [verbosity level]. This determines how verbose a given span or event
+/// is, and allows enabling or disabling more verbose diagnostics
+/// situationally. See the documentation for the [`Level`] type for details.
+/// - The names of the [fields] defined by the span or event.
+/// - Whether the metadata corresponds to a span or event.
+///
+/// In addition, the following optional metadata describing the source code
+/// location where the span or event originated _may_ be provided:
+/// - The [file name]
+/// - The [line number]
+/// - The [module path]
+///
+/// Metadata is used by [`Subscriber`]s when filtering spans and events, and it
+/// may also be used as part of their data payload.
+///
+/// When created by the `event!` or `span!` macro, the metadata describing a
+/// particular event or span is constructed statically and exists as a single
+/// static instance. Thus, the overhead of creating the metadata is
+/// _significantly_ lower than that of creating the actual span. Therefore,
+/// filtering is based on metadata, rather than on the constructed span.
+///
+/// ## Equality
+///
+/// In well-behaved applications, two `Metadata` with equal
+/// [callsite identifiers] will be equal in all other ways (i.e., have the same
+/// `name`, `target`, etc.). Consequently, in release builds, [`Metadata::eq`]
+/// *only* checks that its arguments have equal callsites. However, the equality
+/// of `Metadata`'s other fields is checked in debug builds.
+///
+/// [span]: super::span
+/// [event]: super::event
+/// [name]: Self::name
+/// [target]: Self::target
+/// [fields]: Self::fields
+/// [verbosity level]: Self::level
+/// [file name]: Self::file
+/// [line number]: Self::line
+/// [module path]: Self::module_path
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [callsite identifiers]: Self::callsite
+pub struct Metadata<'a> {
+ /// The name of the span described by this metadata.
+ name: &'static str,
+
+ /// The part of the system that the span that this metadata describes
+ /// occurred in.
+ target: &'a str,
+
+ /// The level of verbosity of the described span.
+ level: Level,
+
+ /// The name of the Rust module where the span occurred, or `None` if this
+ /// could not be determined.
+ module_path: Option<&'a str>,
+
+ /// The name of the source code file where the span occurred, or `None` if
+ /// this could not be determined.
+ file: Option<&'a str>,
+
+ /// The line number in the source code file where the span occurred, or
+ /// `None` if this could not be determined.
+ line: Option<u32>,
+
+ /// The names of the key-value fields attached to the described span or
+ /// event.
+ fields: field::FieldSet,
+
+ /// The kind of the callsite.
+ kind: Kind,
+}
+
+/// Indicates whether the callsite is a span or event.
+#[derive(Clone, Eq, PartialEq)]
+pub struct Kind(u8);
+
+/// Describes the level of verbosity of a span or event.
+///
+/// # Comparing Levels
+///
+/// `Level` implements the [`PartialOrd`] and [`Ord`] traits, allowing two
+/// `Level`s to be compared to determine which is considered more or less
+/// verbose. Levels which are more verbose are considered "greater than" levels
+/// which are less verbose, with [`Level::ERROR`] considered the lowest, and
+/// [`Level::TRACE`] considered the highest.
+///
+/// For example:
+/// ```
+/// use tracing_core::Level;
+///
+/// assert!(Level::TRACE > Level::DEBUG);
+/// assert!(Level::ERROR < Level::WARN);
+/// assert!(Level::INFO <= Level::DEBUG);
+/// assert_eq!(Level::TRACE, Level::TRACE);
+/// ```
+///
+/// # Filtering
+///
+/// `Level`s are typically used to implement filtering that determines which
+/// spans and events are enabled. Depending on the use case, more or less
+/// verbose diagnostics may be desired. For example, when running in
+/// development, [`DEBUG`]-level traces may be enabled by default. When running in
+/// production, only [`INFO`]-level and lower traces might be enabled. Libraries
+/// may include very verbose diagnostics at the [`DEBUG`] and/or [`TRACE`] levels.
+/// Applications using those libraries typically chose to ignore those traces. However, when
+/// debugging an issue involving said libraries, it may be useful to temporarily
+/// enable the more verbose traces.
+///
+/// The [`LevelFilter`] type is provided to enable filtering traces by
+/// verbosity. `Level`s can be compared against [`LevelFilter`]s, and
+/// [`LevelFilter`] has a variant for each `Level`, which compares analogously
+/// to that level. In addition, [`LevelFilter`] adds a [`LevelFilter::OFF`]
+/// variant, which is considered "less verbose" than every other `Level`. This is
+/// intended to allow filters to completely disable tracing in a particular context.
+///
+/// For example:
+/// ```
+/// use tracing_core::{Level, LevelFilter};
+///
+/// assert!(LevelFilter::OFF < Level::TRACE);
+/// assert!(LevelFilter::TRACE > Level::DEBUG);
+/// assert!(LevelFilter::ERROR < Level::WARN);
+/// assert!(LevelFilter::INFO <= Level::DEBUG);
+/// assert!(LevelFilter::INFO >= Level::INFO);
+/// ```
+///
+/// ## Examples
+///
+/// Below is a simple example of how a [`Subscriber`] could implement filtering through
+/// a [`LevelFilter`]. When a span or event is recorded, the [`Subscriber::enabled`] method
+/// compares the span or event's `Level` against the configured [`LevelFilter`].
+/// The optional [`Subscriber::max_level_hint`] method can also be implemented to allow spans
+/// and events above a maximum verbosity level to be skipped more efficiently,
+/// often improving performance in short-lived programs.
+///
+/// ```
+/// use tracing_core::{span, Event, Level, LevelFilter, Subscriber, Metadata};
+/// # use tracing_core::span::{Id, Record, Current};
+///
+/// #[derive(Debug)]
+/// pub struct MySubscriber {
+/// /// The most verbose level that this subscriber will enable.
+/// max_level: LevelFilter,
+///
+/// // ...
+/// }
+///
+/// impl MySubscriber {
+/// /// Returns a new `MySubscriber` which will record spans and events up to
+/// /// `max_level`.
+/// pub fn with_max_level(max_level: LevelFilter) -> Self {
+/// Self {
+/// max_level,
+/// // ...
+/// }
+/// }
+/// }
+/// impl Subscriber for MySubscriber {
+/// fn enabled(&self, meta: &Metadata<'_>) -> bool {
+/// // A span or event is enabled if it is at or below the configured
+/// // maximum level.
+/// meta.level() <= &self.max_level
+/// }
+///
+/// // This optional method returns the most verbose level that this
+/// // subscriber will enable. Although implementing this method is not
+/// // *required*, it permits additional optimizations when it is provided,
+/// // allowing spans and events above the max level to be skipped
+/// // more efficiently.
+/// fn max_level_hint(&self) -> Option<LevelFilter> {
+/// Some(self.max_level)
+/// }
+///
+/// // Implement the rest of the subscriber...
+/// fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
+/// // ...
+/// # drop(span); Id::from_u64(1)
+/// }
+
+/// fn event(&self, event: &Event<'_>) {
+/// // ...
+/// # drop(event);
+/// }
+///
+/// // ...
+/// # fn enter(&self, _: &Id) {}
+/// # fn exit(&self, _: &Id) {}
+/// # fn record(&self, _: &Id, _: &Record<'_>) {}
+/// # fn record_follows_from(&self, _: &Id, _: &Id) {}
+/// }
+/// ```
+///
+/// It is worth noting that the `tracing-subscriber` crate provides [additional
+/// APIs][envfilter] for performing more sophisticated filtering, such as
+/// enabling different levels based on which module or crate a span or event is
+/// recorded in.
+///
+/// [`DEBUG`]: Level::DEBUG
+/// [`INFO`]: Level::INFO
+/// [`TRACE`]: Level::TRACE
+/// [`Subscriber::enabled`]: crate::subscriber::Subscriber::enabled
+/// [`Subscriber::max_level_hint`]: crate::subscriber::Subscriber::max_level_hint
+/// [`Subscriber`]: crate::subscriber::Subscriber
+/// [envfilter]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Level(LevelInner);
+
+/// A filter comparable to a verbosity [`Level`].
+///
+/// If a [`Level`] is considered less than a `LevelFilter`, it should be
+/// considered enabled; if greater than or equal to the `LevelFilter`,
+/// that level is disabled. See [`LevelFilter::current`] for more
+/// details.
+///
+/// Note that this is essentially identical to the `Level` type, but with the
+/// addition of an [`OFF`] level that completely disables all trace
+/// instrumentation.
+///
+/// See the documentation for the [`Level`] type to see how `Level`s
+/// and `LevelFilter`s interact.
+///
+/// [`OFF`]: LevelFilter::OFF
+#[repr(transparent)]
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct LevelFilter(Option<Level>);
+
+/// Indicates that a string could not be parsed to a valid level.
+#[derive(Clone, Debug)]
+pub struct ParseLevelFilterError(());
+
+static MAX_LEVEL: AtomicUsize = AtomicUsize::new(LevelFilter::OFF_USIZE);
+
+// ===== impl Metadata =====
+
+impl<'a> Metadata<'a> {
+ /// Construct new metadata for a span or event, with a name, target, level, field
+ /// names, and optional source code location.
+ pub const fn new(
+ name: &'static str,
+ target: &'a str,
+ level: Level,
+ file: Option<&'a str>,
+ line: Option<u32>,
+ module_path: Option<&'a str>,
+ fields: field::FieldSet,
+ kind: Kind,
+ ) -> Self {
+ Metadata {
+ name,
+ target,
+ level,
+ module_path,
+ file,
+ line,
+ fields,
+ kind,
+ }
+ }
+
+ /// Returns the names of the fields on the described span or event.
+ pub fn fields(&self) -> &field::FieldSet {
+ &self.fields
+ }
+
+ /// Returns the level of verbosity of the described span or event.
+ pub fn level(&self) -> &Level {
+ &self.level
+ }
+
+ /// Returns the name of the span.
+ pub fn name(&self) -> &'static str {
+ self.name
+ }
+
+ /// Returns a string describing the part of the system where the span or
+ /// event that this metadata describes occurred.
+ ///
+ /// Typically, this is the module path, but alternate targets may be set
+ /// when spans or events are constructed.
+ pub fn target(&self) -> &'a str {
+ self.target
+ }
+
+ /// Returns the path to the Rust module where the span occurred, or
+ /// `None` if the module path is unknown.
+ pub fn module_path(&self) -> Option<&'a str> {
+ self.module_path
+ }
+
+ /// Returns the name of the source code file where the span
+ /// occurred, or `None` if the file is unknown
+ pub fn file(&self) -> Option<&'a str> {
+ self.file
+ }
+
+ /// Returns the line number in the source code file where the span
+ /// occurred, or `None` if the line number is unknown.
+ pub fn line(&self) -> Option<u32> {
+ self.line
+ }
+
+ /// Returns an opaque `Identifier` that uniquely identifies the callsite
+ /// this `Metadata` originated from.
+ #[inline]
+ pub fn callsite(&self) -> callsite::Identifier {
+ self.fields.callsite()
+ }
+
+ /// Returns true if the callsite kind is `Event`.
+ pub fn is_event(&self) -> bool {
+ self.kind.is_event()
+ }
+
+ /// Return true if the callsite kind is `Span`.
+ pub fn is_span(&self) -> bool {
+ self.kind.is_span()
+ }
+}
+
+impl<'a> fmt::Debug for Metadata<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut meta = f.debug_struct("Metadata");
+ meta.field("name", &self.name)
+ .field("target", &self.target)
+ .field("level", &self.level);
+
+ if let Some(path) = self.module_path() {
+ meta.field("module_path", &path);
+ }
+
+ match (self.file(), self.line()) {
+ (Some(file), Some(line)) => {
+ meta.field("location", &format_args!("{}:{}", file, line));
+ }
+ (Some(file), None) => {
+ meta.field("file", &format_args!("{}", file));
+ }
+
+ // Note: a line num with no file is a kind of weird case that _probably_ never occurs...
+ (None, Some(line)) => {
+ meta.field("line", &line);
+ }
+ (None, None) => {}
+ };
+
+ meta.field("fields", &format_args!("{}", self.fields))
+ .field("callsite", &self.callsite())
+ .field("kind", &self.kind)
+ .finish()
+ }
+}
+
+impl Kind {
+ const EVENT_BIT: u8 = 1 << 0;
+ const SPAN_BIT: u8 = 1 << 1;
+ const HINT_BIT: u8 = 1 << 2;
+
+ /// `Event` callsite
+ pub const EVENT: Kind = Kind(Self::EVENT_BIT);
+
+ /// `Span` callsite
+ pub const SPAN: Kind = Kind(Self::SPAN_BIT);
+
+ /// `enabled!` callsite. [`Subscriber`][`crate::subscriber::Subscriber`]s can assume
+ /// this `Kind` means they will never recieve a
+ /// full event with this [`Metadata`].
+ pub const HINT: Kind = Kind(Self::HINT_BIT);
+
+ /// Return true if the callsite kind is `Span`
+ pub fn is_span(&self) -> bool {
+ self.0 & Self::SPAN_BIT == Self::SPAN_BIT
+ }
+
+ /// Return true if the callsite kind is `Event`
+ pub fn is_event(&self) -> bool {
+ self.0 & Self::EVENT_BIT == Self::EVENT_BIT
+ }
+
+ /// Return true if the callsite kind is `Hint`
+ pub fn is_hint(&self) -> bool {
+ self.0 & Self::HINT_BIT == Self::HINT_BIT
+ }
+
+ /// Sets that this `Kind` is a [hint](Self::HINT).
+ ///
+ /// This can be called on [`SPAN`](Self::SPAN) and [`EVENT`](Self::EVENT)
+ /// kinds to construct a hint callsite that also counts as a span or event.
+ pub const fn hint(self) -> Self {
+ Self(self.0 | Self::HINT_BIT)
+ }
+}
+
+impl fmt::Debug for Kind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.write_str("Kind(")?;
+ let mut has_bits = false;
+ let mut write_bit = |name: &str| {
+ if has_bits {
+ f.write_str(" | ")?;
+ }
+ f.write_str(name)?;
+ has_bits = true;
+ Ok(())
+ };
+
+ if self.is_event() {
+ write_bit("EVENT")?;
+ }
+
+ if self.is_span() {
+ write_bit("SPAN")?;
+ }
+
+ if self.is_hint() {
+ write_bit("HINT")?;
+ }
+
+ // if none of the expected bits were set, something is messed up, so
+ // just print the bits for debugging purposes
+ if !has_bits {
+ write!(f, "{:#b}", self.0)?;
+ }
+
+ f.write_str(")")
+ }
+}
+
+impl<'a> Eq for Metadata<'a> {}
+
+impl<'a> PartialEq for Metadata<'a> {
+ #[inline]
+ fn eq(&self, other: &Self) -> bool {
+ if core::ptr::eq(&self, &other) {
+ true
+ } else if cfg!(not(debug_assertions)) {
+ // In a well-behaving application, two `Metadata` can be assumed to
+ // be totally equal so long as they share the same callsite.
+ self.callsite() == other.callsite()
+ } else {
+ // However, when debug-assertions are enabled, do not assume that
+ // the application is well-behaving; check every field of `Metadata`
+ // for equality.
+
+ // `Metadata` is destructured here to ensure a compile-error if the
+ // fields of `Metadata` change.
+ let Metadata {
+ name: lhs_name,
+ target: lhs_target,
+ level: lhs_level,
+ module_path: lhs_module_path,
+ file: lhs_file,
+ line: lhs_line,
+ fields: lhs_fields,
+ kind: lhs_kind,
+ } = self;
+
+ let Metadata {
+ name: rhs_name,
+ target: rhs_target,
+ level: rhs_level,
+ module_path: rhs_module_path,
+ file: rhs_file,
+ line: rhs_line,
+ fields: rhs_fields,
+ kind: rhs_kind,
+ } = &other;
+
+ // The initial comparison of callsites is purely an optimization;
+ // it can be removed without affecting the overall semantics of the
+ // expression.
+ self.callsite() == other.callsite()
+ && lhs_name == rhs_name
+ && lhs_target == rhs_target
+ && lhs_level == rhs_level
+ && lhs_module_path == rhs_module_path
+ && lhs_file == rhs_file
+ && lhs_line == rhs_line
+ && lhs_fields == rhs_fields
+ && lhs_kind == rhs_kind
+ }
+ }
+}
+
+// ===== impl Level =====
+
+impl Level {
+ /// The "error" level.
+ ///
+ /// Designates very serious errors.
+ pub const ERROR: Level = Level(LevelInner::Error);
+ /// The "warn" level.
+ ///
+ /// Designates hazardous situations.
+ pub const WARN: Level = Level(LevelInner::Warn);
+ /// The "info" level.
+ ///
+ /// Designates useful information.
+ pub const INFO: Level = Level(LevelInner::Info);
+ /// The "debug" level.
+ ///
+ /// Designates lower priority information.
+ pub const DEBUG: Level = Level(LevelInner::Debug);
+ /// The "trace" level.
+ ///
+ /// Designates very low priority, often extremely verbose, information.
+ pub const TRACE: Level = Level(LevelInner::Trace);
+
+ /// Returns the string representation of the `Level`.
+ ///
+ /// This returns the same string as the `fmt::Display` implementation.
+ pub fn as_str(&self) -> &'static str {
+ match *self {
+ Level::TRACE => "TRACE",
+ Level::DEBUG => "DEBUG",
+ Level::INFO => "INFO",
+ Level::WARN => "WARN",
+ Level::ERROR => "ERROR",
+ }
+ }
+}
+
+impl fmt::Display for Level {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Level::TRACE => f.pad("TRACE"),
+ Level::DEBUG => f.pad("DEBUG"),
+ Level::INFO => f.pad("INFO"),
+ Level::WARN => f.pad("WARN"),
+ Level::ERROR => f.pad("ERROR"),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl crate::stdlib::error::Error for ParseLevelError {}
+
+impl FromStr for Level {
+ type Err = ParseLevelError;
+ fn from_str(s: &str) -> Result<Self, ParseLevelError> {
+ s.parse::<usize>()
+ .map_err(|_| ParseLevelError { _p: () })
+ .and_then(|num| match num {
+ 1 => Ok(Level::ERROR),
+ 2 => Ok(Level::WARN),
+ 3 => Ok(Level::INFO),
+ 4 => Ok(Level::DEBUG),
+ 5 => Ok(Level::TRACE),
+ _ => Err(ParseLevelError { _p: () }),
+ })
+ .or_else(|_| match s {
+ s if s.eq_ignore_ascii_case("error") => Ok(Level::ERROR),
+ s if s.eq_ignore_ascii_case("warn") => Ok(Level::WARN),
+ s if s.eq_ignore_ascii_case("info") => Ok(Level::INFO),
+ s if s.eq_ignore_ascii_case("debug") => Ok(Level::DEBUG),
+ s if s.eq_ignore_ascii_case("trace") => Ok(Level::TRACE),
+ _ => Err(ParseLevelError { _p: () }),
+ })
+ }
+}
+
+#[repr(usize)]
+#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
+enum LevelInner {
+ /// The "trace" level.
+ ///
+ /// Designates very low priority, often extremely verbose, information.
+ Trace = 0,
+ /// The "debug" level.
+ ///
+ /// Designates lower priority information.
+ Debug = 1,
+ /// The "info" level.
+ ///
+ /// Designates useful information.
+ Info = 2,
+ /// The "warn" level.
+ ///
+ /// Designates hazardous situations.
+ Warn = 3,
+ /// The "error" level.
+ ///
+ /// Designates very serious errors.
+ Error = 4,
+}
+
+// === impl LevelFilter ===
+
+impl From<Level> for LevelFilter {
+ #[inline]
+ fn from(level: Level) -> Self {
+ Self::from_level(level)
+ }
+}
+
+impl From<Option<Level>> for LevelFilter {
+ #[inline]
+ fn from(level: Option<Level>) -> Self {
+ Self(level)
+ }
+}
+
+impl From<LevelFilter> for Option<Level> {
+ #[inline]
+ fn from(filter: LevelFilter) -> Self {
+ filter.into_level()
+ }
+}
+
+impl LevelFilter {
+ /// The "off" level.
+ ///
+ /// Designates that trace instrumentation should be completely disabled.
+ pub const OFF: LevelFilter = LevelFilter(None);
+ /// The "error" level.
+ ///
+ /// Designates very serious errors.
+ pub const ERROR: LevelFilter = LevelFilter::from_level(Level::ERROR);
+ /// The "warn" level.
+ ///
+ /// Designates hazardous situations.
+ pub const WARN: LevelFilter = LevelFilter::from_level(Level::WARN);
+ /// The "info" level.
+ ///
+ /// Designates useful information.
+ pub const INFO: LevelFilter = LevelFilter::from_level(Level::INFO);
+ /// The "debug" level.
+ ///
+ /// Designates lower priority information.
+ pub const DEBUG: LevelFilter = LevelFilter::from_level(Level::DEBUG);
+ /// The "trace" level.
+ ///
+ /// Designates very low priority, often extremely verbose, information.
+ pub const TRACE: LevelFilter = LevelFilter(Some(Level::TRACE));
+
+ /// Returns a `LevelFilter` that enables spans and events with verbosity up
+ /// to and including `level`.
+ pub const fn from_level(level: Level) -> Self {
+ Self(Some(level))
+ }
+
+ /// Returns the most verbose [`Level`] that this filter accepts, or `None`
+ /// if it is [`OFF`].
+ ///
+ /// [`OFF`]: LevelFilter::OFF
+ pub const fn into_level(self) -> Option<Level> {
+ self.0
+ }
+
+ // These consts are necessary because `as` casts are not allowed as
+ // match patterns.
+ const ERROR_USIZE: usize = LevelInner::Error as usize;
+ const WARN_USIZE: usize = LevelInner::Warn as usize;
+ const INFO_USIZE: usize = LevelInner::Info as usize;
+ const DEBUG_USIZE: usize = LevelInner::Debug as usize;
+ const TRACE_USIZE: usize = LevelInner::Trace as usize;
+ // Using the value of the last variant + 1 ensures that we match the value
+ // for `Option::None` as selected by the niche optimization for
+ // `LevelFilter`. If this is the case, converting a `usize` value into a
+ // `LevelFilter` (in `LevelFilter::current`) will be an identity conversion,
+ // rather than generating a lookup table.
+ const OFF_USIZE: usize = LevelInner::Error as usize + 1;
+
+ /// Returns a `LevelFilter` that matches the most verbose [`Level`] that any
+ /// currently active [`Subscriber`] will enable.
+ ///
+ /// User code should treat this as a *hint*. If a given span or event has a
+ /// level *higher* than the returned `LevelFilter`, it will not be enabled.
+ /// However, if the level is less than or equal to this value, the span or
+ /// event is *not* guaranteed to be enabled; the subscriber will still
+ /// filter each callsite individually.
+ ///
+ /// Therefore, comparing a given span or event's level to the returned
+ /// `LevelFilter` **can** be used for determining if something is
+ /// *disabled*, but **should not** be used for determining if something is
+ /// *enabled*.
+ ///
+ /// [`Level`]: super::Level
+ /// [`Subscriber`]: super::Subscriber
+ #[inline(always)]
+ pub fn current() -> Self {
+ match MAX_LEVEL.load(Ordering::Relaxed) {
+ Self::ERROR_USIZE => Self::ERROR,
+ Self::WARN_USIZE => Self::WARN,
+ Self::INFO_USIZE => Self::INFO,
+ Self::DEBUG_USIZE => Self::DEBUG,
+ Self::TRACE_USIZE => Self::TRACE,
+ Self::OFF_USIZE => Self::OFF,
+ #[cfg(debug_assertions)]
+ unknown => unreachable!(
+ "/!\\ `LevelFilter` representation seems to have changed! /!\\ \n\
+ This is a bug (and it's pretty bad). Please contact the `tracing` \
+ maintainers. Thank you and I'm sorry.\n \
+ The offending repr was: {:?}",
+ unknown,
+ ),
+ #[cfg(not(debug_assertions))]
+ _ => unsafe {
+ // Using `unreachable_unchecked` here (rather than
+ // `unreachable!()`) is necessary to ensure that rustc generates
+ // an identity conversion from integer -> discriminant, rather
+ // than generating a lookup table. We want to ensure this
+ // function is a single `mov` instruction (on x86) if at all
+ // possible, because it is called *every* time a span/event
+ // callsite is hit; and it is (potentially) the only code in the
+ // hottest path for skipping a majority of callsites when level
+ // filtering is in use.
+ //
+ // safety: This branch is only truly unreachable if we guarantee
+ // that no values other than the possible enum discriminants
+ // will *ever* be present. The `AtomicUsize` is initialized to
+ // the `OFF` value. It is only set by the `set_max` function,
+ // which takes a `LevelFilter` as a parameter. This restricts
+ // the inputs to `set_max` to the set of valid discriminants.
+ // Therefore, **as long as `MAX_VALUE` is only ever set by
+ // `set_max`**, this is safe.
+ crate::stdlib::hint::unreachable_unchecked()
+ },
+ }
+ }
+
+ pub(crate) fn set_max(LevelFilter(level): LevelFilter) {
+ let val = match level {
+ Some(Level(level)) => level as usize,
+ None => Self::OFF_USIZE,
+ };
+
+ // using an AcqRel swap ensures an ordered relationship of writes to the
+ // max level.
+ MAX_LEVEL.swap(val, Ordering::AcqRel);
+ }
+}
+
+impl fmt::Display for LevelFilter {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ LevelFilter::OFF => f.pad("off"),
+ LevelFilter::ERROR => f.pad("error"),
+ LevelFilter::WARN => f.pad("warn"),
+ LevelFilter::INFO => f.pad("info"),
+ LevelFilter::DEBUG => f.pad("debug"),
+ LevelFilter::TRACE => f.pad("trace"),
+ }
+ }
+}
+
+impl fmt::Debug for LevelFilter {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ LevelFilter::OFF => f.pad("LevelFilter::OFF"),
+ LevelFilter::ERROR => f.pad("LevelFilter::ERROR"),
+ LevelFilter::WARN => f.pad("LevelFilter::WARN"),
+ LevelFilter::INFO => f.pad("LevelFilter::INFO"),
+ LevelFilter::DEBUG => f.pad("LevelFilter::DEBUG"),
+ LevelFilter::TRACE => f.pad("LevelFilter::TRACE"),
+ }
+ }
+}
+
+impl FromStr for LevelFilter {
+ type Err = ParseLevelFilterError;
+ fn from_str(from: &str) -> Result<Self, Self::Err> {
+ from.parse::<usize>()
+ .ok()
+ .and_then(|num| match num {
+ 0 => Some(LevelFilter::OFF),
+ 1 => Some(LevelFilter::ERROR),
+ 2 => Some(LevelFilter::WARN),
+ 3 => Some(LevelFilter::INFO),
+ 4 => Some(LevelFilter::DEBUG),
+ 5 => Some(LevelFilter::TRACE),
+ _ => None,
+ })
+ .or_else(|| match from {
+ "" => Some(LevelFilter::ERROR),
+ s if s.eq_ignore_ascii_case("error") => Some(LevelFilter::ERROR),
+ s if s.eq_ignore_ascii_case("warn") => Some(LevelFilter::WARN),
+ s if s.eq_ignore_ascii_case("info") => Some(LevelFilter::INFO),
+ s if s.eq_ignore_ascii_case("debug") => Some(LevelFilter::DEBUG),
+ s if s.eq_ignore_ascii_case("trace") => Some(LevelFilter::TRACE),
+ s if s.eq_ignore_ascii_case("off") => Some(LevelFilter::OFF),
+ _ => None,
+ })
+ .ok_or(ParseLevelFilterError(()))
+ }
+}
+
+/// Returned if parsing a `Level` fails.
+#[derive(Debug)]
+pub struct ParseLevelError {
+ _p: (),
+}
+
+impl fmt::Display for ParseLevelError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad(
+ "error parsing level: expected one of \"error\", \"warn\", \
+ \"info\", \"debug\", \"trace\", or a number 1-5",
+ )
+ }
+}
+
+impl fmt::Display for ParseLevelFilterError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad(
+ "error parsing level filter: expected one of \"off\", \"error\", \
+ \"warn\", \"info\", \"debug\", \"trace\", or a number 0-5",
+ )
+ }
+}
+
+#[cfg(feature = "std")]
+impl std::error::Error for ParseLevelFilterError {}
+
+// ==== Level and LevelFilter comparisons ====
+
+// /!\ BIG, IMPORTANT WARNING /!\
+// Do NOT mess with these implementations! They are hand-written for a reason!
+//
+// Since comparing `Level`s and `LevelFilter`s happens in a *very* hot path
+// (potentially, every time a span or event macro is hit, regardless of whether
+// or not is enabled), we *need* to ensure that these comparisons are as fast as
+// possible. Therefore, we have some requirements:
+//
+// 1. We want to do our best to ensure that rustc will generate integer-integer
+// comparisons wherever possible.
+//
+// The derived `Ord`/`PartialOrd` impls for `LevelFilter` will not do this,
+// because `LevelFilter`s are represented by `Option<Level>`, rather than as
+// a separate `#[repr(usize)]` enum. This was (unfortunately) necessary for
+// backwards-compatibility reasons, as the `tracing` crate's original
+// version of `LevelFilter` defined `const fn` conversions between `Level`s
+// and `LevelFilter`, so we're stuck with the `Option<Level>` repr.
+// Therefore, we need hand-written `PartialOrd` impls that cast both sides of
+// the comparison to `usize`s, to force the compiler to generate integer
+// compares.
+//
+// 2. The hottest `Level`/`LevelFilter` comparison, the one that happens every
+// time a callsite is hit, occurs *within the `tracing` crate's macros*.
+// This means that the comparison is happening *inside* a crate that
+// *depends* on `tracing-core`, not in `tracing-core` itself. The compiler
+// will only inline function calls across crate boundaries if the called
+// function is annotated with an `#[inline]` attribute, and we *definitely*
+// want the comparison functions to be inlined: as previously mentioned, they
+// should compile down to a single integer comparison on release builds, and
+// it seems really sad to push an entire stack frame to call a function
+// consisting of one `cmp` instruction!
+//
+// Therefore, we need to ensure that all the comparison methods have
+// `#[inline]` or `#[inline(always)]` attributes. It's not sufficient to just
+// add the attribute to `partial_cmp` in a manual implementation of the
+// trait, since it's the comparison operators (`lt`, `le`, `gt`, and `ge`)
+// that will actually be *used*, and the default implementation of *those*
+// methods, which calls `partial_cmp`, does not have an inline annotation.
+//
+// 3. We need the comparisons to be inverted. The discriminants for the
+// `LevelInner` enum are assigned in "backwards" order, with `TRACE` having
+// the *lowest* value. However, we want `TRACE` to compare greater-than all
+// other levels.
+//
+// Why are the numeric values inverted? In order to ensure that `LevelFilter`
+// (which, as previously mentioned, *has* to be internally represented by an
+// `Option<Level>`) compiles down to a single integer value. This is
+// necessary for storing the global max in an `AtomicUsize`, and for ensuring
+// that we use fast integer-integer comparisons, as mentioned previously. In
+// order to ensure this, we exploit the niche optimization. The niche
+// optimization for `Option<{enum with a numeric repr}>` will choose
+// `(HIGHEST_DISCRIMINANT_VALUE + 1)` as the representation for `None`.
+// Therefore, the integer representation of `LevelFilter::OFF` (which is
+// `None`) will be the number 5. `OFF` must compare higher than every other
+// level in order for it to filter as expected. Since we want to use a single
+// `cmp` instruction, we can't special-case the integer value of `OFF` to
+// compare higher, as that will generate more code. Instead, we need it to be
+// on one end of the enum, with `ERROR` on the opposite end, so we assign the
+// value 0 to `ERROR`.
+//
+// This *does* mean that when parsing `LevelFilter`s or `Level`s from
+// `String`s, the integer values are inverted, but that doesn't happen in a
+// hot path.
+//
+// Note that we manually invert the comparisons by swapping the left-hand and
+// right-hand side. Using `Ordering::reverse` generates significantly worse
+// code (per Matt Godbolt's Compiler Explorer).
+//
+// Anyway, that's a brief history of why this code is the way it is. Don't
+// change it unless you know what you're doing.
+
+impl PartialEq<LevelFilter> for Level {
+ #[inline(always)]
+ fn eq(&self, other: &LevelFilter) -> bool {
+ self.0 as usize == filter_as_usize(&other.0)
+ }
+}
+
+impl PartialOrd for Level {
+ #[inline(always)]
+ fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+
+ #[inline(always)]
+ fn lt(&self, other: &Level) -> bool {
+ (other.0 as usize) < (self.0 as usize)
+ }
+
+ #[inline(always)]
+ fn le(&self, other: &Level) -> bool {
+ (other.0 as usize) <= (self.0 as usize)
+ }
+
+ #[inline(always)]
+ fn gt(&self, other: &Level) -> bool {
+ (other.0 as usize) > (self.0 as usize)
+ }
+
+ #[inline(always)]
+ fn ge(&self, other: &Level) -> bool {
+ (other.0 as usize) >= (self.0 as usize)
+ }
+}
+
+impl Ord for Level {
+ #[inline(always)]
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ (other.0 as usize).cmp(&(self.0 as usize))
+ }
+}
+
+impl PartialOrd<LevelFilter> for Level {
+ #[inline(always)]
+ fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
+ Some(filter_as_usize(&other.0).cmp(&(self.0 as usize)))
+ }
+
+ #[inline(always)]
+ fn lt(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) < (self.0 as usize)
+ }
+
+ #[inline(always)]
+ fn le(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) <= (self.0 as usize)
+ }
+
+ #[inline(always)]
+ fn gt(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) > (self.0 as usize)
+ }
+
+ #[inline(always)]
+ fn ge(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) >= (self.0 as usize)
+ }
+}
+
+#[inline(always)]
+fn filter_as_usize(x: &Option<Level>) -> usize {
+ match x {
+ Some(Level(f)) => *f as usize,
+ None => LevelFilter::OFF_USIZE,
+ }
+}
+
+impl PartialEq<Level> for LevelFilter {
+ #[inline(always)]
+ fn eq(&self, other: &Level) -> bool {
+ filter_as_usize(&self.0) == other.0 as usize
+ }
+}
+
+impl PartialOrd for LevelFilter {
+ #[inline(always)]
+ fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+
+ #[inline(always)]
+ fn lt(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) < filter_as_usize(&self.0)
+ }
+
+ #[inline(always)]
+ fn le(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) <= filter_as_usize(&self.0)
+ }
+
+ #[inline(always)]
+ fn gt(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) > filter_as_usize(&self.0)
+ }
+
+ #[inline(always)]
+ fn ge(&self, other: &LevelFilter) -> bool {
+ filter_as_usize(&other.0) >= filter_as_usize(&self.0)
+ }
+}
+
+impl Ord for LevelFilter {
+ #[inline(always)]
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ filter_as_usize(&other.0).cmp(&filter_as_usize(&self.0))
+ }
+}
+
+impl PartialOrd<Level> for LevelFilter {
+ #[inline(always)]
+ fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
+ Some((other.0 as usize).cmp(&filter_as_usize(&self.0)))
+ }
+
+ #[inline(always)]
+ fn lt(&self, other: &Level) -> bool {
+ (other.0 as usize) < filter_as_usize(&self.0)
+ }
+
+ #[inline(always)]
+ fn le(&self, other: &Level) -> bool {
+ (other.0 as usize) <= filter_as_usize(&self.0)
+ }
+
+ #[inline(always)]
+ fn gt(&self, other: &Level) -> bool {
+ (other.0 as usize) > filter_as_usize(&self.0)
+ }
+
+ #[inline(always)]
+ fn ge(&self, other: &Level) -> bool {
+ (other.0 as usize) >= filter_as_usize(&self.0)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::stdlib::mem;
+
+ #[test]
+ fn level_from_str() {
+ assert_eq!("error".parse::<Level>().unwrap(), Level::ERROR);
+ assert_eq!("4".parse::<Level>().unwrap(), Level::DEBUG);
+ assert!("0".parse::<Level>().is_err())
+ }
+
+ #[test]
+ fn filter_level_conversion() {
+ let mapping = [
+ (LevelFilter::OFF, None),
+ (LevelFilter::ERROR, Some(Level::ERROR)),
+ (LevelFilter::WARN, Some(Level::WARN)),
+ (LevelFilter::INFO, Some(Level::INFO)),
+ (LevelFilter::DEBUG, Some(Level::DEBUG)),
+ (LevelFilter::TRACE, Some(Level::TRACE)),
+ ];
+ for (filter, level) in mapping.iter() {
+ assert_eq!(filter.into_level(), *level);
+ match level {
+ Some(level) => {
+ let actual: LevelFilter = (*level).into();
+ assert_eq!(actual, *filter);
+ }
+ None => {
+ let actual: LevelFilter = None.into();
+ assert_eq!(actual, *filter);
+ }
+ }
+ }
+ }
+
+ #[test]
+ fn level_filter_is_usize_sized() {
+ assert_eq!(
+ mem::size_of::<LevelFilter>(),
+ mem::size_of::<usize>(),
+ "`LevelFilter` is no longer `usize`-sized! global MAX_LEVEL may now be invalid!"
+ )
+ }
+
+ #[test]
+ fn level_filter_reprs() {
+ let mapping = [
+ (LevelFilter::OFF, LevelInner::Error as usize + 1),
+ (LevelFilter::ERROR, LevelInner::Error as usize),
+ (LevelFilter::WARN, LevelInner::Warn as usize),
+ (LevelFilter::INFO, LevelInner::Info as usize),
+ (LevelFilter::DEBUG, LevelInner::Debug as usize),
+ (LevelFilter::TRACE, LevelInner::Trace as usize),
+ ];
+ for &(filter, expected) in &mapping {
+ let repr = unsafe {
+ // safety: The entire purpose of this test is to assert that the
+ // actual repr matches what we expect it to be --- we're testing
+ // that *other* unsafe code is sound using the transmuted value.
+ // We're not going to do anything with it that might be unsound.
+ mem::transmute::<LevelFilter, usize>(filter)
+ };
+ assert_eq!(expected, repr, "repr changed for {:?}", filter)
+ }
+ }
+}
diff --git a/third_party/rust/tracing-core/src/parent.rs b/third_party/rust/tracing-core/src/parent.rs
new file mode 100644
index 0000000000..cb34b376cc
--- /dev/null
+++ b/third_party/rust/tracing-core/src/parent.rs
@@ -0,0 +1,11 @@
+use crate::span::Id;
+
+#[derive(Debug)]
+pub(crate) enum Parent {
+ /// The new span will be a root span.
+ Root,
+ /// The new span will be rooted in the current span.
+ Current,
+ /// The new span has an explicitly-specified parent.
+ Explicit(Id),
+}
diff --git a/third_party/rust/tracing-core/src/span.rs b/third_party/rust/tracing-core/src/span.rs
new file mode 100644
index 0000000000..44738b2903
--- /dev/null
+++ b/third_party/rust/tracing-core/src/span.rs
@@ -0,0 +1,341 @@
+//! Spans represent periods of time in the execution of a program.
+use crate::field::FieldSet;
+use crate::parent::Parent;
+use crate::stdlib::num::NonZeroU64;
+use crate::{field, Metadata};
+
+/// Identifies a span within the context of a subscriber.
+///
+/// They are generated by [`Subscriber`]s for each span as it is created, by
+/// the [`new_span`] trait method. See the documentation for that method for
+/// more information on span ID generation.
+///
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [`new_span`]: super::subscriber::Subscriber::new_span
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct Id(NonZeroU64);
+
+/// Attributes provided to a `Subscriber` describing a new span when it is
+/// created.
+#[derive(Debug)]
+pub struct Attributes<'a> {
+ metadata: &'static Metadata<'static>,
+ values: &'a field::ValueSet<'a>,
+ parent: Parent,
+}
+
+/// A set of fields recorded by a span.
+#[derive(Debug)]
+pub struct Record<'a> {
+ values: &'a field::ValueSet<'a>,
+}
+
+/// Indicates what [the `Subscriber` considers] the "current" span.
+///
+/// As subscribers may not track a notion of a current span, this has three
+/// possible states:
+/// - "unknown", indicating that the subscriber does not track a current span,
+/// - "none", indicating that the current context is known to not be in a span,
+/// - "some", with the current span's [`Id`] and [`Metadata`].
+///
+/// [the `Subscriber` considers]: super::subscriber::Subscriber::current_span
+/// [`Metadata`]: super::metadata::Metadata
+#[derive(Debug)]
+pub struct Current {
+ inner: CurrentInner,
+}
+
+#[derive(Debug)]
+enum CurrentInner {
+ Current {
+ id: Id,
+ metadata: &'static Metadata<'static>,
+ },
+ None,
+ Unknown,
+}
+
+// ===== impl Span =====
+
+impl Id {
+ /// Constructs a new span ID from the given `u64`.
+ ///
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ /// <strong>Note</strong>: Span IDs must be greater than zero.
+ /// </pre>
+ ///
+ /// # Panics
+ /// - If the provided `u64` is 0.
+ pub fn from_u64(u: u64) -> Self {
+ Id(NonZeroU64::new(u).expect("span IDs must be > 0"))
+ }
+
+ /// Constructs a new span ID from the given `NonZeroU64`.
+ ///
+ /// Unlike [`Id::from_u64`](Id::from_u64()), this will never panic.
+ #[inline]
+ pub const fn from_non_zero_u64(id: NonZeroU64) -> Self {
+ Id(id)
+ }
+
+ // Allow `into` by-ref since we don't want to impl Copy for Id
+ #[allow(clippy::wrong_self_convention)]
+ /// Returns the span's ID as a `u64`.
+ pub fn into_u64(&self) -> u64 {
+ self.0.get()
+ }
+
+ // Allow `into` by-ref since we don't want to impl Copy for Id
+ #[allow(clippy::wrong_self_convention)]
+ /// Returns the span's ID as a `NonZeroU64`.
+ #[inline]
+ pub const fn into_non_zero_u64(&self) -> NonZeroU64 {
+ self.0
+ }
+}
+
+impl<'a> From<&'a Id> for Option<Id> {
+ fn from(id: &'a Id) -> Self {
+ Some(id.clone())
+ }
+}
+
+// ===== impl Attributes =====
+
+impl<'a> Attributes<'a> {
+ /// Returns `Attributes` describing a new child span of the current span,
+ /// with the provided metadata and values.
+ pub fn new(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self {
+ Attributes {
+ metadata,
+ values,
+ parent: Parent::Current,
+ }
+ }
+
+ /// Returns `Attributes` describing a new span at the root of its own trace
+ /// tree, with the provided metadata and values.
+ pub fn new_root(metadata: &'static Metadata<'static>, values: &'a field::ValueSet<'a>) -> Self {
+ Attributes {
+ metadata,
+ values,
+ parent: Parent::Root,
+ }
+ }
+
+ /// Returns `Attributes` describing a new child span of the specified
+ /// parent span, with the provided metadata and values.
+ pub fn child_of(
+ parent: Id,
+ metadata: &'static Metadata<'static>,
+ values: &'a field::ValueSet<'a>,
+ ) -> Self {
+ Attributes {
+ metadata,
+ values,
+ parent: Parent::Explicit(parent),
+ }
+ }
+
+ /// Returns a reference to the new span's metadata.
+ pub fn metadata(&self) -> &'static Metadata<'static> {
+ self.metadata
+ }
+
+ /// Returns a reference to a `ValueSet` containing any values the new span
+ /// was created with.
+ pub fn values(&self) -> &field::ValueSet<'a> {
+ self.values
+ }
+
+ /// Returns true if the new span should be a root.
+ pub fn is_root(&self) -> bool {
+ matches!(self.parent, Parent::Root)
+ }
+
+ /// Returns true if the new span's parent should be determined based on the
+ /// current context.
+ ///
+ /// If this is true and the current thread is currently inside a span, then
+ /// that span should be the new span's parent. Otherwise, if the current
+ /// thread is _not_ inside a span, then the new span will be the root of its
+ /// own trace tree.
+ pub fn is_contextual(&self) -> bool {
+ matches!(self.parent, Parent::Current)
+ }
+
+ /// Returns the new span's explicitly-specified parent, if there is one.
+ ///
+ /// Otherwise (if the new span is a root or is a child of the current span),
+ /// returns `None`.
+ pub fn parent(&self) -> Option<&Id> {
+ match self.parent {
+ Parent::Explicit(ref p) => Some(p),
+ _ => None,
+ }
+ }
+
+ /// Records all the fields in this set of `Attributes` with the provided
+ /// [Visitor].
+ ///
+ /// [visitor]: super::field::Visit
+ pub fn record(&self, visitor: &mut dyn field::Visit) {
+ self.values.record(visitor)
+ }
+
+ /// Returns `true` if this set of `Attributes` contains a value for the
+ /// given `Field`.
+ pub fn contains(&self, field: &field::Field) -> bool {
+ self.values.contains(field)
+ }
+
+ /// Returns true if this set of `Attributes` contains _no_ values.
+ pub fn is_empty(&self) -> bool {
+ self.values.is_empty()
+ }
+
+ /// Returns the set of all [fields] defined by this span's [`Metadata`].
+ ///
+ /// Note that the [`FieldSet`] returned by this method includes *all* the
+ /// fields declared by this span, not just those with values that are recorded
+ /// as part of this set of `Attributes`. Other fields with values not present in
+ /// this `Attributes`' value set may [record] values later.
+ ///
+ /// [fields]: crate::field
+ /// [record]: Attributes::record()
+ /// [`Metadata`]: crate::metadata::Metadata
+ /// [`FieldSet`]: crate::field::FieldSet
+ pub fn fields(&self) -> &FieldSet {
+ self.values.field_set()
+ }
+}
+
+// ===== impl Record =====
+
+impl<'a> Record<'a> {
+ /// Constructs a new `Record` from a `ValueSet`.
+ pub fn new(values: &'a field::ValueSet<'a>) -> Self {
+ Self { values }
+ }
+
+ /// Records all the fields in this `Record` with the provided [Visitor].
+ ///
+ /// [visitor]: super::field::Visit
+ pub fn record(&self, visitor: &mut dyn field::Visit) {
+ self.values.record(visitor)
+ }
+
+ /// Returns the number of fields that would be visited from this `Record`
+ /// when [`Record::record()`] is called
+ ///
+ /// [`Record::record()`]: Record::record()
+ pub fn len(&self) -> usize {
+ self.values.len()
+ }
+
+ /// Returns `true` if this `Record` contains a value for the given `Field`.
+ pub fn contains(&self, field: &field::Field) -> bool {
+ self.values.contains(field)
+ }
+
+ /// Returns true if this `Record` contains _no_ values.
+ pub fn is_empty(&self) -> bool {
+ self.values.is_empty()
+ }
+}
+
+// ===== impl Current =====
+
+impl Current {
+ /// Constructs a new `Current` that indicates the current context is a span
+ /// with the given `metadata` and `metadata`.
+ pub fn new(id: Id, metadata: &'static Metadata<'static>) -> Self {
+ Self {
+ inner: CurrentInner::Current { id, metadata },
+ }
+ }
+
+ /// Constructs a new `Current` that indicates the current context is *not*
+ /// in a span.
+ pub fn none() -> Self {
+ Self {
+ inner: CurrentInner::None,
+ }
+ }
+
+ /// Constructs a new `Current` that indicates the `Subscriber` does not
+ /// track a current span.
+ pub(crate) fn unknown() -> Self {
+ Self {
+ inner: CurrentInner::Unknown,
+ }
+ }
+
+ /// Returns `true` if the `Subscriber` that constructed this `Current` tracks a
+ /// current span.
+ ///
+ /// If this returns `true` and [`id`], [`metadata`], or [`into_inner`]
+ /// return `None`, that indicates that we are currently known to *not* be
+ /// inside a span. If this returns `false`, those methods will also return
+ /// `None`, but in this case, that is because the subscriber does not keep
+ /// track of the currently-entered span.
+ ///
+ /// [`id`]: Current::id()
+ /// [`metadata`]: Current::metadata()
+ /// [`into_inner`]: Current::into_inner()
+ pub fn is_known(&self) -> bool {
+ !matches!(self.inner, CurrentInner::Unknown)
+ }
+
+ /// Consumes `self` and returns the span `Id` and `Metadata` of the current
+ /// span, if one exists and is known.
+ pub fn into_inner(self) -> Option<(Id, &'static Metadata<'static>)> {
+ match self.inner {
+ CurrentInner::Current { id, metadata } => Some((id, metadata)),
+ _ => None,
+ }
+ }
+
+ /// Borrows the `Id` of the current span, if one exists and is known.
+ pub fn id(&self) -> Option<&Id> {
+ match self.inner {
+ CurrentInner::Current { ref id, .. } => Some(id),
+ _ => None,
+ }
+ }
+
+ /// Borrows the `Metadata` of the current span, if one exists and is known.
+ pub fn metadata(&self) -> Option<&'static Metadata<'static>> {
+ match self.inner {
+ CurrentInner::Current { metadata, .. } => Some(metadata),
+ _ => None,
+ }
+ }
+}
+
+impl<'a> From<&'a Current> for Option<&'a Id> {
+ fn from(cur: &'a Current) -> Self {
+ cur.id()
+ }
+}
+
+impl<'a> From<&'a Current> for Option<Id> {
+ fn from(cur: &'a Current) -> Self {
+ cur.id().cloned()
+ }
+}
+
+impl From<Current> for Option<Id> {
+ fn from(cur: Current) -> Self {
+ match cur.inner {
+ CurrentInner::Current { id, .. } => Some(id),
+ _ => None,
+ }
+ }
+}
+
+impl<'a> From<&'a Current> for Option<&'static Metadata<'static>> {
+ fn from(cur: &'a Current) -> Self {
+ cur.metadata()
+ }
+}
diff --git a/third_party/rust/tracing-core/src/spin/LICENSE b/third_party/rust/tracing-core/src/spin/LICENSE
new file mode 100644
index 0000000000..84d5f4d7af
--- /dev/null
+++ b/third_party/rust/tracing-core/src/spin/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Mathijs van de Nes
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/third_party/rust/tracing-core/src/spin/mod.rs b/third_party/rust/tracing-core/src/spin/mod.rs
new file mode 100644
index 0000000000..148b192b34
--- /dev/null
+++ b/third_party/rust/tracing-core/src/spin/mod.rs
@@ -0,0 +1,7 @@
+//! Synchronization primitives based on spinning
+
+pub(crate) use mutex::*;
+pub(crate) use once::Once;
+
+mod mutex;
+mod once;
diff --git a/third_party/rust/tracing-core/src/spin/mutex.rs b/third_party/rust/tracing-core/src/spin/mutex.rs
new file mode 100644
index 0000000000..c261a61910
--- /dev/null
+++ b/third_party/rust/tracing-core/src/spin/mutex.rs
@@ -0,0 +1,118 @@
+use core::cell::UnsafeCell;
+use core::default::Default;
+use core::fmt;
+use core::hint;
+use core::marker::Sync;
+use core::ops::{Deref, DerefMut, Drop};
+use core::option::Option::{self, None, Some};
+use core::sync::atomic::{AtomicBool, Ordering};
+
+/// This type provides MUTual EXclusion based on spinning.
+pub(crate) struct Mutex<T: ?Sized> {
+ lock: AtomicBool,
+ data: UnsafeCell<T>,
+}
+
+/// A guard to which the protected data can be accessed
+///
+/// When the guard falls out of scope it will release the lock.
+#[derive(Debug)]
+pub(crate) struct MutexGuard<'a, T: ?Sized> {
+ lock: &'a AtomicBool,
+ data: &'a mut T,
+}
+
+// Same unsafe impls as `std::sync::Mutex`
+unsafe impl<T: ?Sized + Send> Sync for Mutex<T> {}
+unsafe impl<T: ?Sized + Send> Send for Mutex<T> {}
+
+impl<T> Mutex<T> {
+ /// Creates a new spinlock wrapping the supplied data.
+ pub(crate) const fn new(user_data: T) -> Mutex<T> {
+ Mutex {
+ lock: AtomicBool::new(false),
+ data: UnsafeCell::new(user_data),
+ }
+ }
+}
+
+impl<T: ?Sized> Mutex<T> {
+ fn obtain_lock(&self) {
+ while self
+ .lock
+ .compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed)
+ .is_err()
+ {
+ // Wait until the lock looks unlocked before retrying
+ while self.lock.load(Ordering::Relaxed) {
+ hint::spin_loop();
+ }
+ }
+ }
+
+ /// Locks the spinlock and returns a guard.
+ ///
+ /// The returned value may be dereferenced for data access
+ /// and the lock will be dropped when the guard falls out of scope.
+ pub(crate) fn lock(&self) -> MutexGuard<'_, T> {
+ self.obtain_lock();
+ MutexGuard {
+ lock: &self.lock,
+ data: unsafe { &mut *self.data.get() },
+ }
+ }
+
+ /// Tries to lock the mutex. If it is already locked, it will return None. Otherwise it returns
+ /// a guard within Some.
+ pub(crate) fn try_lock(&self) -> Option<MutexGuard<'_, T>> {
+ if self
+ .lock
+ .compare_exchange(false, true, Ordering::Acquire, Ordering::Relaxed)
+ .is_ok()
+ {
+ Some(MutexGuard {
+ lock: &self.lock,
+ data: unsafe { &mut *self.data.get() },
+ })
+ } else {
+ None
+ }
+ }
+}
+
+impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.try_lock() {
+ Some(guard) => write!(f, "Mutex {{ data: ")
+ .and_then(|()| (&*guard).fmt(f))
+ .and_then(|()| write!(f, "}}")),
+ None => write!(f, "Mutex {{ <locked> }}"),
+ }
+ }
+}
+
+impl<T: ?Sized + Default> Default for Mutex<T> {
+ fn default() -> Mutex<T> {
+ Mutex::new(Default::default())
+ }
+}
+
+impl<'a, T: ?Sized> Deref for MutexGuard<'a, T> {
+ type Target = T;
+ fn deref<'b>(&'b self) -> &'b T {
+ &*self.data
+ }
+}
+
+impl<'a, T: ?Sized> DerefMut for MutexGuard<'a, T> {
+ fn deref_mut<'b>(&'b mut self) -> &'b mut T {
+ &mut *self.data
+ }
+}
+
+impl<'a, T: ?Sized> Drop for MutexGuard<'a, T> {
+ /// The dropping of the MutexGuard will release the lock it was created from.
+ fn drop(&mut self) {
+ self.lock.store(false, Ordering::Release);
+ }
+}
diff --git a/third_party/rust/tracing-core/src/spin/once.rs b/third_party/rust/tracing-core/src/spin/once.rs
new file mode 100644
index 0000000000..27c99e56ee
--- /dev/null
+++ b/third_party/rust/tracing-core/src/spin/once.rs
@@ -0,0 +1,158 @@
+use core::cell::UnsafeCell;
+use core::fmt;
+use core::hint::spin_loop;
+use core::sync::atomic::{AtomicUsize, Ordering};
+
+/// A synchronization primitive which can be used to run a one-time global
+/// initialization. Unlike its std equivalent, this is generalized so that the
+/// closure returns a value and it is stored. Once therefore acts something like
+/// a future, too.
+pub struct Once<T> {
+ state: AtomicUsize,
+ data: UnsafeCell<Option<T>>, // TODO remove option and use mem::uninitialized
+}
+
+impl<T: fmt::Debug> fmt::Debug for Once<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self.r#try() {
+ Some(s) => write!(f, "Once {{ data: ")
+ .and_then(|()| s.fmt(f))
+ .and_then(|()| write!(f, "}}")),
+ None => write!(f, "Once {{ <uninitialized> }}"),
+ }
+ }
+}
+
+// Same unsafe impls as `std::sync::RwLock`, because this also allows for
+// concurrent reads.
+unsafe impl<T: Send + Sync> Sync for Once<T> {}
+unsafe impl<T: Send> Send for Once<T> {}
+
+// Four states that a Once can be in, encoded into the lower bits of `state` in
+// the Once structure.
+const INCOMPLETE: usize = 0x0;
+const RUNNING: usize = 0x1;
+const COMPLETE: usize = 0x2;
+const PANICKED: usize = 0x3;
+
+use core::hint::unreachable_unchecked as unreachable;
+
+impl<T> Once<T> {
+ /// Initialization constant of `Once`.
+ pub const INIT: Self = Once {
+ state: AtomicUsize::new(INCOMPLETE),
+ data: UnsafeCell::new(None),
+ };
+
+ /// Creates a new `Once` value.
+ pub const fn new() -> Once<T> {
+ Self::INIT
+ }
+
+ fn force_get<'a>(&'a self) -> &'a T {
+ match unsafe { &*self.data.get() }.as_ref() {
+ None => unsafe { unreachable() },
+ Some(p) => p,
+ }
+ }
+
+ /// Performs an initialization routine once and only once. The given closure
+ /// will be executed if this is the first time `call_once` has been called,
+ /// and otherwise the routine will *not* be invoked.
+ ///
+ /// This method will block the calling thread if another initialization
+ /// routine is currently running.
+ ///
+ /// When this function returns, it is guaranteed that some initialization
+ /// has run and completed (it may not be the closure specified). The
+ /// returned pointer will point to the result from the closure that was
+ /// run.
+ pub fn call_once<'a, F>(&'a self, builder: F) -> &'a T
+ where
+ F: FnOnce() -> T,
+ {
+ let mut status = self.state.load(Ordering::SeqCst);
+
+ if status == INCOMPLETE {
+ status = match self.state.compare_exchange(
+ INCOMPLETE,
+ RUNNING,
+ Ordering::SeqCst,
+ Ordering::SeqCst,
+ ) {
+ Ok(status) => {
+ debug_assert_eq!(
+ status, INCOMPLETE,
+ "if compare_exchange succeeded, previous status must be incomplete",
+ );
+ // We init
+ // We use a guard (Finish) to catch panics caused by builder
+ let mut finish = Finish {
+ state: &self.state,
+ panicked: true,
+ };
+ unsafe { *self.data.get() = Some(builder()) };
+ finish.panicked = false;
+
+ self.state.store(COMPLETE, Ordering::SeqCst);
+
+ // This next line is strictly an optimization
+ return self.force_get();
+ }
+ Err(status) => status,
+ }
+ }
+
+ loop {
+ match status {
+ INCOMPLETE => unreachable!(),
+ RUNNING => {
+ // We spin
+ spin_loop();
+ status = self.state.load(Ordering::SeqCst)
+ }
+ PANICKED => panic!("Once has panicked"),
+ COMPLETE => return self.force_get(),
+ _ => unsafe { unreachable() },
+ }
+ }
+ }
+
+ /// Returns a pointer iff the `Once` was previously initialized
+ pub fn r#try<'a>(&'a self) -> Option<&'a T> {
+ match self.state.load(Ordering::SeqCst) {
+ COMPLETE => Some(self.force_get()),
+ _ => None,
+ }
+ }
+
+ /// Like try, but will spin if the `Once` is in the process of being
+ /// initialized
+ pub fn wait<'a>(&'a self) -> Option<&'a T> {
+ loop {
+ match self.state.load(Ordering::SeqCst) {
+ INCOMPLETE => return None,
+
+ RUNNING => {
+ spin_loop() // We spin
+ }
+ COMPLETE => return Some(self.force_get()),
+ PANICKED => panic!("Once has panicked"),
+ _ => unsafe { unreachable() },
+ }
+ }
+ }
+}
+
+struct Finish<'a> {
+ state: &'a AtomicUsize,
+ panicked: bool,
+}
+
+impl<'a> Drop for Finish<'a> {
+ fn drop(&mut self) {
+ if self.panicked {
+ self.state.store(PANICKED, Ordering::SeqCst);
+ }
+ }
+}
diff --git a/third_party/rust/tracing-core/src/stdlib.rs b/third_party/rust/tracing-core/src/stdlib.rs
new file mode 100644
index 0000000000..741549519c
--- /dev/null
+++ b/third_party/rust/tracing-core/src/stdlib.rs
@@ -0,0 +1,78 @@
+//! Re-exports either the Rust `std` library or `core` and `alloc` when `std` is
+//! disabled.
+//!
+//! `crate::stdlib::...` should be used rather than `std::` when adding code that
+//! will be available with the standard library disabled.
+//!
+//! Note that this module is called `stdlib` rather than `std`, as Rust 1.34.0
+//! does not permit redefining the name `stdlib` (although this works on the
+//! latest stable Rust).
+#[cfg(feature = "std")]
+pub(crate) use std::*;
+
+#[cfg(not(feature = "std"))]
+pub(crate) use self::no_std::*;
+
+#[cfg(not(feature = "std"))]
+mod no_std {
+ // We pre-emptively export everything from libcore/liballoc, (even modules
+ // we aren't using currently) to make adding new code easier. Therefore,
+ // some of these imports will be unused.
+ #![allow(unused_imports)]
+
+ pub(crate) use core::{
+ any, array, ascii, cell, char, clone, cmp, convert, default, f32, f64, ffi, future, hash,
+ hint, i128, i16, i8, isize, iter, marker, mem, num, ops, option, pin, ptr, result, task,
+ time, u128, u16, u32, u8, usize,
+ };
+
+ pub(crate) use alloc::{boxed, collections, rc, string, vec};
+
+ pub(crate) mod borrow {
+ pub(crate) use alloc::borrow::*;
+ pub(crate) use core::borrow::*;
+ }
+
+ pub(crate) mod fmt {
+ pub(crate) use alloc::fmt::*;
+ pub(crate) use core::fmt::*;
+ }
+
+ pub(crate) mod slice {
+ pub(crate) use alloc::slice::*;
+ pub(crate) use core::slice::*;
+ }
+
+ pub(crate) mod str {
+ pub(crate) use alloc::str::*;
+ pub(crate) use core::str::*;
+ }
+
+ pub(crate) mod sync {
+ pub(crate) use crate::spin::MutexGuard;
+ pub(crate) use alloc::sync::*;
+ pub(crate) use core::sync::*;
+
+ /// This wraps `spin::Mutex` to return a `Result`, so that it can be
+ /// used with code written against `std::sync::Mutex`.
+ ///
+ /// Since `spin::Mutex` doesn't support poisoning, the `Result` returned
+ /// by `lock` will always be `Ok`.
+ #[derive(Debug, Default)]
+ pub(crate) struct Mutex<T> {
+ inner: crate::spin::Mutex<T>,
+ }
+
+ impl<T> Mutex<T> {
+ // pub(crate) fn new(data: T) -> Self {
+ // Self {
+ // inner: crate::spin::Mutex::new(data),
+ // }
+ // }
+
+ pub(crate) fn lock(&self) -> Result<MutexGuard<'_, T>, ()> {
+ Ok(self.inner.lock())
+ }
+ }
+ }
+}
diff --git a/third_party/rust/tracing-core/src/subscriber.rs b/third_party/rust/tracing-core/src/subscriber.rs
new file mode 100644
index 0000000000..e8f4441196
--- /dev/null
+++ b/third_party/rust/tracing-core/src/subscriber.rs
@@ -0,0 +1,870 @@
+//! Collectors collect and record trace data.
+use crate::{span, Dispatch, Event, LevelFilter, Metadata};
+
+use crate::stdlib::{
+ any::{Any, TypeId},
+ boxed::Box,
+ sync::Arc,
+};
+
+/// Trait representing the functions required to collect trace data.
+///
+/// Crates that provide implementations of methods for collecting or recording
+/// trace data should implement the `Subscriber` interface. This trait is
+/// intended to represent fundamental primitives for collecting trace events and
+/// spans — other libraries may offer utility functions and types to make
+/// subscriber implementations more modular or improve the ergonomics of writing
+/// subscribers.
+///
+/// A subscriber is responsible for the following:
+/// - Registering new spans as they are created, and providing them with span
+/// IDs. Implicitly, this means the subscriber may determine the strategy for
+/// determining span equality.
+/// - Recording the attachment of field values and follows-from annotations to
+/// spans.
+/// - Filtering spans and events, and determining when those filters must be
+/// invalidated.
+/// - Observing spans as they are entered, exited, and closed, and events as
+/// they occur.
+///
+/// When a span is entered or exited, the subscriber is provided only with the
+/// [ID] with which it tagged that span when it was created. This means
+/// that it is up to the subscriber to determine whether and how span _data_ —
+/// the fields and metadata describing the span — should be stored. The
+/// [`new_span`] function is called when a new span is created, and at that
+/// point, the subscriber _may_ choose to store the associated data if it will
+/// be referenced again. However, if the data has already been recorded and will
+/// not be needed by the implementations of `enter` and `exit`, the subscriber
+/// may freely discard that data without allocating space to store it.
+///
+/// ## Overriding default impls
+///
+/// Some trait methods on `Subscriber` have default implementations, either in
+/// order to reduce the surface area of implementing `Subscriber`, or for
+/// backward-compatibility reasons. However, many subscribers will likely want
+/// to override these default implementations.
+///
+/// The following methods are likely of interest:
+///
+/// - [`register_callsite`] is called once for each callsite from which a span
+/// event may originate, and returns an [`Interest`] value describing whether or
+/// not the subscriber wishes to see events or spans from that callsite. By
+/// default, it calls [`enabled`], and returns `Interest::always()` if
+/// `enabled` returns true, or `Interest::never()` if enabled returns false.
+/// However, if the subscriber's interest can change dynamically at runtime,
+/// it may want to override this function to return `Interest::sometimes()`.
+/// Additionally, subscribers which wish to perform a behaviour once for each
+/// callsite, such as allocating storage for data related to that callsite,
+/// can perform it in `register_callsite`.
+///
+/// See also the [documentation on the callsite registry][cs-reg] for details
+/// on [`register_callsite`].
+///
+/// - [`event_enabled`] is called once before every call to the [`event`]
+/// method. This can be used to implement filtering on events once their field
+/// values are known, but before any processing is done in the `event` method.
+/// - [`clone_span`] is called every time a span ID is cloned, and [`try_close`]
+/// is called when a span ID is dropped. By default, these functions do
+/// nothing. However, they can be used to implement reference counting for
+/// spans, allowing subscribers to free storage for span data and to determine
+/// when a span has _closed_ permanently (rather than being exited).
+/// Subscribers which store per-span data or which need to track span closures
+/// should override these functions together.
+///
+/// [ID]: super::span::Id
+/// [`new_span`]: Subscriber::new_span
+/// [`register_callsite`]: Subscriber::register_callsite
+/// [`enabled`]: Subscriber::enabled
+/// [`clone_span`]: Subscriber::clone_span
+/// [`try_close`]: Subscriber::try_close
+/// [cs-reg]: crate::callsite#registering-callsites
+/// [`event`]: Subscriber::event
+/// [`event_enabled`]: Subscriber::event_enabled
+pub trait Subscriber: 'static {
+ /// Invoked when this subscriber becomes a [`Dispatch`].
+ ///
+ /// ## Avoiding Memory Leaks
+ ///
+ /// `Subscriber`s should not store their own [`Dispatch`]. Because the
+ /// `Dispatch` owns the `Subscriber`, storing the `Dispatch` within the
+ /// `Subscriber` will create a reference count cycle, preventing the `Dispatch`
+ /// from ever being dropped.
+ ///
+ /// Instead, when it is necessary to store a cyclical reference to the
+ /// `Dispatch` within a `Subscriber`, use [`Dispatch::downgrade`] to convert a
+ /// `Dispatch` into a [`WeakDispatch`]. This type is analogous to
+ /// [`std::sync::Weak`], and does not create a reference count cycle. A
+ /// [`WeakDispatch`] can be stored within a `Subscriber` without causing a
+ /// memory leak, and can be [upgraded] into a `Dispatch` temporarily when
+ /// the `Dispatch` must be accessed by the `Subscriber`.
+ ///
+ /// [`WeakDispatch`]: crate::dispatcher::WeakDispatch
+ /// [upgraded]: crate::dispatcher::WeakDispatch::upgrade
+ fn on_register_dispatch(&self, subscriber: &Dispatch) {
+ let _ = subscriber;
+ }
+
+ /// Registers a new [callsite] with this subscriber, returning whether or not
+ /// the subscriber is interested in being notified about the callsite.
+ ///
+ /// By default, this function assumes that the subscriber's [filter]
+ /// represents an unchanging view of its interest in the callsite. However,
+ /// if this is not the case, subscribers may override this function to
+ /// indicate different interests, or to implement behaviour that should run
+ /// once for every callsite.
+ ///
+ /// This function is guaranteed to be called at least once per callsite on
+ /// every active subscriber. The subscriber may store the keys to fields it
+ /// cares about in order to reduce the cost of accessing fields by name,
+ /// preallocate storage for that callsite, or perform any other actions it
+ /// wishes to perform once for each callsite.
+ ///
+ /// The subscriber should then return an [`Interest`], indicating
+ /// whether it is interested in being notified about that callsite in the
+ /// future. This may be `Always` indicating that the subscriber always
+ /// wishes to be notified about the callsite, and its filter need not be
+ /// re-evaluated; `Sometimes`, indicating that the subscriber may sometimes
+ /// care about the callsite but not always (such as when sampling), or
+ /// `Never`, indicating that the subscriber never wishes to be notified about
+ /// that callsite. If all active subscribers return `Never`, a callsite will
+ /// never be enabled unless a new subscriber expresses interest in it.
+ ///
+ /// `Subscriber`s which require their filters to be run every time an event
+ /// occurs or a span is entered/exited should return `Interest::sometimes`.
+ /// If a subscriber returns `Interest::sometimes`, then its [`enabled`] method
+ /// will be called every time an event or span is created from that callsite.
+ ///
+ /// For example, suppose a sampling subscriber is implemented by
+ /// incrementing a counter every time `enabled` is called and only returning
+ /// `true` when the counter is divisible by a specified sampling rate. If
+ /// that subscriber returns `Interest::always` from `register_callsite`, then
+ /// the filter will not be re-evaluated once it has been applied to a given
+ /// set of metadata. Thus, the counter will not be incremented, and the span
+ /// or event that corresponds to the metadata will never be `enabled`.
+ ///
+ /// `Subscriber`s that need to change their filters occasionally should call
+ /// [`rebuild_interest_cache`] to re-evaluate `register_callsite` for all
+ /// callsites.
+ ///
+ /// Similarly, if a `Subscriber` has a filtering strategy that can be
+ /// changed dynamically at runtime, it would need to re-evaluate that filter
+ /// if the cached results have changed.
+ ///
+ /// A subscriber which manages fanout to multiple other subscribers
+ /// should proxy this decision to all of its child subscribers,
+ /// returning `Interest::never` only if _all_ such children return
+ /// `Interest::never`. If the set of subscribers to which spans are
+ /// broadcast may change dynamically, the subscriber should also never
+ /// return `Interest::Never`, as a new subscriber may be added that _is_
+ /// interested.
+ ///
+ /// See the [documentation on the callsite registry][cs-reg] for more
+ /// details on how and when the `register_callsite` method is called.
+ ///
+ /// # Notes
+ /// This function may be called again when a new subscriber is created or
+ /// when the registry is invalidated.
+ ///
+ /// If a subscriber returns `Interest::never` for a particular callsite, it
+ /// _may_ still see spans and events originating from that callsite, if
+ /// another subscriber expressed interest in it.
+ ///
+ /// [callsite]: crate::callsite
+ /// [filter]: Self::enabled
+ /// [metadata]: super::metadata::Metadata
+ /// [`enabled`]: Subscriber::enabled()
+ /// [`rebuild_interest_cache`]: super::callsite::rebuild_interest_cache
+ /// [cs-reg]: crate::callsite#registering-callsites
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ if self.enabled(metadata) {
+ Interest::always()
+ } else {
+ Interest::never()
+ }
+ }
+
+ /// Returns true if a span or event with the specified [metadata] would be
+ /// recorded.
+ ///
+ /// By default, it is assumed that this filter needs only be evaluated once
+ /// for each callsite, so it is called by [`register_callsite`] when each
+ /// callsite is registered. The result is used to determine if the subscriber
+ /// is always [interested] or never interested in that callsite. This is intended
+ /// primarily as an optimization, so that expensive filters (such as those
+ /// involving string search, et cetera) need not be re-evaluated.
+ ///
+ /// However, if the subscriber's interest in a particular span or event may
+ /// change, or depends on contexts only determined dynamically at runtime,
+ /// then the `register_callsite` method should be overridden to return
+ /// [`Interest::sometimes`]. In that case, this function will be called every
+ /// time that span or event occurs.
+ ///
+ /// [metadata]: super::metadata::Metadata
+ /// [interested]: Interest
+ /// [`Interest::sometimes`]: Interest::sometimes
+ /// [`register_callsite`]: Subscriber::register_callsite()
+ fn enabled(&self, metadata: &Metadata<'_>) -> bool;
+
+ /// Returns the highest [verbosity level][level] that this `Subscriber` will
+ /// enable, or `None`, if the subscriber does not implement level-based
+ /// filtering or chooses not to implement this method.
+ ///
+ /// If this method returns a [`Level`][level], it will be used as a hint to
+ /// determine the most verbose level that will be enabled. This will allow
+ /// spans and events which are more verbose than that level to be skipped
+ /// more efficiently. Subscribers which perform filtering are strongly
+ /// encouraged to provide an implementation of this method.
+ ///
+ /// If the maximum level the subscriber will enable can change over the
+ /// course of its lifetime, it is free to return a different value from
+ /// multiple invocations of this method. However, note that changes in the
+ /// maximum level will **only** be reflected after the callsite [`Interest`]
+ /// cache is rebuilt, by calling the [`callsite::rebuild_interest_cache`][rebuild]
+ /// function. Therefore, if the subscriber will change the value returned by
+ /// this method, it is responsible for ensuring that
+ /// [`rebuild_interest_cache`][rebuild] is called after the value of the max
+ /// level changes.
+ ///
+ /// [level]: super::Level
+ /// [rebuild]: super::callsite::rebuild_interest_cache
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ None
+ }
+
+ /// Visit the construction of a new span, returning a new [span ID] for the
+ /// span being constructed.
+ ///
+ /// The provided [`Attributes`] contains any field values that were provided
+ /// when the span was created. The subscriber may pass a [visitor] to the
+ /// `Attributes`' [`record` method] to record these values.
+ ///
+ /// IDs are used to uniquely identify spans and events within the context of a
+ /// subscriber, so span equality will be based on the returned ID. Thus, if
+ /// the subscriber wishes for all spans with the same metadata to be
+ /// considered equal, it should return the same ID every time it is given a
+ /// particular set of metadata. Similarly, if it wishes for two separate
+ /// instances of a span with the same metadata to *not* be equal, it should
+ /// return a distinct ID every time this function is called, regardless of
+ /// the metadata.
+ ///
+ /// Note that the subscriber is free to assign span IDs based on whatever
+ /// scheme it sees fit. Any guarantees about uniqueness, ordering, or ID
+ /// reuse are left up to the subscriber implementation to determine.
+ ///
+ /// [span ID]: super::span::Id
+ /// [`Attributes`]: super::span::Attributes
+ /// [visitor]: super::field::Visit
+ /// [`record` method]: super::span::Attributes::record
+ fn new_span(&self, span: &span::Attributes<'_>) -> span::Id;
+
+ // === Notification methods ===============================================
+
+ /// Record a set of values on a span.
+ ///
+ /// This method will be invoked when value is recorded on a span.
+ /// Recording multiple values for the same field is possible,
+ /// but the actual behaviour is defined by the subscriber implementation.
+ ///
+ /// Keep in mind that a span might not provide a value
+ /// for each field it declares.
+ ///
+ /// The subscriber is expected to provide a [visitor] to the `Record`'s
+ /// [`record` method] in order to record the added values.
+ ///
+ /// # Example
+ /// "foo = 3" will be recorded when [`record`] is called on the
+ /// `Attributes` passed to `new_span`.
+ /// Since values are not provided for the `bar` and `baz` fields,
+ /// the span's `Metadata` will indicate that it _has_ those fields,
+ /// but values for them won't be recorded at this time.
+ ///
+ /// ```rust,ignore
+ /// # use tracing::span;
+ ///
+ /// let mut span = span!("my_span", foo = 3, bar, baz);
+ ///
+ /// // `Subscriber::record` will be called with a `Record`
+ /// // containing "bar = false"
+ /// span.record("bar", &false);
+ ///
+ /// // `Subscriber::record` will be called with a `Record`
+ /// // containing "baz = "a string""
+ /// span.record("baz", &"a string");
+ /// ```
+ ///
+ /// [visitor]: super::field::Visit
+ /// [`record`]: super::span::Attributes::record
+ /// [`record` method]: super::span::Record::record
+ fn record(&self, span: &span::Id, values: &span::Record<'_>);
+
+ /// Adds an indication that `span` follows from the span with the id
+ /// `follows`.
+ ///
+ /// This relationship differs somewhat from the parent-child relationship: a
+ /// span may have any number of prior spans, rather than a single one; and
+ /// spans are not considered to be executing _inside_ of the spans they
+ /// follow from. This means that a span may close even if subsequent spans
+ /// that follow from it are still open, and time spent inside of a
+ /// subsequent span should not be included in the time its precedents were
+ /// executing. This is used to model causal relationships such as when a
+ /// single future spawns several related background tasks, et cetera.
+ ///
+ /// If the subscriber has spans corresponding to the given IDs, it should
+ /// record this relationship in whatever way it deems necessary. Otherwise,
+ /// if one or both of the given span IDs do not correspond to spans that the
+ /// subscriber knows about, or if a cyclical relationship would be created
+ /// (i.e., some span _a_ which proceeds some other span _b_ may not also
+ /// follow from _b_), it may silently do nothing.
+ fn record_follows_from(&self, span: &span::Id, follows: &span::Id);
+
+ /// Determine if an [`Event`] should be recorded.
+ ///
+ /// By default, this returns `true` and `Subscriber`s can filter events in
+ /// [`event`][Self::event] without any penalty. However, when `event` is
+ /// more complicated, this can be used to determine if `event` should be
+ /// called at all, separating out the decision from the processing.
+ fn event_enabled(&self, event: &Event<'_>) -> bool {
+ let _ = event;
+ true
+ }
+
+ /// Records that an [`Event`] has occurred.
+ ///
+ /// This method will be invoked when an Event is constructed by
+ /// the `Event`'s [`dispatch` method]. For example, this happens internally
+ /// when an event macro from `tracing` is called.
+ ///
+ /// The key difference between this method and `record` is that `record` is
+ /// called when a value is recorded for a field defined by a span,
+ /// while `event` is called when a new event occurs.
+ ///
+ /// The provided `Event` struct contains any field values attached to the
+ /// event. The subscriber may pass a [visitor] to the `Event`'s
+ /// [`record` method] to record these values.
+ ///
+ /// [`Event`]: super::event::Event
+ /// [visitor]: super::field::Visit
+ /// [`record` method]: super::event::Event::record
+ /// [`dispatch` method]: super::event::Event::dispatch
+ fn event(&self, event: &Event<'_>);
+
+ /// Records that a span has been entered.
+ ///
+ /// When entering a span, this method is called to notify the subscriber
+ /// that the span has been entered. The subscriber is provided with the
+ /// [span ID] of the entered span, and should update any internal state
+ /// tracking the current span accordingly.
+ ///
+ /// [span ID]: super::span::Id
+ fn enter(&self, span: &span::Id);
+
+ /// Records that a span has been exited.
+ ///
+ /// When exiting a span, this method is called to notify the subscriber
+ /// that the span has been exited. The subscriber is provided with the
+ /// [span ID] of the exited span, and should update any internal state
+ /// tracking the current span accordingly.
+ ///
+ /// Exiting a span does not imply that the span will not be re-entered.
+ ///
+ /// [span ID]: super::span::Id
+ fn exit(&self, span: &span::Id);
+
+ /// Notifies the subscriber that a [span ID] has been cloned.
+ ///
+ /// This function is guaranteed to only be called with span IDs that were
+ /// returned by this subscriber's `new_span` function.
+ ///
+ /// Note that the default implementation of this function this is just the
+ /// identity function, passing through the identifier. However, it can be
+ /// used in conjunction with [`try_close`] to track the number of handles
+ /// capable of `enter`ing a span. When all the handles have been dropped
+ /// (i.e., `try_close` has been called one more time than `clone_span` for a
+ /// given ID), the subscriber may assume that the span will not be entered
+ /// again. It is then free to deallocate storage for data associated with
+ /// that span, write data from that span to IO, and so on.
+ ///
+ /// For more unsafe situations, however, if `id` is itself a pointer of some
+ /// kind this can be used as a hook to "clone" the pointer, depending on
+ /// what that means for the specified pointer.
+ ///
+ /// [span ID]: super::span::Id
+ /// [`try_close`]: Subscriber::try_close
+ fn clone_span(&self, id: &span::Id) -> span::Id {
+ id.clone()
+ }
+
+ /// **This method is deprecated.**
+ ///
+ /// Using `drop_span` may result in subscribers composed using
+ /// `tracing-subscriber` crate's `Layer` trait from observing close events.
+ /// Use [`try_close`] instead.
+ ///
+ /// The default implementation of this function does nothing.
+ ///
+ /// [`try_close`]: Subscriber::try_close
+ #[deprecated(since = "0.1.2", note = "use `Subscriber::try_close` instead")]
+ fn drop_span(&self, _id: span::Id) {}
+
+ /// Notifies the subscriber that a [span ID] has been dropped, and returns
+ /// `true` if there are now 0 IDs that refer to that span.
+ ///
+ /// Higher-level libraries providing functionality for composing multiple
+ /// subscriber implementations may use this return value to notify any
+ /// "layered" subscribers that this subscriber considers the span closed.
+ ///
+ /// The default implementation of this method calls the subscriber's
+ /// [`drop_span`] method and returns `false`. This means that, unless the
+ /// subscriber overrides the default implementation, close notifications
+ /// will never be sent to any layered subscribers. In general, if the
+ /// subscriber tracks reference counts, this method should be implemented,
+ /// rather than `drop_span`.
+ ///
+ /// This function is guaranteed to only be called with span IDs that were
+ /// returned by this subscriber's `new_span` function.
+ ///
+ /// It's guaranteed that if this function has been called once more than the
+ /// number of times `clone_span` was called with the same `id`, then no more
+ /// handles that can enter the span with that `id` exist. This means that it
+ /// can be used in conjunction with [`clone_span`] to track the number of
+ /// handles capable of `enter`ing a span. When all the handles have been
+ /// dropped (i.e., `try_close` has been called one more time than
+ /// `clone_span` for a given ID), the subscriber may assume that the span
+ /// will not be entered again, and should return `true`. It is then free to
+ /// deallocate storage for data associated with that span, write data from
+ /// that span to IO, and so on.
+ ///
+ /// **Note**: since this function is called when spans are dropped,
+ /// implementations should ensure that they are unwind-safe. Panicking from
+ /// inside of a `try_close` function may cause a double panic, if the span
+ /// was dropped due to a thread unwinding.
+ ///
+ /// [span ID]: super::span::Id
+ /// [`clone_span`]: Subscriber::clone_span
+ /// [`drop_span`]: Subscriber::drop_span
+ fn try_close(&self, id: span::Id) -> bool {
+ #[allow(deprecated)]
+ self.drop_span(id);
+ false
+ }
+
+ /// Returns a type representing this subscriber's view of the current span.
+ ///
+ /// If subscribers track a current span, they should override this function
+ /// to return [`Current::new`] if the thread from which this method is
+ /// called is inside a span, or [`Current::none`] if the thread is not
+ /// inside a span.
+ ///
+ /// By default, this returns a value indicating that the subscriber
+ /// does **not** track what span is current. If the subscriber does not
+ /// implement a current span, it should not override this method.
+ ///
+ /// [`Current::new`]: super::span::Current#tymethod.new
+ /// [`Current::none`]: super::span::Current#tymethod.none
+ fn current_span(&self) -> span::Current {
+ span::Current::unknown()
+ }
+
+ // === Downcasting methods ================================================
+
+ /// If `self` is the same type as the provided `TypeId`, returns an untyped
+ /// `*const` pointer to that type. Otherwise, returns `None`.
+ ///
+ /// If you wish to downcast a `Subscriber`, it is strongly advised to use
+ /// the safe API provided by [`downcast_ref`] instead.
+ ///
+ /// This API is required for `downcast_raw` to be a trait method; a method
+ /// signature like [`downcast_ref`] (with a generic type parameter) is not
+ /// object-safe, and thus cannot be a trait method for `Subscriber`. This
+ /// means that if we only exposed `downcast_ref`, `Subscriber`
+ /// implementations could not override the downcasting behavior
+ ///
+ /// This method may be overridden by "fan out" or "chained" subscriber
+ /// implementations which consist of multiple composed types. Such
+ /// subscribers might allow `downcast_raw` by returning references to those
+ /// component if they contain components with the given `TypeId`.
+ ///
+ /// # Safety
+ ///
+ /// The [`downcast_ref`] method expects that the pointer returned by
+ /// `downcast_raw` is non-null and points to a valid instance of the type
+ /// with the provided `TypeId`. Failure to ensure this will result in
+ /// undefined behaviour, so implementing `downcast_raw` is unsafe.
+ ///
+ /// [`downcast_ref`]: #method.downcast_ref
+ unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
+ if id == TypeId::of::<Self>() {
+ Some(self as *const Self as *const ())
+ } else {
+ None
+ }
+ }
+}
+
+impl dyn Subscriber {
+ /// Returns `true` if this `Subscriber` is the same type as `T`.
+ pub fn is<T: Any>(&self) -> bool {
+ self.downcast_ref::<T>().is_some()
+ }
+
+ /// Returns some reference to this `Subscriber` value if it is of type `T`,
+ /// or `None` if it isn't.
+ pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+ unsafe {
+ let raw = self.downcast_raw(TypeId::of::<T>())?;
+ if raw.is_null() {
+ None
+ } else {
+ Some(&*(raw as *const _))
+ }
+ }
+ }
+}
+
+impl dyn Subscriber + Send {
+ /// Returns `true` if this [`Subscriber`] is the same type as `T`.
+ pub fn is<T: Any>(&self) -> bool {
+ self.downcast_ref::<T>().is_some()
+ }
+
+ /// Returns some reference to this [`Subscriber`] value if it is of type `T`,
+ /// or `None` if it isn't.
+ pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+ unsafe {
+ let raw = self.downcast_raw(TypeId::of::<T>())?;
+ if raw.is_null() {
+ None
+ } else {
+ Some(&*(raw as *const _))
+ }
+ }
+ }
+}
+
+impl dyn Subscriber + Sync {
+ /// Returns `true` if this [`Subscriber`] is the same type as `T`.
+ pub fn is<T: Any>(&self) -> bool {
+ self.downcast_ref::<T>().is_some()
+ }
+
+ /// Returns some reference to this `[`Subscriber`] value if it is of type `T`,
+ /// or `None` if it isn't.
+ pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+ unsafe {
+ let raw = self.downcast_raw(TypeId::of::<T>())?;
+ if raw.is_null() {
+ None
+ } else {
+ Some(&*(raw as *const _))
+ }
+ }
+ }
+}
+
+impl dyn Subscriber + Send + Sync {
+ /// Returns `true` if this [`Subscriber`] is the same type as `T`.
+ pub fn is<T: Any>(&self) -> bool {
+ self.downcast_ref::<T>().is_some()
+ }
+
+ /// Returns some reference to this [`Subscriber`] value if it is of type `T`,
+ /// or `None` if it isn't.
+ pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
+ unsafe {
+ let raw = self.downcast_raw(TypeId::of::<T>())?;
+ if raw.is_null() {
+ None
+ } else {
+ Some(&*(raw as *const _))
+ }
+ }
+ }
+}
+
+/// Indicates a [`Subscriber`]'s interest in a particular callsite.
+///
+/// `Subscriber`s return an `Interest` from their [`register_callsite`] methods
+/// in order to determine whether that span should be enabled or disabled.
+///
+/// [`Subscriber`]: super::Subscriber
+/// [`register_callsite`]: super::Subscriber::register_callsite
+#[derive(Clone, Debug)]
+pub struct Interest(InterestKind);
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
+enum InterestKind {
+ Never = 0,
+ Sometimes = 1,
+ Always = 2,
+}
+
+impl Interest {
+ /// Returns an `Interest` indicating that the subscriber is never interested
+ /// in being notified about a callsite.
+ ///
+ /// If all active subscribers are `never()` interested in a callsite, it will
+ /// be completely disabled unless a new subscriber becomes active.
+ #[inline]
+ pub fn never() -> Self {
+ Interest(InterestKind::Never)
+ }
+
+ /// Returns an `Interest` indicating the subscriber is sometimes interested
+ /// in being notified about a callsite.
+ ///
+ /// If all active subscribers are `sometimes` or `never` interested in a
+ /// callsite, the currently active subscriber will be asked to filter that
+ /// callsite every time it creates a span. This will be the case until a new
+ /// subscriber expresses that it is `always` interested in the callsite.
+ #[inline]
+ pub fn sometimes() -> Self {
+ Interest(InterestKind::Sometimes)
+ }
+
+ /// Returns an `Interest` indicating the subscriber is always interested in
+ /// being notified about a callsite.
+ ///
+ /// If any subscriber expresses that it is `always()` interested in a given
+ /// callsite, then the callsite will always be enabled.
+ #[inline]
+ pub fn always() -> Self {
+ Interest(InterestKind::Always)
+ }
+
+ /// Returns `true` if the subscriber is never interested in being notified
+ /// about this callsite.
+ #[inline]
+ pub fn is_never(&self) -> bool {
+ matches!(self.0, InterestKind::Never)
+ }
+
+ /// Returns `true` if the subscriber is sometimes interested in being notified
+ /// about this callsite.
+ #[inline]
+ pub fn is_sometimes(&self) -> bool {
+ matches!(self.0, InterestKind::Sometimes)
+ }
+
+ /// Returns `true` if the subscriber is always interested in being notified
+ /// about this callsite.
+ #[inline]
+ pub fn is_always(&self) -> bool {
+ matches!(self.0, InterestKind::Always)
+ }
+
+ /// Returns the common interest between these two Interests.
+ ///
+ /// If both interests are the same, this propagates that interest.
+ /// Otherwise, if they differ, the result must always be
+ /// `Interest::sometimes` --- if the two subscribers differ in opinion, we
+ /// will have to ask the current subscriber what it thinks, no matter what.
+ pub(crate) fn and(self, rhs: Interest) -> Self {
+ if self.0 == rhs.0 {
+ self
+ } else {
+ Interest::sometimes()
+ }
+ }
+}
+
+/// A no-op [`Subscriber`].
+///
+/// [`NoSubscriber`] implements the [`Subscriber`] trait by never being enabled,
+/// never being interested in any callsite, and dropping all spans and events.
+#[derive(Copy, Clone, Debug, Default)]
+pub struct NoSubscriber(());
+
+impl Subscriber for NoSubscriber {
+ #[inline]
+ fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest {
+ Interest::never()
+ }
+
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ span::Id::from_u64(0xDEAD)
+ }
+
+ fn event(&self, _event: &Event<'_>) {}
+
+ fn record(&self, _span: &span::Id, _values: &span::Record<'_>) {}
+
+ fn record_follows_from(&self, _span: &span::Id, _follows: &span::Id) {}
+
+ #[inline]
+ fn enabled(&self, _metadata: &Metadata<'_>) -> bool {
+ false
+ }
+
+ fn enter(&self, _span: &span::Id) {}
+ fn exit(&self, _span: &span::Id) {}
+}
+
+impl<S> Subscriber for Box<S>
+where
+ S: Subscriber + ?Sized,
+{
+ #[inline]
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.as_ref().register_callsite(metadata)
+ }
+
+ #[inline]
+ fn enabled(&self, metadata: &Metadata<'_>) -> bool {
+ self.as_ref().enabled(metadata)
+ }
+
+ #[inline]
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.as_ref().max_level_hint()
+ }
+
+ #[inline]
+ fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
+ self.as_ref().new_span(span)
+ }
+
+ #[inline]
+ fn record(&self, span: &span::Id, values: &span::Record<'_>) {
+ self.as_ref().record(span, values)
+ }
+
+ #[inline]
+ fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
+ self.as_ref().record_follows_from(span, follows)
+ }
+
+ #[inline]
+ fn event_enabled(&self, event: &Event<'_>) -> bool {
+ self.as_ref().event_enabled(event)
+ }
+
+ #[inline]
+ fn event(&self, event: &Event<'_>) {
+ self.as_ref().event(event)
+ }
+
+ #[inline]
+ fn enter(&self, span: &span::Id) {
+ self.as_ref().enter(span)
+ }
+
+ #[inline]
+ fn exit(&self, span: &span::Id) {
+ self.as_ref().exit(span)
+ }
+
+ #[inline]
+ fn clone_span(&self, id: &span::Id) -> span::Id {
+ self.as_ref().clone_span(id)
+ }
+
+ #[inline]
+ fn try_close(&self, id: span::Id) -> bool {
+ self.as_ref().try_close(id)
+ }
+
+ #[inline]
+ #[allow(deprecated)]
+ fn drop_span(&self, id: span::Id) {
+ self.as_ref().try_close(id);
+ }
+
+ #[inline]
+ fn current_span(&self) -> span::Current {
+ self.as_ref().current_span()
+ }
+
+ #[inline]
+ unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
+ if id == TypeId::of::<Self>() {
+ return Some(self as *const Self as *const _);
+ }
+
+ self.as_ref().downcast_raw(id)
+ }
+}
+
+impl<S> Subscriber for Arc<S>
+where
+ S: Subscriber + ?Sized,
+{
+ #[inline]
+ fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
+ self.as_ref().register_callsite(metadata)
+ }
+
+ #[inline]
+ fn enabled(&self, metadata: &Metadata<'_>) -> bool {
+ self.as_ref().enabled(metadata)
+ }
+
+ #[inline]
+ fn max_level_hint(&self) -> Option<LevelFilter> {
+ self.as_ref().max_level_hint()
+ }
+
+ #[inline]
+ fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
+ self.as_ref().new_span(span)
+ }
+
+ #[inline]
+ fn record(&self, span: &span::Id, values: &span::Record<'_>) {
+ self.as_ref().record(span, values)
+ }
+
+ #[inline]
+ fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
+ self.as_ref().record_follows_from(span, follows)
+ }
+
+ #[inline]
+ fn event_enabled(&self, event: &Event<'_>) -> bool {
+ self.as_ref().event_enabled(event)
+ }
+
+ #[inline]
+ fn event(&self, event: &Event<'_>) {
+ self.as_ref().event(event)
+ }
+
+ #[inline]
+ fn enter(&self, span: &span::Id) {
+ self.as_ref().enter(span)
+ }
+
+ #[inline]
+ fn exit(&self, span: &span::Id) {
+ self.as_ref().exit(span)
+ }
+
+ #[inline]
+ fn clone_span(&self, id: &span::Id) -> span::Id {
+ self.as_ref().clone_span(id)
+ }
+
+ #[inline]
+ fn try_close(&self, id: span::Id) -> bool {
+ self.as_ref().try_close(id)
+ }
+
+ #[inline]
+ #[allow(deprecated)]
+ fn drop_span(&self, id: span::Id) {
+ self.as_ref().try_close(id);
+ }
+
+ #[inline]
+ fn current_span(&self) -> span::Current {
+ self.as_ref().current_span()
+ }
+
+ #[inline]
+ unsafe fn downcast_raw(&self, id: TypeId) -> Option<*const ()> {
+ if id == TypeId::of::<Self>() {
+ return Some(self as *const Self as *const _);
+ }
+
+ self.as_ref().downcast_raw(id)
+ }
+}
diff --git a/third_party/rust/tracing-core/tests/common/mod.rs b/third_party/rust/tracing-core/tests/common/mod.rs
new file mode 100644
index 0000000000..3420f0b899
--- /dev/null
+++ b/third_party/rust/tracing-core/tests/common/mod.rs
@@ -0,0 +1,30 @@
+use tracing_core::{metadata::Metadata, span, subscriber::Subscriber, Event};
+
+pub struct TestSubscriberA;
+impl Subscriber for TestSubscriberA {
+ fn enabled(&self, _: &Metadata<'_>) -> bool {
+ true
+ }
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ span::Id::from_u64(1)
+ }
+ fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
+ fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
+ fn event(&self, _: &Event<'_>) {}
+ fn enter(&self, _: &span::Id) {}
+ fn exit(&self, _: &span::Id) {}
+}
+pub struct TestSubscriberB;
+impl Subscriber for TestSubscriberB {
+ fn enabled(&self, _: &Metadata<'_>) -> bool {
+ true
+ }
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ span::Id::from_u64(1)
+ }
+ fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
+ fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
+ fn event(&self, _: &Event<'_>) {}
+ fn enter(&self, _: &span::Id) {}
+ fn exit(&self, _: &span::Id) {}
+}
diff --git a/third_party/rust/tracing-core/tests/dispatch.rs b/third_party/rust/tracing-core/tests/dispatch.rs
new file mode 100644
index 0000000000..3820692a86
--- /dev/null
+++ b/third_party/rust/tracing-core/tests/dispatch.rs
@@ -0,0 +1,56 @@
+#![cfg(feature = "std")]
+mod common;
+
+use common::*;
+use tracing_core::dispatcher::*;
+
+#[test]
+fn set_default_dispatch() {
+ set_global_default(Dispatch::new(TestSubscriberA)).expect("global dispatch set failed");
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberA>(),
+ "global dispatch get failed"
+ )
+ });
+
+ let guard = set_default(&Dispatch::new(TestSubscriberB));
+ get_default(|current| assert!(current.is::<TestSubscriberB>(), "set_default get failed"));
+
+ // Drop the guard, setting the dispatch back to the global dispatch
+ drop(guard);
+
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberA>(),
+ "global dispatch get failed"
+ )
+ });
+}
+
+#[test]
+fn nested_set_default() {
+ let _guard = set_default(&Dispatch::new(TestSubscriberA));
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberA>(),
+ "set_default for outer subscriber failed"
+ )
+ });
+
+ let inner_guard = set_default(&Dispatch::new(TestSubscriberB));
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberB>(),
+ "set_default inner subscriber failed"
+ )
+ });
+
+ drop(inner_guard);
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberA>(),
+ "set_default outer subscriber failed"
+ )
+ });
+}
diff --git a/third_party/rust/tracing-core/tests/global_dispatch.rs b/third_party/rust/tracing-core/tests/global_dispatch.rs
new file mode 100644
index 0000000000..d430ac6182
--- /dev/null
+++ b/third_party/rust/tracing-core/tests/global_dispatch.rs
@@ -0,0 +1,34 @@
+mod common;
+
+use common::*;
+use tracing_core::dispatcher::*;
+#[test]
+fn global_dispatch() {
+ set_global_default(Dispatch::new(TestSubscriberA)).expect("global dispatch set failed");
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberA>(),
+ "global dispatch get failed"
+ )
+ });
+
+ #[cfg(feature = "std")]
+ with_default(&Dispatch::new(TestSubscriberB), || {
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberB>(),
+ "thread-local override of global dispatch failed"
+ )
+ });
+ });
+
+ get_default(|current| {
+ assert!(
+ current.is::<TestSubscriberA>(),
+ "reset to global override failed"
+ )
+ });
+
+ set_global_default(Dispatch::new(TestSubscriberA))
+ .expect_err("double global dispatch set succeeded");
+}
diff --git a/third_party/rust/tracing-core/tests/macros.rs b/third_party/rust/tracing-core/tests/macros.rs
new file mode 100644
index 0000000000..ee9007eeeb
--- /dev/null
+++ b/third_party/rust/tracing-core/tests/macros.rs
@@ -0,0 +1,48 @@
+use tracing_core::{
+ callsite::Callsite,
+ metadata,
+ metadata::{Kind, Level, Metadata},
+ subscriber::Interest,
+};
+
+#[test]
+fn metadata_macro_api() {
+ // This test should catch any inadvertent breaking changes
+ // caused by changes to the macro.
+ struct TestCallsite;
+
+ impl Callsite for TestCallsite {
+ fn set_interest(&self, _: Interest) {
+ unimplemented!("test")
+ }
+ fn metadata(&self) -> &Metadata<'_> {
+ unimplemented!("test")
+ }
+ }
+
+ static CALLSITE: TestCallsite = TestCallsite;
+ let _metadata = metadata! {
+ name: "test_metadata",
+ target: "test_target",
+ level: Level::DEBUG,
+ fields: &["foo", "bar", "baz"],
+ callsite: &CALLSITE,
+ kind: Kind::SPAN,
+ };
+ let _metadata = metadata! {
+ name: "test_metadata",
+ target: "test_target",
+ level: Level::TRACE,
+ fields: &[],
+ callsite: &CALLSITE,
+ kind: Kind::EVENT,
+ };
+ let _metadata = metadata! {
+ name: "test_metadata",
+ target: "test_target",
+ level: Level::INFO,
+ fields: &[],
+ callsite: &CALLSITE,
+ kind: Kind::EVENT
+ };
+}
diff --git a/third_party/rust/tracing/.cargo-checksum.json b/third_party/rust/tracing/.cargo-checksum.json
new file mode 100644
index 0000000000..8bfa395bbf
--- /dev/null
+++ b/third_party/rust/tracing/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"dc8a552611986799a0eebb56fd119ea8ae32c9b8da4be9914fe127627ad4f38a","Cargo.toml":"f8d12a05bc7ed5cfef787db206c05cc5ebcd2c165e6e629b613d1a3ff4f138de","LICENSE":"898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1","README.md":"6ff17749109fbe0855220188015846f40d3997bc2631c3163496c183c0bd50ce","benches/baseline.rs":"43a3e31b6c33dba2e6328052301b707b212487b83f0dcffc843061a9c48a2319","benches/dispatch_get_clone.rs":"866239abeb74a82440741c948a4e7e0a44e92e8cc87319ec57e3b057c9e8f5dd","benches/dispatch_get_ref.rs":"dd2803259a6784c256304e676bbce05de233e4c8451ac85863787213343e9be7","benches/empty_span.rs":"9f51cf376414ea751b2f50c357f2435a545d606118286f5b8b89f185e28aad8c","benches/enter_span.rs":"4410ec73d277e7b54e9f306c00ff3b79a150d1832966b7fc29984c8e3ad8d57c","benches/event.rs":"98de3c82ed18abe0a3cbe6eda9a4f9deec2b69bca42c3aac11dea4b608b85a67","benches/shared.rs":"2623311af7d153685064e664a5903d03e7dc3179754c324f3a76f29f060515e6","benches/span_fields.rs":"9166cd43ef2783e5419dd61ea57a02e48e8cc38aa1b357e9b79fa581929b60d8","benches/span_no_fields.rs":"79cc4befacf27d7ce728246087c4f06a6066f913e831d9043caeb7941f0193f6","benches/span_repeated.rs":"e4b3c99a7a9fc15d9042b8db399a56cf647b4eebd26f29d95325bb057b68330b","src/dispatcher.rs":"a8732392ffe56b1178f8fd3d6e6e02d40b51475c38bb4600abd9cd170df1bf6c","src/field.rs":"55c7a2798b9ad0269e7c738c3f15a5d0281bf34ac3a6196a3f0b15801e5278bd","src/instrument.rs":"1fe4de5c13b5ba048e9872d78d1fa4e85655f9f2ed10f79b72b5da881c9b8b45","src/level_filters.rs":"baae8e797897bae9cdd9ec64b8e9a3d71156e9c03261be17b5b18acba034e154","src/lib.rs":"325d0d9487ecd646a7e5e22617f5f291c4112e0e7e359e0033de1677217c5b22","src/macros.rs":"1b38906bcb32cad50b60d350c88f6f4f1fa4d46d99bf50318c44d75219760c42","src/span.rs":"372695b3eda8354a892316826d2598f821fcb835fb18e1e0271767bce730b7ad","src/stdlib.rs":"248514a9bae6106e436358aee44c92abf8e7f79022895c4a25136ddef211d198","src/subscriber.rs":"8933d8766439f929c0a98a0863d20aff37b221314b3825edd9058be511149968","tests/enabled.rs":"1333339aace87ea9d701f2f76a1985820cc513a75013a7ed89669f7a2c635479","tests/event.rs":"7678d1cc8a29ae8b716fbddb7cc4836422732ba3dce109ff511c8bb6100da606","tests/filter_caching_is_lexically_scoped.rs":"5487a37db5fbdf3d57020ab1f01185d928c45d967d99d723ffc434540459d8dc","tests/filters_are_not_reevaluated_for_the_same_span.rs":"251abbc000dddd298448958a1f0e5be71da527ac6c1a368d57837c83a5467329","tests/filters_are_reevaluated_for_different_call_sites.rs":"e0fdd8e930c043674702831b4d96f331e63aba824576bbac50b3f53bb0241cc7","tests/filters_dont_leak.rs":"d594266818a3461886da33bfcc76937d89a433ed6980226fc428706b216c093c","tests/future_send.rs":"3e9c9193219d12e342c18bbedb2f6ec940334202feb3cffba91601d6001b8575","tests/macro_imports.rs":"d5de857162185d4a2384f3cb644bfcf76c7f5c1a3b5f72bfa0d2620ac6e3873c","tests/macros.rs":"fa83397181d73d2cae09c16d9647a63d1e3bad0f2dbc5b3280f69f3d0180c488","tests/macros_incompatible_concat.rs":"5f3bcbb65e4ae39db1cfc2def62fc913c20bab0fb769c8f731504e2615585ee5","tests/macros_redefined_core.rs":"a6eac60522f71fe6c9a040b8b869d596f7eb9e907f5b49f4be4413a40c387676","tests/max_level_hint.rs":"9b366591d947ca0202fa0bdf797e1bb14534d3c896cf8b9674660cd2807c32ef","tests/multiple_max_level_hints.rs":"4d9ef0de9cccc787da8f5e3f6c233ac9db42a2a99cfe5e39997e1f4aa9df0c00","tests/no_subscriber.rs":"2f8f2ada5089d8e2e503394dfe8206598a11895907c53bf940b892f1e6afdd2f","tests/register_callsite_deadlock.rs":"c0b3142543e7a10065c7583a8ee0b6bc978ea4f3979599651101c5a28966e7c8","tests/scoped_clobbers_default.rs":"806480a74c15e4d68bb7576050662b1e53ee765fd583d003f8b349f17ea63a4b","tests/span.rs":"f84ead5b1dad9b91e5cec9d8378ab932a942936374ba928fb381e67fab52cda0","tests/subscriber.rs":"1617c098f4fa6abed174fe062111444c7b67fa0f377d2b342176998e572480e3"},"package":"8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"} \ No newline at end of file
diff --git a/third_party/rust/tracing/CHANGELOG.md b/third_party/rust/tracing/CHANGELOG.md
new file mode 100644
index 0000000000..978e0ca554
--- /dev/null
+++ b/third_party/rust/tracing/CHANGELOG.md
@@ -0,0 +1,806 @@
+# 0.1.37 (October 6, 2022)
+
+This release of `tracing` incorporates changes from `tracing-core`
+[v0.1.30][core-0.1.30] and `tracing-attributes` [v0.1.23][attrs-0.1.23],
+including the new `Subscriber::on_register_dispatch` method for performing late
+initialization after a `Subscriber` is registered as a `Dispatch`, and bugfixes
+for the `#[instrument]` attribute. Additionally, it fixes instances of the
+`bare_trait_objects` lint, which is now a warning on `tracing`'s MSRV and will
+become an error in the next edition.
+
+### Fixed
+
+- **attributes**: Incorrect handling of inner attributes in `#[instrument]`ed
+ functions ([#2307])
+- **attributes**: Incorrect location of compiler diagnostic spans generated for
+ type errors in `#[instrument]`ed `async fn`s ([#2270])
+- **attributes**: Updated `syn` dependency to fix compilation with `-Z
+ minimal-versions` ([#2246])
+- `bare_trait_objects` warning in `valueset!` macro expansion ([#2308])
+
+### Added
+
+- **core**: `Subscriber::on_register_dispatch` method ([#2269])
+- **core**: `WeakDispatch` type and `Dispatch::downgrade()` function ([#2293])
+
+### Changed
+
+- `tracing-core`: updated to [0.1.30][core-0.1.30]
+- `tracing-attributes`: updated to [0.1.23][attrs-0.1.23]
+
+### Documented
+
+- Added [`tracing-web`] and [`reqwest-tracing`] to related crates ([#2283],
+ [#2331])
+
+Thanks to new contributors @compiler-errors, @e-nomem, @WorldSEnder, @Xiami2012,
+and @tl-rodrigo-gryzinski, as well as @jswrenn and @CAD97, for contributing to
+this release!
+
+[core-0.1.30]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.30
+[attrs-0.1.23]: https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.23
+[`tracing-web`]: https://crates.io/crates/tracing-web/
+[`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing/
+[#2246]: https://github.com/tokio-rs/tracing/pull/2246
+[#2269]: https://github.com/tokio-rs/tracing/pull/2269
+[#2283]: https://github.com/tokio-rs/tracing/pull/2283
+[#2270]: https://github.com/tokio-rs/tracing/pull/2270
+[#2293]: https://github.com/tokio-rs/tracing/pull/2293
+[#2307]: https://github.com/tokio-rs/tracing/pull/2307
+[#2308]: https://github.com/tokio-rs/tracing/pull/2308
+[#2331]: https://github.com/tokio-rs/tracing/pull/2331
+
+# 0.1.36 (July 29, 2022)
+
+This release adds support for owned values and fat pointers as arguments to the
+`Span::record` method, as well as updating the minimum `tracing-core` version
+and several documentation improvements.
+
+### Fixed
+
+- Incorrect docs in `dispatcher::set_default` ([#2220])
+- Compilation with `-Z minimal-versions` ([#2246])
+
+### Added
+
+- Support for owned values and fat pointers in `Span::record` ([#2212])
+- Documentation improvements ([#2208], [#2163])
+
+### Changed
+
+- `tracing-core`: updated to [0.1.29][core-0.1.29]
+
+Thanks to @fredr, @cgbur, @jyn514, @matklad, and @CAD97 for contributing to this
+release!
+
+[core-0.1.29]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.29
+[#2220]: https://github.com/tokio-rs/tracing/pull/2220
+[#2246]: https://github.com/tokio-rs/tracing/pull/2246
+[#2212]: https://github.com/tokio-rs/tracing/pull/2212
+[#2208]: https://github.com/tokio-rs/tracing/pull/2208
+[#2163]: https://github.com/tokio-rs/tracing/pull/2163
+
+# 0.1.35 (June 8, 2022)
+
+This release reduces the overhead of callsite registration by using new
+`tracing-core` APIs.
+
+### Added
+
+- Use `DefaultCallsite` to reduce callsite registration overhead ([#2083])
+
+### Changed
+
+- `tracing-core`: updated to [0.1.27][core-0.1.27]
+
+[core-0.1.27]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.27
+[#2088]: https://github.com/tokio-rs/tracing/pull/2083
+
+# 0.1.34 (April 14, 2022)
+
+This release includes bug fixes for the "log" support feature and for the use of
+both scoped and global default dispatchers in the same program.
+
+### Fixed
+
+- Failure to use the global default dispatcher when a thread sets a local
+ default dispatcher before the global default is set ([#2065])
+- **log**: Compilation errors due to `async` block/fn futures becoming `!Send`
+ when the "log" feature flag is enabled ([#2073])
+- Broken links in documentation ([#2068])
+
+Thanks to @ben0x539 for contributing to this release!
+
+[#2065]: https://github.com/tokio-rs/tracing/pull/2065
+[#2073]: https://github.com/tokio-rs/tracing/pull/2073
+[#2068]: https://github.com/tokio-rs/tracing/pull/2068
+
+# 0.1.33 (April 9, 2022)
+
+This release adds new `span_enabled!` and `event_enabled!` variants of the
+`enabled!` macro, for testing whether a subscriber would specifically enable a
+span or an event.
+
+### Added
+
+- `span_enabled!` and `event_enabled!` macros ([#1900])
+- Several documentation improvements ([#2010], [#2012])
+
+### Fixed
+
+- Compilation warning when compiling for <=32-bit targets (including `wasm32`)
+ ([#2060])
+
+Thanks to @guswynn, @arifd, @hrxi, @CAD97, and @name1e5s for contributing to
+this release!
+
+[#1900]: https://github.com/tokio-rs/tracing/pull/1900
+[#2010]: https://github.com/tokio-rs/tracing/pull/2010
+[#2012]: https://github.com/tokio-rs/tracing/pull/2012
+[#2060]: https://github.com/tokio-rs/tracing/pull/2060
+
+# 0.1.32 (March 8th, 2022)
+
+This release reduces the overhead of creating and dropping disabled
+spans significantly, which should improve performance when no `tracing`
+subscriber is in use or when spans are disabled by a filter.
+
+### Fixed
+
+- **attributes**: Compilation failure with `--minimal-versions` due to a
+ too-permissive `syn` dependency ([#1960])
+
+### Changed
+
+- Reduced `Drop` overhead for disabled spans ([#1974])
+- `tracing-attributes`: updated to [0.1.20][attributes-0.1.20]
+
+[#1974]: https://github.com/tokio-rs/tracing/pull/1974
+[#1960]: https://github.com/tokio-rs/tracing/pull/1960
+[attributes-0.1.20]: https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.20
+
+# 0.1.31 (February 17th, 2022)
+
+This release increases the minimum supported Rust version (MSRV) to 1.49.0. In
+addition, it fixes some relatively rare macro bugs.
+
+### Added
+
+- Added `tracing-forest` to the list of related crates ([#1935])
+
+### Changed
+
+- Updated minimum supported Rust version (MSRV) to 1.49.0 ([#1913])
+
+### Fixed
+
+- Fixed the `warn!` macro incorrectly generating an event with the `TRACE` level
+ ([#1930])
+- Fixed macro hygiene issues when used in a crate that defines its own `concat!`
+ macro, for real this time ([#1918])
+
+Thanks to @QnnOkabayashi, @nicolaasg, and @teohhanhui for contributing to this
+release!
+
+[#1935]: https://github.com/tokio-rs/tracing/pull/1935
+[#1913]: https://github.com/tokio-rs/tracing/pull/1913
+[#1930]: https://github.com/tokio-rs/tracing/pull/1930
+[#1918]: https://github.com/tokio-rs/tracing/pull/1918
+
+# 0.1.30 (February 3rd, 2022)
+
+This release adds *experimental* support for recording structured field
+values using the [`valuable`] crate. See [this blog post][post] for
+details on `valuable`.
+
+Note that `valuable` support currently requires `--cfg tracing_unstable`. See
+the documentation for details.
+
+This release also adds a new `enabled!` macro for testing if a span or event
+would be enabled.
+
+### Added
+
+- **field**: Experimental support for recording field values using the
+ [`valuable`] crate ([#1608], [#1888], [#1887])
+- `enabled!` macro for testing if a span or event is enabled ([#1882])
+
+### Changed
+
+- `tracing-core`: updated to [0.1.22][core-0.1.22]
+- `tracing-attributes`: updated to [0.1.19][attributes-0.1.19]
+
+### Fixed
+
+- **log**: Fixed "use of moved value" compiler error when the "log" feature is
+ enabled ([#1823])
+- Fixed macro hygiene issues when used in a crate that defines its own `concat!`
+ macro ([#1842])
+- A very large number of documentation fixes and improvements.
+
+Thanks to @@Vlad-Scherbina, @Skepfyr, @Swatinem, @guswynn, @teohhanhui,
+@xd009642, @tobz, @d-e-s-o@0b01, and @nickelc for contributing to this release!
+
+[`valuable`]: https://crates.io/crates/valuable
+[post]: https://tokio.rs/blog/2021-05-valuable
+[core-0.1.22]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.22
+[attributes-0.1.19]: https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.19
+[#1608]: https://github.com/tokio-rs/tracing/pull/1608
+[#1888]: https://github.com/tokio-rs/tracing/pull/1888
+[#1887]: https://github.com/tokio-rs/tracing/pull/1887
+[#1882]: https://github.com/tokio-rs/tracing/pull/1882
+[#1823]: https://github.com/tokio-rs/tracing/pull/1823
+[#1842]: https://github.com/tokio-rs/tracing/pull/1842
+
+# 0.1.29 (October 5th, 2021)
+
+This release adds support for recording `Option<T> where T: Value` as typed
+`tracing` field values. It also includes significant performance improvements
+for functions annotated with the `#[instrument]` attribute when the generated
+span is disabled.
+
+### Changed
+
+- `tracing-core`: updated to v0.1.21
+- `tracing-attributes`: updated to v0.1.18
+
+### Added
+
+- **field**: `Value` impl for `Option<T> where T: Value` ([#1585])
+- **attributes**: - improved performance when skipping `#[instrument]`-generated
+ spans below the max level ([#1600], [#1605], [#1614], [#1616], [#1617])
+
+### Fixed
+
+- **instrument**: added missing `Future` implementation for `WithSubscriber`,
+ making the `WithDispatch` extension trait actually useable ([#1602])
+- Documentation fixes and improvements ([#1595], [#1601], [#1597])
+
+Thanks to @brianburgers, @mattiast, @DCjanus, @oli-obk, and @matklad for
+contributing to this release!
+
+[#1585]: https://github.com/tokio-rs/tracing/pull/1585
+[#1595]: https://github.com/tokio-rs/tracing/pull/1596
+[#1597]: https://github.com/tokio-rs/tracing/pull/1597
+[#1600]: https://github.com/tokio-rs/tracing/pull/1600
+[#1601]: https://github.com/tokio-rs/tracing/pull/1601
+[#1602]: https://github.com/tokio-rs/tracing/pull/1602
+[#1605]: https://github.com/tokio-rs/tracing/pull/1605
+[#1614]: https://github.com/tokio-rs/tracing/pull/1614
+[#1616]: https://github.com/tokio-rs/tracing/pull/1616
+[#1617]: https://github.com/tokio-rs/tracing/pull/1617
+
+# 0.1.28 (September 17th, 2021)
+
+This release fixes an issue where the RustDoc documentation was rendered
+incorrectly. It doesn't include any actual code changes, and is very boring and
+can be ignored.
+
+### Fixed
+
+- **docs**: Incorrect documentation rendering due to unclosed `<div>` tag
+ ([#1572])
+
+[#1572]: https://github.com/tokio-rs/tracing/pull/1572
+
+# 0.1.27 (September 13, 2021)
+
+This release adds a new [`Span::or_current`] method to aid in efficiently
+propagating span contexts to spawned threads or tasks. Additionally, it updates
+the [`tracing-core`] version to [0.1.20] and the [`tracing-attributes`] version to
+[0.1.16], ensuring that a number of new features in those crates are present.
+
+### Fixed
+
+- **instrument**: Added missing `WithSubscriber` implementations for futures and
+ other types ([#1424])
+
+### Added
+
+- `Span::or_current` method, to help with efficient span context propagation
+ ([#1538])
+- **attributes**: add `skip_all` option to `#[instrument]` ([#1548])
+- **attributes**: record primitive types as primitive values rather than as
+ `fmt::Debug` ([#1378])
+- **core**: `NoSubscriber`, a no-op `Subscriber` implementation
+ ([#1549])
+- **core**: Added `Visit::record_f64` and support for recording floating-point
+ values ([#1507], [#1522])
+- A large number of documentation improvements and fixes ([#1369], [#1398],
+ [#1435], [#1442], [#1524], [#1556])
+
+Thanks to new contributors @dzvon and @mbergkvist, as well as @teozkr,
+@maxburke, @LukeMathWalker, and @jsgf, for contributing to this
+release!
+
+[`Span::or_current`]: https://docs.rs/tracing/0.1.27/tracing/struct.Span.html#method.or_current
+[`tracing-core`]: https://crates.io/crates/tracing-core
+[`tracing-attributes`]: https://crates.io/crates/tracing-attributes
+[`tracing-core`]: https://crates.io/crates/tracing-core
+[0.1.20]: https://github.com/tokio-rs/tracing/releases/tag/tracing-core-0.1.20
+[0.1.16]: https://github.com/tokio-rs/tracing/releases/tag/tracing-attributes-0.1.16
+[#1424]: https://github.com/tokio-rs/tracing/pull/1424
+[#1538]: https://github.com/tokio-rs/tracing/pull/1538
+[#1548]: https://github.com/tokio-rs/tracing/pull/1548
+[#1378]: https://github.com/tokio-rs/tracing/pull/1378
+[#1507]: https://github.com/tokio-rs/tracing/pull/1507
+[#1522]: https://github.com/tokio-rs/tracing/pull/1522
+[#1369]: https://github.com/tokio-rs/tracing/pull/1369
+[#1398]: https://github.com/tokio-rs/tracing/pull/1398
+[#1435]: https://github.com/tokio-rs/tracing/pull/1435
+[#1442]: https://github.com/tokio-rs/tracing/pull/1442
+[#1524]: https://github.com/tokio-rs/tracing/pull/1524
+[#1556]: https://github.com/tokio-rs/tracing/pull/1556
+
+# 0.1.26 (April 30, 2021)
+
+### Fixed
+
+- **attributes**: Compatibility between `#[instrument]` and `async-trait`
+ v0.1.43 and newer ([#1228])
+- Several documentation fixes ([#1305], [#1344])
+### Added
+
+- `Subscriber` impl for `Box<dyn Subscriber + Send + Sync + 'static>` ([#1358])
+- `Subscriber` impl for `Arc<dyn Subscriber + Send + Sync + 'static>` ([#1374])
+- Symmetric `From` impls for existing `Into` impls on `span::Current`, `Span`,
+ and `Option<Id>` ([#1335], [#1338])
+- `From<EnteredSpan>` implementation for `Option<Id>`, allowing `EnteredSpan` to
+ be used in a `span!` macro's `parent:` field ([#1325])
+- `Attributes::fields` accessor that returns the set of fields defined on a
+ span's `Attributes` ([#1331])
+
+
+Thanks to @Folyd, @nightmared, and new contributors @rmsc and @Fishrock123 for
+contributing to this release!
+
+[#1227]: https://github.com/tokio-rs/tracing/pull/1228
+[#1305]: https://github.com/tokio-rs/tracing/pull/1305
+[#1325]: https://github.com/tokio-rs/tracing/pull/1325
+[#1338]: https://github.com/tokio-rs/tracing/pull/1338
+[#1344]: https://github.com/tokio-rs/tracing/pull/1344
+[#1358]: https://github.com/tokio-rs/tracing/pull/1358
+[#1374]: https://github.com/tokio-rs/tracing/pull/1374
+[#1335]: https://github.com/tokio-rs/tracing/pull/1335
+[#1331]: https://github.com/tokio-rs/tracing/pull/1331
+
+# 0.1.25 (February 23, 2021)
+
+### Added
+
+- `Span::entered` method for entering a span and moving it into a guard by value
+ rather than borrowing it ([#1252])
+
+Thanks to @matklad for contributing to this release!
+
+[#1252]: https://github.com/tokio-rs/tracing/pull/1252
+
+# 0.1.24 (February 17, 2021)
+
+### Fixed
+
+- **attributes**: Compiler error when using `#[instrument(err)]` on functions
+ which return `impl Trait` ([#1236])
+- Fixed broken match arms in event macros ([#1239])
+- Documentation improvements ([#1232])
+
+Thanks to @bkchr and @lfranke for contributing to this release!
+
+[#1236]: https://github.com/tokio-rs/tracing/pull/1236
+[#1239]: https://github.com/tokio-rs/tracing/pull/1239
+[#1232]: https://github.com/tokio-rs/tracing/pull/1232
+
+# 0.1.23 (February 4, 2021)
+
+### Fixed
+
+- **attributes**: Compiler error when using `#[instrument(err)]` on functions
+ with mutable parameters ([#1167])
+- **attributes**: Missing function visibility modifier when using
+ `#[instrument]` with `async-trait` ([#977])
+- **attributes** Removed unused `syn` features ([#928])
+- **log**: Fixed an issue where the `tracing` macros would generate code for
+ events whose levels are disabled statically by the `log` crate's
+ `static_max_level_XXX` features ([#1175])
+- Fixed deprecations and clippy lints ([#1195])
+- Several documentation fixes and improvements ([#941], [#965], [#981], [#1146],
+ [#1215])
+
+### Changed
+
+- **attributes**: `tracing-futures` dependency is no longer required when using
+ `#[instrument]` on async functions ([#808])
+- **attributes**: Updated `tracing-attributes` minimum dependency to v0.1.12
+ ([#1222])
+
+Thanks to @nagisa, @Txuritan, @TaKO8Ki, @okready, and @krojew for contributing
+to this release!
+
+[#1167]: https://github.com/tokio-rs/tracing/pull/1167
+[#977]: https://github.com/tokio-rs/tracing/pull/977
+[#965]: https://github.com/tokio-rs/tracing/pull/965
+[#981]: https://github.com/tokio-rs/tracing/pull/981
+[#1215]: https://github.com/tokio-rs/tracing/pull/1215
+[#808]: https://github.com/tokio-rs/tracing/pull/808
+[#941]: https://github.com/tokio-rs/tracing/pull/941
+[#1146]: https://github.com/tokio-rs/tracing/pull/1146
+[#1175]: https://github.com/tokio-rs/tracing/pull/1175
+[#1195]: https://github.com/tokio-rs/tracing/pull/1195
+[#1222]: https://github.com/tokio-rs/tracing/pull/1222
+
+# 0.1.22 (November 23, 2020)
+
+### Changed
+
+- Updated `pin-project-lite` dependency to 0.2 ([#1108])
+
+[#1108]: https://github.com/tokio-rs/tracing/pull/1108
+
+# 0.1.21 (September 28, 2020)
+
+### Fixed
+
+- Incorrect inlining of `Span::new`, `Span::new_root`, and `Span::new_child_of`,
+ which could result in `dispatcher::get_default` being inlined at the callsite
+ ([#994])
+- Regression where using a struct field as a span or event field when other
+ fields on that struct are borrowed mutably would fail to compile ([#987])
+
+### Changed
+
+- Updated `tracing-core` to 0.1.17 ([#992])
+
+### Added
+
+- `Instrument` trait and `Instrumented` type for attaching a `Span` to a
+ `Future` ([#808])
+- `Copy` implementations for `Level` and `LevelFilter` ([#992])
+- Multiple documentation fixes and improvements ([#964], [#980], [#981])
+
+Thanks to @nagisa, and new contributors @SecurityInsanity, @froydnj, @jyn514 and
+@TaKO8Ki for contributing to this release!
+
+[#994]: https://github.com/tokio-rs/tracing/pull/994
+[#992]: https://github.com/tokio-rs/tracing/pull/992
+[#987]: https://github.com/tokio-rs/tracing/pull/987
+[#980]: https://github.com/tokio-rs/tracing/pull/980
+[#981]: https://github.com/tokio-rs/tracing/pull/981
+[#964]: https://github.com/tokio-rs/tracing/pull/964
+[#808]: https://github.com/tokio-rs/tracing/pull/808
+
+# 0.1.20 (August 24, 2020)
+
+### Changed
+
+- Significantly reduced assembly generated by macro invocations (#943)
+- Updated `tracing-core` to 0.1.15 (#943)
+
+### Added
+
+- Documented minimum supported Rust version policy (#941)
+
+# 0.1.19 (August 10, 2020)
+
+### Fixed
+
+- Updated `tracing-core` to fix incorrect calculation of the global max level
+ filter (#908)
+
+### Added
+
+- **attributes**: Support for using `self` in field expressions when
+ instrumenting `async-trait` functions (#875)
+- Several documentation improvements (#832, #881, #896, #897, #911, #913)
+
+Thanks to @anton-dutov, @nightmared, @mystor, and @toshokan for contributing to
+this release!
+
+# 0.1.18 (July 31, 2020)
+
+### Fixed
+
+- Fixed a bug where `LevelFilter::OFF` (and thus also the `static_max_level_off`
+ feature flag) would enable *all* traces, rather than *none* (#853)
+- **log**: Fixed `tracing` macros and `Span`s not checking `log::max_level`
+ before emitting `log` records (#870)
+
+### Changed
+
+- **macros**: Macros now check the global max level (`LevelFilter::current`)
+ before the per-callsite cache when determining if a span or event is enabled.
+ This significantly improves performance in some use cases (#853)
+- **macros**: Simplified the code generated by macro expansion significantly,
+ which may improve compile times and/or `rustc` optimizatation of surrounding
+ code (#869, #869)
+- **macros**: Macros now check the static max level before checking any runtime
+ filtering, improving performance when a span or event is disabled by a
+ `static_max_level_XXX` feature flag (#868)
+- `LevelFilter` is now a re-export of the `tracing_core::LevelFilter` type, it
+ can now be used interchangably with the versions in `tracing-core` and
+ `tracing-subscriber` (#853)
+- Significant performance improvements when comparing `LevelFilter`s and
+ `Level`s (#853)
+- Updated the minimum `tracing-core` dependency to 0.1.12 (#853)
+
+### Added
+
+- **macros**: Quoted string literals may now be used as field names, to allow
+ fields whose names are not valid Rust identifiers (#790)
+- **docs**: Several documentation improvements (#850, #857, #841)
+- `LevelFilter::current()` function, which returns the highest level that any
+ subscriber will enable (#853)
+- `Subscriber::max_level_hint` optional trait method, for setting the value
+ returned by `LevelFilter::current()` (#853)
+
+Thanks to new contributors @cuviper, @ethanboxx, @ben0x539, @dignati,
+@colelawrence, and @rbtcollins for helping out with this release!
+
+# 0.1.17 (July 22, 2020)
+
+### Changed
+
+- **log**: Moved verbose span enter/exit log records to "tracing::span::active"
+ target, allowing them to be filtered separately (#833)
+- **log**: All span lifecycle log records without fields now have the `Trace`
+ log filter, to guard against `log` users enabling them by default with blanket
+ level filtering (#833)
+
+### Fixed
+
+- **log**/**macros**: Fixed missing implicit imports of the
+ `tracing::field::debug` and `tracing::field::display` functions inside the
+ macros when the "log" feature is enabled (#835)
+
+# 0.1.16 (July 8, 2020)
+
+### Added
+
+- **attributes**: Support for arbitrary expressions as fields in `#[instrument]` (#672)
+- **attributes**: `#[instrument]` now emits a compiler warning when ignoring unrecognized
+ input (#672, #786)
+- Improved documentation on using `tracing` in async code (#769)
+
+### Changed
+
+- Updated `tracing-core` dependency to 0.1.11
+
+### Fixed
+
+- **macros**: Excessive monomorphization in macros, which could lead to
+ longer compilation times (#787)
+- **log**: Compiler warnings in macros when `log` or `log-always` features
+ are enabled (#753)
+- Compiler error when `tracing-core/std` feature is enabled but `tracing/std` is
+ not (#760)
+
+Thanks to @nagisa for contributing to this release!
+
+# 0.1.15 (June 2, 2020)
+
+### Changed
+
+- **macros**: Replaced use of legacy `local_inner_macros` with `$crate::` (#740)
+
+### Added
+
+- Docs fixes and improvements (#742, #731, #730)
+
+Thanks to @bnjjj, @blaenk, and @LukeMathWalker for contributing to this release!
+
+# 0.1.14 (May 14, 2020)
+
+### Added
+
+- **log**: When using the [`log`] compatibility feature alongside a `tracing`
+ `Subscriber`, log records for spans now include span IDs (#613)
+- **attributes**: Support for using `#[instrument]` on methods that are part of
+ [`async-trait`] trait implementations (#711)
+- **attributes**: Optional `#[instrument(err)]` argument to automatically emit
+ an event if an instrumented function returns `Err` (#637)
+- Added `#[must_use]` attribute to the guard returned by
+ `subscriber::set_default` (#685)
+
+### Changed
+
+- **log**: Made [`log`] records emitted by spans much less noisy when span IDs are
+ not available (#613)
+
+### Fixed
+
+- Several typos in the documentation (#656, #710, #715)
+
+Thanks to @FintanH, @shepmaster, @inanna-malick, @zekisharif, @bkchr, @majecty,
+@ilana and @nightmared for contributing to this release!
+
+[`async-trait`]: https://crates.io/crates/async-trait
+[`log`]: https://crates.io/crates/log
+
+# 0.1.13 (February 26, 2019)
+
+### Added
+
+- **field**: `field::Empty` type for declaring empty fields whose values will be
+ recorded later (#548)
+- **field**: `field::Value` implementations for `Wrapping` and `NonZero*`
+ numbers (#538)
+- **attributes**: Support for adding arbitrary literal fields to spans generated
+ by `#[instrument]` (#569)
+- **attributes**: `#[instrument]` now emits a helpful compiler error when
+ attempting to skip a function parameter (#600)
+
+### Changed
+
+- **attributes**: The `#[instrument]` attribute was placed under an on-by-default
+ feature flag "attributes" (#603)
+
+### Fixed
+
+- Broken and unresolvable links in RustDoc (#595)
+
+Thanks to @oli-cosmian and @Kobzol for contributing to this release!
+
+# 0.1.12 (January 11, 2019)
+
+### Added
+
+- `Span::with_subscriber` method to access the subscriber that tracks a `Span`
+ (#503)
+- API documentation now shows which features are required by feature-flagged
+ items (#523)
+- Improved README examples (#496)
+- Documentation links to related crates (#507)
+
+# 0.1.11 (December 20, 2019)
+
+### Added
+
+- `Span::is_none` method (#475)
+- `LevelFilter::into_level` method (#470)
+- `LevelFilter::from_level` function and `From<Level>` impl (#471)
+- Documented minimum supported Rust version (#482)
+
+### Fixed
+
+- Incorrect parameter type to `Span::follows_from` that made it impossible to
+ call (#467)
+- Missing whitespace in `log` records generated when enabling the `log` feature
+ flag (#484)
+- Typos and missing links in documentation (#405, #423, #439)
+
+# 0.1.10 (October 23, 2019)
+
+### Added
+
+- Support for destructuring in arguments to `#[instrument]`ed functions (#397)
+- Generated field for `self` parameters when `#[instrument]`ing methods (#397)
+- Optional `skip` argument to `#[instrument]` for excluding function parameters
+ from generated spans (#359)
+- Added `dispatcher::set_default` and `subscriber::set_default` APIs, which
+ return a drop guard (#388)
+
+### Fixed
+
+- Some minor documentation errors (#356, #370)
+
+# 0.1.9 (September 13, 2019)
+
+### Fixed
+
+- Fixed `#[instrument]`ed async functions not compiling on `nightly-2019-09-11`
+ or newer (#342)
+
+### Changed
+
+- Significantly reduced performance impact of skipped spans and events when a
+ `Subscriber` is not in use (#326)
+- The `log` feature will now only cause `tracing` spans and events to emit log
+ records when a `Subscriber` is not in use (#346)
+
+### Added
+
+- Added support for overriding the name of the span generated by `#[instrument]`
+ (#330)
+- `log-always` feature flag to emit log records even when a `Subscriber` is set
+ (#346)
+
+# 0.1.8 (September 3, 2019)
+
+### Changed
+
+- Reorganized and improved API documentation (#317)
+
+### Removed
+
+- Dev-dependencies on `ansi_term` and `humantime` crates, which were used only
+ for examples (#316)
+
+# 0.1.7 (August 30, 2019)
+
+### Changed
+
+- New (curly-brace free) event message syntax to place the message in the first
+ field rather than the last (#309)
+
+### Fixed
+
+- Fixed a regression causing macro stack exhaustion when the `log` feature flag
+ is enabled (#304)
+
+# 0.1.6 (August 20, 2019)
+
+### Added
+
+- `std::error::Error` as a new primitive type (#277)
+- Support for mixing key-value fields and `format_args` messages without curly
+ braces as delimiters (#288)
+
+### Changed
+
+- `tracing-core` dependency to 0.1.5 (#294)
+- `tracing-attributes` dependency to 0.1.2 (#297)
+
+# 0.1.5 (August 9, 2019)
+
+### Added
+
+- Support for `no-std` + `liballoc` (#263)
+
+### Changed
+
+- Using the `#[instrument]` attribute on `async fn`s no longer requires a
+ feature flag (#258)
+
+### Fixed
+
+- The `#[instrument]` macro now works on generic functions (#262)
+
+# 0.1.4 (August 8, 2019)
+
+### Added
+
+- `#[instrument]` attribute for automatically adding spans to functions (#253)
+
+# 0.1.3 (July 11, 2019)
+
+### Added
+
+- Log messages when a subscriber indicates that a span has closed, when the
+ `log` feature flag is enabled (#180).
+
+### Changed
+
+- `tracing-core` minimum dependency version to 0.1.2 (#174).
+
+### Fixed
+
+- Fixed an issue where event macro invocations with a single field, using local
+ variable shorthand, would recur infinitely (#166).
+- Fixed uses of deprecated `tracing-core` APIs (#174).
+
+# 0.1.2 (July 6, 2019)
+
+### Added
+
+- `Span::none()` constructor, which does not require metadata and
+ returns a completely empty span (#147).
+- `Span::current()` function, returning the current span if it is
+ known to the subscriber (#148).
+
+### Fixed
+
+- Broken macro imports when used prefixed with `tracing::` (#152).
+
+# 0.1.1 (July 3, 2019)
+
+### Changed
+
+- `cfg_if` dependency to 0.1.9.
+
+### Fixed
+
+- Compilation errors when the `log` feature is enabled (#131).
+- Unclear wording and typos in documentation (#124, #128, #142).
+
+# 0.1.0 (June 27, 2019)
+
+- Initial release
diff --git a/third_party/rust/tracing/Cargo.toml b/third_party/rust/tracing/Cargo.toml
new file mode 100644
index 0000000000..90f084d8ed
--- /dev/null
+++ b/third_party/rust/tracing/Cargo.toml
@@ -0,0 +1,142 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2018"
+rust-version = "1.49.0"
+name = "tracing"
+version = "0.1.37"
+authors = [
+ "Eliza Weisman <eliza@buoyant.io>",
+ "Tokio Contributors <team@tokio.rs>",
+]
+description = """
+Application-level tracing for Rust.
+"""
+homepage = "https://tokio.rs"
+readme = "README.md"
+keywords = [
+ "logging",
+ "tracing",
+ "metrics",
+ "async",
+]
+categories = [
+ "development-tools::debugging",
+ "development-tools::profiling",
+ "asynchronous",
+ "no-std",
+]
+license = "MIT"
+repository = "https://github.com/tokio-rs/tracing"
+
+[package.metadata.docs.rs]
+all-features = true
+rustdoc-args = [
+ "--cfg",
+ "docsrs",
+ "--cfg",
+ "tracing_unstable",
+]
+rustc-args = [
+ "--cfg",
+ "tracing_unstable",
+]
+
+[[bench]]
+name = "baseline"
+harness = false
+
+[[bench]]
+name = "dispatch_get_clone"
+harness = false
+
+[[bench]]
+name = "dispatch_get_ref"
+harness = false
+
+[[bench]]
+name = "empty_span"
+harness = false
+
+[[bench]]
+name = "enter_span"
+harness = false
+
+[[bench]]
+name = "event"
+harness = false
+
+[[bench]]
+name = "span_fields"
+harness = false
+
+[[bench]]
+name = "span_no_fields"
+harness = false
+
+[[bench]]
+name = "span_repeated"
+harness = false
+
+[dependencies.cfg-if]
+version = "1.0.0"
+
+[dependencies.log]
+version = "0.4.17"
+optional = true
+
+[dependencies.pin-project-lite]
+version = "0.2.9"
+
+[dependencies.tracing-attributes]
+version = "0.1.23"
+optional = true
+
+[dependencies.tracing-core]
+version = "0.1.30"
+default-features = false
+
+[dev-dependencies.criterion]
+version = "0.3.6"
+default-features = false
+
+[dev-dependencies.log]
+version = "0.4.17"
+
+[features]
+async-await = []
+attributes = ["tracing-attributes"]
+default = [
+ "std",
+ "attributes",
+]
+log-always = ["log"]
+max_level_debug = []
+max_level_error = []
+max_level_info = []
+max_level_off = []
+max_level_trace = []
+max_level_warn = []
+release_max_level_debug = []
+release_max_level_error = []
+release_max_level_info = []
+release_max_level_off = []
+release_max_level_trace = []
+release_max_level_warn = []
+std = ["tracing-core/std"]
+valuable = ["tracing-core/valuable"]
+
+[target."cfg(target_arch = \"wasm32\")".dev-dependencies.wasm-bindgen-test]
+version = "^0.3"
+
+[badges.maintenance]
+status = "actively-developed"
diff --git a/third_party/rust/tracing/LICENSE b/third_party/rust/tracing/LICENSE
new file mode 100644
index 0000000000..cdb28b4b56
--- /dev/null
+++ b/third_party/rust/tracing/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2019 Tokio Contributors
+
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/third_party/rust/tracing/README.md b/third_party/rust/tracing/README.md
new file mode 100644
index 0000000000..6947345771
--- /dev/null
+++ b/third_party/rust/tracing/README.md
@@ -0,0 +1,465 @@
+![Tracing — Structured, application-level diagnostics][splash]
+
+[splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg
+
+# tracing
+
+Application-level tracing for Rust.
+
+[![Crates.io][crates-badge]][crates-url]
+[![Documentation][docs-badge]][docs-url]
+[![Documentation (master)][docs-master-badge]][docs-master-url]
+[![MIT licensed][mit-badge]][mit-url]
+[![Build Status][actions-badge]][actions-url]
+[![Discord chat][discord-badge]][discord-url]
+
+[Documentation][docs-url] | [Chat][discord-url]
+
+[crates-badge]: https://img.shields.io/crates/v/tracing.svg
+[crates-url]: https://crates.io/crates/tracing
+[docs-badge]: https://docs.rs/tracing/badge.svg
+[docs-url]: https://docs.rs/tracing
+[docs-master-badge]: https://img.shields.io/badge/docs-master-blue
+[docs-master-url]: https://tracing-rs.netlify.com/tracing
+[mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg
+[mit-url]: LICENSE
+[actions-badge]: https://github.com/tokio-rs/tracing/workflows/CI/badge.svg
+[actions-url]:https://github.com/tokio-rs/tracing/actions?query=workflow%3ACI
+[discord-badge]: https://img.shields.io/discord/500028886025895936?logo=discord&label=discord&logoColor=white
+[discord-url]: https://discord.gg/EeF3cQw
+
+## Overview
+
+`tracing` is a framework for instrumenting Rust programs to collect
+structured, event-based diagnostic information.
+
+In asynchronous systems like Tokio, interpreting traditional log messages can
+often be quite challenging. Since individual tasks are multiplexed on the same
+thread, associated events and log lines are intermixed making it difficult to
+trace the logic flow. `tracing` expands upon logging-style diagnostics by
+allowing libraries and applications to record structured events with additional
+information about *temporality* and *causality* — unlike a log message, a span
+in `tracing` has a beginning and end time, may be entered and exited by the
+flow of execution, and may exist within a nested tree of similar spans. In
+addition, `tracing` spans are *structured*, with the ability to record typed
+data as well as textual messages.
+
+The `tracing` crate provides the APIs necessary for instrumenting libraries
+and applications to emit trace data.
+
+*Compiler support: [requires `rustc` 1.49+][msrv]*
+
+[msrv]: #supported-rust-versions
+
+## Usage
+
+(The examples below are borrowed from the `log` crate's yak-shaving
+[example](https://docs.rs/log/0.4.10/log/index.html#examples), modified to
+idiomatic `tracing`.)
+
+### In Applications
+
+In order to record trace events, executables have to use a `Subscriber`
+implementation compatible with `tracing`. A `Subscriber` implements a way of
+collecting trace data, such as by logging it to standard output. [`tracing_subscriber`](https://docs.rs/tracing-subscriber/)'s
+[`fmt` module](https://docs.rs/tracing-subscriber/0.3/tracing_subscriber/fmt/index.html) provides reasonable defaults.
+Additionally, `tracing-subscriber` is able to consume messages emitted by `log`-instrumented libraries and modules.
+
+The simplest way to use a subscriber is to call the `set_global_default` function.
+
+```rust
+use tracing::{info, Level};
+use tracing_subscriber::FmtSubscriber;
+
+fn main() {
+ // a builder for `FmtSubscriber`.
+ let subscriber = FmtSubscriber::builder()
+ // all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.)
+ // will be written to stdout.
+ .with_max_level(Level::TRACE)
+ // completes the builder.
+ .finish();
+
+ tracing::subscriber::set_global_default(subscriber)
+ .expect("setting default subscriber failed");
+
+ let number_of_yaks = 3;
+ // this creates a new event, outside of any spans.
+ info!(number_of_yaks, "preparing to shave yaks");
+
+ let number_shaved = yak_shave::shave_all(number_of_yaks);
+ info!(
+ all_yaks_shaved = number_shaved == number_of_yaks,
+ "yak shaving completed."
+ );
+}
+```
+
+```toml
+[dependencies]
+tracing = "0.1"
+tracing-subscriber = "0.2.0"
+```
+
+This subscriber will be used as the default in all threads for the remainder of the duration
+of the program, similar to how loggers work in the `log` crate.
+
+In addition, you can locally override the default subscriber. For example:
+
+```rust
+use tracing::{info, Level};
+use tracing_subscriber::FmtSubscriber;
+
+fn main() {
+ let subscriber = tracing_subscriber::FmtSubscriber::builder()
+ // all spans/events with a level higher than TRACE (e.g, debug, info, warn, etc.)
+ // will be written to stdout.
+ .with_max_level(Level::TRACE)
+ // builds the subscriber.
+ .finish();
+
+ tracing::subscriber::with_default(subscriber, || {
+ info!("This will be logged to stdout");
+ });
+ info!("This will _not_ be logged to stdout");
+}
+```
+
+This approach allows trace data to be collected by multiple subscribers
+within different contexts in the program. Note that the override only applies to the
+currently executing thread; other threads will not see the change from with_default.
+
+Any trace events generated outside the context of a subscriber will not be collected.
+
+Once a subscriber has been set, instrumentation points may be added to the
+executable using the `tracing` crate's macros.
+
+### In Libraries
+
+Libraries should only rely on the `tracing` crate and use the provided macros
+and types to collect whatever information might be useful to downstream consumers.
+
+```rust
+use std::{error::Error, io};
+use tracing::{debug, error, info, span, warn, Level};
+
+// the `#[tracing::instrument]` attribute creates and enters a span
+// every time the instrumented function is called. The span is named after the
+// the function or method. Paramaters passed to the function are recorded as fields.
+#[tracing::instrument]
+pub fn shave(yak: usize) -> Result<(), Box<dyn Error + 'static>> {
+ // this creates an event at the DEBUG level with two fields:
+ // - `excitement`, with the key "excitement" and the value "yay!"
+ // - `message`, with the key "message" and the value "hello! I'm gonna shave a yak."
+ //
+ // unlike other fields, `message`'s shorthand initialization is just the string itself.
+ debug!(excitement = "yay!", "hello! I'm gonna shave a yak.");
+ if yak == 3 {
+ warn!("could not locate yak!");
+ // note that this is intended to demonstrate `tracing`'s features, not idiomatic
+ // error handling! in a library or application, you should consider returning
+ // a dedicated `YakError`. libraries like snafu or thiserror make this easy.
+ return Err(io::Error::new(io::ErrorKind::Other, "shaving yak failed!").into());
+ } else {
+ debug!("yak shaved successfully");
+ }
+ Ok(())
+}
+
+pub fn shave_all(yaks: usize) -> usize {
+ // Constructs a new span named "shaving_yaks" at the TRACE level,
+ // and a field whose key is "yaks". This is equivalent to writing:
+ //
+ // let span = span!(Level::TRACE, "shaving_yaks", yaks = yaks);
+ //
+ // local variables (`yaks`) can be used as field values
+ // without an assignment, similar to struct initializers.
+ let _span_ = span!(Level::TRACE, "shaving_yaks", yaks).entered();
+
+ info!("shaving yaks");
+
+ let mut yaks_shaved = 0;
+ for yak in 1..=yaks {
+ let res = shave(yak);
+ debug!(yak, shaved = res.is_ok());
+
+ if let Err(ref error) = res {
+ // Like spans, events can also use the field initialization shorthand.
+ // In this instance, `yak` is the field being initalized.
+ error!(yak, error = error.as_ref(), "failed to shave yak!");
+ } else {
+ yaks_shaved += 1;
+ }
+ debug!(yaks_shaved);
+ }
+
+ yaks_shaved
+}
+```
+
+```toml
+[dependencies]
+tracing = "0.1"
+```
+
+Note: Libraries should *NOT* call `set_global_default()`, as this will cause
+conflicts when executables try to set the default later.
+
+### In Asynchronous Code
+
+If you are instrumenting code that make use of
+[`std::future::Future`](https://doc.rust-lang.org/stable/std/future/trait.Future.html)
+or async/await, avoid using the `Span::enter` method. The following example
+_will not_ work:
+
+```rust
+async {
+ let _s = span.enter();
+ // ...
+}
+```
+```rust
+async {
+ let _s = tracing::span!(...).entered();
+ // ...
+}
+```
+
+The span guard `_s` will not exit until the future generated by the `async` block is complete.
+Since futures and spans can be entered and exited _multiple_ times without them completing,
+the span remains entered for as long as the future exists, rather than being entered only when
+it is polled, leading to very confusing and incorrect output.
+For more details, see [the documentation on closing spans](https://tracing.rs/tracing/span/index.html#closing-spans).
+
+There are two ways to instrument asynchronous code. The first is through the
+[`Future::instrument`](https://docs.rs/tracing/latest/tracing/trait.Instrument.html#method.instrument) combinator:
+
+```rust
+use tracing::Instrument;
+
+let my_future = async {
+ // ...
+};
+
+my_future
+ .instrument(tracing::info_span!("my_future"))
+ .await
+```
+
+`Future::instrument` attaches a span to the future, ensuring that the span's lifetime
+is as long as the future's.
+
+The second, and preferred, option is through the
+[`#[instrument]`](https://docs.rs/tracing/0.1.37/tracing/attr.instrument.html)
+attribute:
+
+```rust
+use tracing::{info, instrument};
+use tokio::{io::AsyncWriteExt, net::TcpStream};
+use std::io;
+
+#[instrument]
+async fn write(stream: &mut TcpStream) -> io::Result<usize> {
+ let result = stream.write(b"hello world\n").await;
+ info!("wrote to stream; success={:?}", result.is_ok());
+ result
+}
+```
+
+Under the hood, the `#[instrument]` macro performs the same explicit span
+attachment that `Future::instrument` does.
+
+### Concepts
+
+This crate provides macros for creating `Span`s and `Event`s, which represent
+periods of time and momentary events within the execution of a program,
+respectively.
+
+As a rule of thumb, _spans_ should be used to represent discrete units of work
+(e.g., a given request's lifetime in a server) or periods of time spent in a
+given context (e.g., time spent interacting with an instance of an external
+system, such as a database). In contrast, _events_ should be used to represent
+points in time within a span — a request returned with a given status code,
+_n_ new items were taken from a queue, and so on.
+
+`Span`s are constructed using the `span!` macro, and then _entered_
+to indicate that some code takes place within the context of that `Span`:
+
+```rust
+use tracing::{span, Level};
+
+// Construct a new span named "my span".
+let mut span = span!(Level::INFO, "my span");
+span.in_scope(|| {
+ // Any trace events in this closure or code called by it will occur within
+ // the span.
+});
+// Dropping the span will close it, indicating that it has ended.
+```
+
+The [`#[instrument]`](https://docs.rs/tracing/0.1.37/tracing/attr.instrument.html) attribute macro
+can reduce some of this boilerplate:
+
+```rust
+use tracing::{instrument};
+
+#[instrument]
+pub fn my_function(my_arg: usize) {
+ // This event will be recorded inside a span named `my_function` with the
+ // field `my_arg`.
+ tracing::info!("inside my_function!");
+ // ...
+}
+```
+
+The `Event` type represent an event that occurs instantaneously, and is
+essentially a `Span` that cannot be entered. They are created using the `event!`
+macro:
+
+```rust
+use tracing::{event, Level};
+
+event!(Level::INFO, "something has happened!");
+```
+
+Users of the [`log`] crate should note that `tracing` exposes a set of macros for
+creating `Event`s (`trace!`, `debug!`, `info!`, `warn!`, and `error!`) which may
+be invoked with the same syntax as the similarly-named macros from the `log`
+crate. Often, the process of converting a project to use `tracing` can begin
+with a simple drop-in replacement.
+
+## Supported Rust Versions
+
+Tracing is built against the latest stable release. The minimum supported
+version is 1.42. The current Tracing version is not guaranteed to build on Rust
+versions earlier than the minimum supported version.
+
+Tracing follows the same compiler support policies as the rest of the Tokio
+project. The current stable Rust compiler and the three most recent minor
+versions before it will always be supported. For example, if the current stable
+compiler version is 1.45, the minimum supported version will not be increased
+past 1.42, three minor versions prior. Increasing the minimum supported compiler
+version is not considered a semver breaking change as long as doing so complies
+with this policy.
+
+## Ecosystem
+
+### Related Crates
+
+In addition to `tracing` and `tracing-core`, the [`tokio-rs/tracing`] repository
+contains several additional crates designed to be used with the `tracing` ecosystem.
+This includes a collection of `Subscriber` implementations, as well as utility
+and adapter crates to assist in writing `Subscriber`s and instrumenting
+applications.
+
+In particular, the following crates are likely to be of interest:
+
+- [`tracing-futures`] provides a compatibility layer with the `futures`
+ crate, allowing spans to be attached to `Future`s, `Stream`s, and `Executor`s.
+- [`tracing-subscriber`] provides `Subscriber` implementations and
+ utilities for working with `Subscriber`s. This includes a [`FmtSubscriber`]
+ `FmtSubscriber` for logging formatted trace data to stdout, with similar
+ filtering and formatting to the [`env_logger`] crate.
+- [`tracing-log`] provides a compatibility layer with the [`log`] crate,
+ allowing log messages to be recorded as `tracing` `Event`s within the
+ trace tree. This is useful when a project using `tracing` have
+ dependencies which use `log`. Note that if you're using
+ `tracing-subscriber`'s `FmtSubscriber`, you don't need to depend on
+ `tracing-log` directly.
+
+Additionally, there are also several third-party crates which are not
+maintained by the `tokio` project. These include:
+
+- [`tracing-timing`] implements inter-event timing metrics on top of `tracing`.
+ It provides a subscriber that records the time elapsed between pairs of
+ `tracing` events and generates histograms.
+- [`tracing-opentelemetry`] provides a subscriber for emitting traces to
+ [OpenTelemetry]-compatible distributed tracing systems.
+- [`tracing-honeycomb`] Provides a layer that reports traces spanning multiple machines to [honeycomb.io]. Backed by [`tracing-distributed`].
+- [`tracing-distributed`] Provides a generic implementation of a layer that reports traces spanning multiple machines to some backend.
+- [`tracing-actix`] provides `tracing` integration for the `actix` actor
+ framework.
+- [`tracing-gelf`] implements a subscriber for exporting traces in Greylog
+ GELF format.
+- [`tracing-coz`] provides integration with the [coz] causal profiler
+ (Linux-only).
+- [`test-log`] takes care of initializing `tracing` for tests, based on
+ environment variables with an `env_logger` compatible syntax.
+- [`tracing-unwrap`] provides convenience methods to report failed unwraps on `Result` or `Option` types to a `Subscriber`.
+- [`diesel-tracing`] provides integration with [`diesel`] database connections.
+- [`tracing-tracy`] provides a way to collect [Tracy] profiles in instrumented
+ applications.
+- [`tracing-elastic-apm`] provides a layer for reporting traces to [Elastic APM].
+- [`tracing-etw`] provides a layer for emitting Windows [ETW] events.
+- [`tracing-fluent-assertions`] provides a fluent assertions-style testing
+ framework for validating the behavior of `tracing` spans.
+- [`sentry-tracing`] provides a layer for reporting events and traces to [Sentry].
+- [`tracing-loki`] provides a layer for shipping logs to [Grafana Loki].
+- [`tracing-logfmt`] provides a layer that formats events and spans into the logfmt format.
+
+If you're the maintainer of a `tracing` ecosystem crate not listed above,
+please let us know! We'd love to add your project to the list!
+
+[`tracing-timing`]: https://crates.io/crates/tracing-timing
+[`tracing-opentelemetry`]: https://crates.io/crates/tracing-opentelemetry
+[OpenTelemetry]: https://opentelemetry.io/
+[`tracing-honeycomb`]: https://crates.io/crates/tracing-honeycomb
+[`tracing-distributed`]: https://crates.io/crates/tracing-distributed
+[honeycomb.io]: https://www.honeycomb.io/
+[`tracing-actix`]: https://crates.io/crates/tracing-actix
+[`tracing-gelf`]: https://crates.io/crates/tracing-gelf
+[`tracing-coz`]: https://crates.io/crates/tracing-coz
+[coz]: https://github.com/plasma-umass/coz
+[`test-log`]: https://crates.io/crates/test-log
+[`tracing-unwrap`]: https://docs.rs/tracing-unwrap
+[`diesel`]: https://crates.io/crates/diesel
+[`diesel-tracing`]: https://crates.io/crates/diesel-tracing
+[`tracing-tracy`]: https://crates.io/crates/tracing-tracy
+[Tracy]: https://github.com/wolfpld/tracy
+[`tracing-elastic-apm`]: https://crates.io/crates/tracing-elastic-apm
+[Elastic APM]: https://www.elastic.co/apm
+[`tracing-etw`]: https://github.com/microsoft/tracing-etw
+[ETW]: https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing
+[`tracing-fluent-assertions`]: https://crates.io/crates/tracing-fluent-assertions
+[`sentry-tracing`]: https://crates.io/crates/sentry-tracing
+[Sentry]: https://sentry.io/welcome/
+[`tracing-loki`]: https://crates.io/crates/tracing-loki
+[Grafana Loki]: https://grafana.com/oss/loki/
+[`tracing-logfmt`]: https://crates.io/crates/tracing-logfmt
+
+**Note:** that some of the ecosystem crates are currently unreleased and
+undergoing active development. They may be less stable than `tracing` and
+`tracing-core`.
+
+[`log`]: https://docs.rs/log/0.4.6/log/
+[`tokio-rs/tracing`]: https://github.com/tokio-rs/tracing
+[`tracing-futures`]: https://github.com/tokio-rs/tracing/tree/master/tracing-futures
+[`tracing-subscriber`]: https://github.com/tokio-rs/tracing/tree/master/tracing-subscriber
+[`tracing-log`]: https://github.com/tokio-rs/tracing/tree/master/tracing-log
+[`env_logger`]: https://crates.io/crates/env_logger
+[`FmtSubscriber`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/struct.Subscriber.html
+[`examples`]: https://github.com/tokio-rs/tracing/tree/master/examples
+
+## Supported Rust Versions
+
+Tracing is built against the latest stable release. The minimum supported
+version is 1.49. The current Tracing version is not guaranteed to build on Rust
+versions earlier than the minimum supported version.
+
+Tracing follows the same compiler support policies as the rest of the Tokio
+project. The current stable Rust compiler and the three most recent minor
+versions before it will always be supported. For example, if the current stable
+compiler version is 1.45, the minimum supported version will not be increased
+past 1.42, three minor versions prior. Increasing the minimum supported compiler
+version is not considered a semver breaking change as long as doing so complies
+with this policy.
+
+## License
+
+This project is licensed under the [MIT license](LICENSE).
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted
+for inclusion in Tokio by you, shall be licensed as MIT, without any additional
+terms or conditions.
diff --git a/third_party/rust/tracing/benches/baseline.rs b/third_party/rust/tracing/benches/baseline.rs
new file mode 100644
index 0000000000..93c14f422c
--- /dev/null
+++ b/third_party/rust/tracing/benches/baseline.rs
@@ -0,0 +1,24 @@
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+
+fn bench(c: &mut Criterion) {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+
+ let mut group = c.benchmark_group("comparison");
+ group.bench_function("relaxed_load", |b| {
+ let foo = AtomicUsize::new(1);
+ b.iter(|| black_box(foo.load(Ordering::Relaxed)));
+ });
+ group.bench_function("acquire_load", |b| {
+ let foo = AtomicUsize::new(1);
+ b.iter(|| black_box(foo.load(Ordering::Acquire)))
+ });
+ group.bench_function("log", |b| {
+ b.iter(|| {
+ log::log!(log::Level::Info, "log");
+ })
+ });
+ group.finish();
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/dispatch_get_clone.rs b/third_party/rust/tracing/benches/dispatch_get_clone.rs
new file mode 100644
index 0000000000..15577c6969
--- /dev/null
+++ b/third_party/rust/tracing/benches/dispatch_get_clone.rs
@@ -0,0 +1,15 @@
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ shared::for_all_dispatches(&mut c.benchmark_group("Dispatch::get_clone"), |b| {
+ b.iter(|| {
+ let current = tracing::dispatcher::get_default(|current| current.clone());
+ black_box(current);
+ })
+ });
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/dispatch_get_ref.rs b/third_party/rust/tracing/benches/dispatch_get_ref.rs
new file mode 100644
index 0000000000..a59c343795
--- /dev/null
+++ b/third_party/rust/tracing/benches/dispatch_get_ref.rs
@@ -0,0 +1,16 @@
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ shared::for_all_dispatches(&mut c.benchmark_group("Dispatch::get_ref"), |b| {
+ b.iter(|| {
+ tracing::dispatcher::get_default(|current| {
+ black_box(&current);
+ })
+ })
+ });
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/empty_span.rs b/third_party/rust/tracing/benches/empty_span.rs
new file mode 100644
index 0000000000..fb38b08e15
--- /dev/null
+++ b/third_party/rust/tracing/benches/empty_span.rs
@@ -0,0 +1,43 @@
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ let mut group = c.benchmark_group("empty_span");
+ shared::for_all_dispatches(&mut group, |b| {
+ b.iter(|| {
+ let span = tracing::span::Span::none();
+ black_box(&span);
+ })
+ });
+ group.bench_function("baseline_struct", |b| {
+ b.iter(|| {
+ let span = FakeEmptySpan::new();
+ black_box(&span);
+ })
+ });
+}
+
+struct FakeEmptySpan {
+ inner: Option<(usize, std::sync::Arc<()>)>,
+ meta: Option<&'static ()>,
+}
+
+impl FakeEmptySpan {
+ fn new() -> Self {
+ Self {
+ inner: None,
+ meta: None,
+ }
+ }
+}
+
+impl Drop for FakeEmptySpan {
+ fn drop(&mut self) {
+ black_box(&self.inner);
+ black_box(&self.meta);
+ }
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/enter_span.rs b/third_party/rust/tracing/benches/enter_span.rs
new file mode 100644
index 0000000000..757350a539
--- /dev/null
+++ b/third_party/rust/tracing/benches/enter_span.rs
@@ -0,0 +1,16 @@
+use criterion::{criterion_group, criterion_main, Criterion};
+use tracing::{span, Level};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ shared::for_all_dispatches(&mut c.benchmark_group("enter_span"), |b| {
+ let span = span!(Level::TRACE, "span");
+ b.iter(|| {
+ let _span = span.enter();
+ })
+ });
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/event.rs b/third_party/rust/tracing/benches/event.rs
new file mode 100644
index 0000000000..1649325482
--- /dev/null
+++ b/third_party/rust/tracing/benches/event.rs
@@ -0,0 +1,12 @@
+use criterion::{criterion_group, criterion_main, Criterion};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ shared::for_all_recording(&mut c.benchmark_group("event"), |b| {
+ b.iter(|| tracing::info!("hello world!"))
+ });
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/shared.rs b/third_party/rust/tracing/benches/shared.rs
new file mode 100644
index 0000000000..56508c4ab7
--- /dev/null
+++ b/third_party/rust/tracing/benches/shared.rs
@@ -0,0 +1,160 @@
+#![allow(dead_code)]
+use criterion::{black_box, measurement::WallTime, Bencher};
+use tracing::{field, span, Event, Id, Metadata};
+
+use std::{
+ fmt::{self, Write},
+ sync::{Mutex, MutexGuard},
+};
+
+pub fn for_all_recording(
+ group: &mut criterion::BenchmarkGroup<'_, WallTime>,
+ mut iter: impl FnMut(&mut Bencher<'_, WallTime>),
+) {
+ // first, run benchmarks with no subscriber
+ group.bench_function("none", &mut iter);
+
+ // then, run benchmarks with a scoped default subscriber
+ tracing::subscriber::with_default(EnabledSubscriber, || {
+ group.bench_function("scoped", &mut iter)
+ });
+
+ let subscriber = VisitingSubscriber(Mutex::new(String::from("")));
+ tracing::subscriber::with_default(subscriber, || {
+ group.bench_function("scoped_recording", &mut iter);
+ });
+
+ // finally, set a global default subscriber, and run the benchmarks again.
+ tracing::subscriber::set_global_default(EnabledSubscriber)
+ .expect("global default should not have already been set!");
+ let _ = log::set_logger(&NOP_LOGGER);
+ log::set_max_level(log::LevelFilter::Trace);
+ group.bench_function("global", &mut iter);
+}
+
+pub fn for_all_dispatches(
+ group: &mut criterion::BenchmarkGroup<'_, WallTime>,
+ mut iter: impl FnMut(&mut Bencher<'_, WallTime>),
+) {
+ // first, run benchmarks with no subscriber
+ group.bench_function("none", &mut iter);
+
+ // then, run benchmarks with a scoped default subscriber
+ tracing::subscriber::with_default(EnabledSubscriber, || {
+ group.bench_function("scoped", &mut iter)
+ });
+
+ // finally, set a global default subscriber, and run the benchmarks again.
+ tracing::subscriber::set_global_default(EnabledSubscriber)
+ .expect("global default should not have already been set!");
+ let _ = log::set_logger(&NOP_LOGGER);
+ log::set_max_level(log::LevelFilter::Trace);
+ group.bench_function("global", &mut iter);
+}
+
+const NOP_LOGGER: NopLogger = NopLogger;
+
+struct NopLogger;
+
+impl log::Log for NopLogger {
+ fn enabled(&self, _metadata: &log::Metadata) -> bool {
+ true
+ }
+
+ fn log(&self, record: &log::Record) {
+ if self.enabled(record.metadata()) {
+ let mut this = self;
+ let _ = write!(this, "{}", record.args());
+ }
+ }
+
+ fn flush(&self) {}
+}
+
+impl Write for &NopLogger {
+ fn write_str(&mut self, s: &str) -> std::fmt::Result {
+ black_box(s);
+ Ok(())
+ }
+}
+
+/// Simulates a subscriber that records span data.
+struct VisitingSubscriber(Mutex<String>);
+
+struct Visitor<'a>(MutexGuard<'a, String>);
+
+impl<'a> field::Visit for Visitor<'a> {
+ fn record_debug(&mut self, _field: &field::Field, value: &dyn fmt::Debug) {
+ let _ = write!(&mut *self.0, "{:?}", value);
+ }
+}
+
+impl tracing::Subscriber for VisitingSubscriber {
+ fn new_span(&self, span: &span::Attributes<'_>) -> Id {
+ let mut visitor = Visitor(self.0.lock().unwrap());
+ span.record(&mut visitor);
+ Id::from_u64(0xDEAD_FACE)
+ }
+
+ fn record(&self, _span: &Id, values: &span::Record<'_>) {
+ let mut visitor = Visitor(self.0.lock().unwrap());
+ values.record(&mut visitor);
+ }
+
+ fn event(&self, event: &Event<'_>) {
+ let mut visitor = Visitor(self.0.lock().unwrap());
+ event.record(&mut visitor);
+ }
+
+ fn record_follows_from(&self, span: &Id, follows: &Id) {
+ let _ = (span, follows);
+ }
+
+ fn enabled(&self, metadata: &Metadata<'_>) -> bool {
+ let _ = metadata;
+ true
+ }
+
+ fn enter(&self, span: &Id) {
+ let _ = span;
+ }
+
+ fn exit(&self, span: &Id) {
+ let _ = span;
+ }
+}
+
+/// A subscriber that is enabled but otherwise does nothing.
+struct EnabledSubscriber;
+
+impl tracing::Subscriber for EnabledSubscriber {
+ fn new_span(&self, span: &span::Attributes<'_>) -> Id {
+ let _ = span;
+ Id::from_u64(0xDEAD_FACE)
+ }
+
+ fn event(&self, event: &Event<'_>) {
+ let _ = event;
+ }
+
+ fn record(&self, span: &Id, values: &span::Record<'_>) {
+ let _ = (span, values);
+ }
+
+ fn record_follows_from(&self, span: &Id, follows: &Id) {
+ let _ = (span, follows);
+ }
+
+ fn enabled(&self, metadata: &Metadata<'_>) -> bool {
+ let _ = metadata;
+ true
+ }
+
+ fn enter(&self, span: &Id) {
+ let _ = span;
+ }
+
+ fn exit(&self, span: &Id) {
+ let _ = span;
+ }
+}
diff --git a/third_party/rust/tracing/benches/span_fields.rs b/third_party/rust/tracing/benches/span_fields.rs
new file mode 100644
index 0000000000..5ad8289826
--- /dev/null
+++ b/third_party/rust/tracing/benches/span_fields.rs
@@ -0,0 +1,23 @@
+use criterion::{criterion_group, criterion_main, Criterion};
+use tracing::{span, Level};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ shared::for_all_recording(&mut c.benchmark_group("span_fields"), |b| {
+ b.iter(|| {
+ let span = span!(
+ Level::TRACE,
+ "span",
+ foo = "foo",
+ bar = "bar",
+ baz = 3,
+ quuux = tracing::field::debug(0.99)
+ );
+ criterion::black_box(span)
+ })
+ });
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/span_no_fields.rs b/third_party/rust/tracing/benches/span_no_fields.rs
new file mode 100644
index 0000000000..8a1ff6e041
--- /dev/null
+++ b/third_party/rust/tracing/benches/span_no_fields.rs
@@ -0,0 +1,13 @@
+use criterion::{criterion_group, criterion_main, Criterion};
+use tracing::{span, Level};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ shared::for_all_recording(&mut c.benchmark_group("span_no_fields"), |b| {
+ b.iter(|| span!(Level::TRACE, "span"))
+ });
+}
+
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/benches/span_repeated.rs b/third_party/rust/tracing/benches/span_repeated.rs
new file mode 100644
index 0000000000..4c6ac409d8
--- /dev/null
+++ b/third_party/rust/tracing/benches/span_repeated.rs
@@ -0,0 +1,20 @@
+use criterion::{black_box, criterion_group, criterion_main, Criterion};
+use tracing::{span, Level};
+
+mod shared;
+
+fn bench(c: &mut Criterion) {
+ shared::for_all_recording(&mut c.benchmark_group("span_repeated"), |b| {
+ let n = black_box(N_SPANS);
+ b.iter(|| (0..n).fold(mk_span(0), |_, i| mk_span(i as u64)))
+ });
+}
+
+#[inline]
+fn mk_span(i: u64) -> tracing::Span {
+ span!(Level::TRACE, "span", i = i)
+}
+
+const N_SPANS: usize = 100;
+criterion_group!(benches, bench);
+criterion_main!(benches);
diff --git a/third_party/rust/tracing/src/dispatcher.rs b/third_party/rust/tracing/src/dispatcher.rs
new file mode 100644
index 0000000000..a84b99f4eb
--- /dev/null
+++ b/third_party/rust/tracing/src/dispatcher.rs
@@ -0,0 +1,145 @@
+//! Dispatches trace events to [`Subscriber`]s.
+//!
+//! The _dispatcher_ is the component of the tracing system which is responsible
+//! for forwarding trace data from the instrumentation points that generate it
+//! to the subscriber that collects it.
+//!
+//! # Using the Trace Dispatcher
+//!
+//! Every thread in a program using `tracing` has a _default subscriber_. When
+//! events occur, or spans are created, they are dispatched to the thread's
+//! current subscriber.
+//!
+//! ## Setting the Default Subscriber
+//!
+//! By default, the current subscriber is an empty implementation that does
+//! nothing. To use a subscriber implementation, it must be set as the default.
+//! There are two methods for doing so: [`with_default`] and
+//! [`set_global_default`]. `with_default` sets the default subscriber for the
+//! duration of a scope, while `set_global_default` sets a default subscriber
+//! for the entire process.
+//!
+//! To use either of these functions, we must first wrap our subscriber in a
+//! [`Dispatch`], a cloneable, type-erased reference to a subscriber. For
+//! example:
+//! ```rust
+//! # pub struct FooSubscriber;
+//! # use tracing_core::{
+//! # dispatcher, Event, Metadata,
+//! # span::{Attributes, Id, Record}
+//! # };
+//! # impl tracing_core::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
+//! use dispatcher::Dispatch;
+//!
+//! let my_subscriber = FooSubscriber::new();
+//! let my_dispatch = Dispatch::new(my_subscriber);
+//! ```
+//! Then, we can use [`with_default`] to set our `Dispatch` as the default for
+//! the duration of a block:
+//! ```rust
+//! # pub struct FooSubscriber;
+//! # use tracing_core::{
+//! # dispatcher, Event, Metadata,
+//! # span::{Attributes, Id, Record}
+//! # };
+//! # impl tracing_core::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
+//! # let my_subscriber = FooSubscriber::new();
+//! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber);
+//! // no default subscriber
+//!
+//! # #[cfg(feature = "std")]
+//! dispatcher::with_default(&my_dispatch, || {
+//! // my_subscriber is the default
+//! });
+//!
+//! // no default subscriber again
+//! ```
+//! It's important to note that `with_default` will not propagate the current
+//! thread's default subscriber to any threads spawned within the `with_default`
+//! block. To propagate the default subscriber to new threads, either use
+//! `with_default` from the new thread, or use `set_global_default`.
+//!
+//! As an alternative to `with_default`, we can use [`set_global_default`] to
+//! set a `Dispatch` as the default for all threads, for the lifetime of the
+//! program. For example:
+//! ```rust
+//! # pub struct FooSubscriber;
+//! # use tracing_core::{
+//! # dispatcher, Event, Metadata,
+//! # span::{Attributes, Id, Record}
+//! # };
+//! # impl tracing_core::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber { fn new() -> Self { FooSubscriber } }
+//! # let my_subscriber = FooSubscriber::new();
+//! # let my_dispatch = dispatcher::Dispatch::new(my_subscriber);
+//! // no default subscriber
+//!
+//! dispatcher::set_global_default(my_dispatch)
+//! // `set_global_default` will return an error if the global default
+//! // subscriber has already been set.
+//! .expect("global default was already set!");
+//!
+//! // `my_subscriber` is now the default
+//! ```
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>: The thread-local scoped dispatcher (<code>with_default</code>)
+//! requires the Rust standard library. <code>no_std</code> users should
+//! use <a href="fn.set_global_default.html"><code>set_global_default</code></a>
+//! instead.
+//! </pre>
+//!
+//! ## Accessing the Default Subscriber
+//!
+//! A thread's current default subscriber can be accessed using the
+//! [`get_default`] function, which executes a closure with a reference to the
+//! currently default `Dispatch`. This is used primarily by `tracing`
+//! instrumentation.
+//!
+//! [`Subscriber`]: crate::Subscriber
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub use tracing_core::dispatcher::set_default;
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub use tracing_core::dispatcher::with_default;
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub use tracing_core::dispatcher::DefaultGuard;
+pub use tracing_core::dispatcher::{
+ get_default, set_global_default, Dispatch, SetGlobalDefaultError, WeakDispatch,
+};
+
+/// Private API for internal use by tracing's macros.
+///
+/// This function is *not* considered part of `tracing`'s public API, and has no
+/// stability guarantees. If you use it, and it breaks or disappears entirely,
+/// don't say we didn;'t warn you.
+#[doc(hidden)]
+pub use tracing_core::dispatcher::has_been_set;
diff --git a/third_party/rust/tracing/src/field.rs b/third_party/rust/tracing/src/field.rs
new file mode 100644
index 0000000000..b3f9fbdfca
--- /dev/null
+++ b/third_party/rust/tracing/src/field.rs
@@ -0,0 +1,170 @@
+//! `Span` and `Event` key-value data.
+//!
+//! Spans and events may be annotated with key-value data, referred to as known
+//! as _fields_. These fields consist of a mapping from a key (corresponding to
+//! a `&str` but represented internally as an array index) to a [`Value`].
+//!
+//! # `Value`s and `Subscriber`s
+//!
+//! `Subscriber`s consume `Value`s as fields attached to [span]s or [`Event`]s.
+//! The set of field keys on a given span or is defined on its [`Metadata`].
+//! When a span is created, it provides [`Attributes`] to the `Subscriber`'s
+//! [`new_span`] method, containing any fields whose values were provided when
+//! the span was created; and may call the `Subscriber`'s [`record`] method
+//! with additional [`Record`]s if values are added for more of its fields.
+//! Similarly, the [`Event`] type passed to the subscriber's [`event`] method
+//! will contain any fields attached to each event.
+//!
+//! `tracing` represents values as either one of a set of Rust primitives
+//! (`i64`, `u64`, `f64`, `bool`, and `&str`) or using a `fmt::Display` or
+//! `fmt::Debug` implementation. `Subscriber`s are provided these primitive
+//! value types as `dyn Value` trait objects.
+//!
+//! These trait objects can be formatted using `fmt::Debug`, but may also be
+//! recorded as typed data by calling the [`Value::record`] method on these
+//! trait objects with a _visitor_ implementing the [`Visit`] trait. This trait
+//! represents the behavior used to record values of various types. For example,
+//! an implementation of `Visit` might record integers by incrementing counters
+//! for their field names rather than printing them.
+//!
+//!
+//! # Using `valuable`
+//!
+//! `tracing`'s [`Value`] trait is intentionally minimalist: it supports only a small
+//! number of Rust primitives as typed values, and only permits recording
+//! user-defined types with their [`fmt::Debug`] or [`fmt::Display`]
+//! implementations. However, there are some cases where it may be useful to record
+//! nested values (such as arrays, `Vec`s, or `HashMap`s containing values), or
+//! user-defined `struct` and `enum` types without having to format them as
+//! unstructured text.
+//!
+//! To address `Value`'s limitations, `tracing` offers experimental support for
+//! the [`valuable`] crate, which provides object-safe inspection of structured
+//! values. User-defined types can implement the [`valuable::Valuable`] trait,
+//! and be recorded as a `tracing` field by calling their [`as_value`] method.
+//! If the [`Subscriber`] also supports the `valuable` crate, it can
+//! then visit those types fields as structured values using `valuable`.
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>: <code>valuable</code> support is an
+//! <a href = "../index.html#unstable-features">unstable feature</a>. See
+//! the documentation on unstable features for details on how to enable it.
+//! </pre>
+//!
+//! For example:
+//! ```ignore
+//! // Derive `Valuable` for our types:
+//! use valuable::Valuable;
+//!
+//! #[derive(Clone, Debug, Valuable)]
+//! struct User {
+//! name: String,
+//! age: u32,
+//! address: Address,
+//! }
+//!
+//! #[derive(Clone, Debug, Valuable)]
+//! struct Address {
+//! country: String,
+//! city: String,
+//! street: String,
+//! }
+//!
+//! let user = User {
+//! name: "Arwen Undomiel".to_string(),
+//! age: 3000,
+//! address: Address {
+//! country: "Middle Earth".to_string(),
+//! city: "Rivendell".to_string(),
+//! street: "leafy lane".to_string(),
+//! },
+//! };
+//!
+//! // Recording `user` as a `valuable::Value` will allow the `tracing` subscriber
+//! // to traverse its fields as a nested, typed structure:
+//! tracing::info!(current_user = user.as_value());
+//! ```
+//!
+//! Alternatively, the [`valuable()`] function may be used to convert a type
+//! implementing [`Valuable`] into a `tracing` field value.
+//!
+//! When the `valuable` feature is enabled, the [`Visit`] trait will include an
+//! optional [`record_value`] method. `Visit` implementations that wish to
+//! record `valuable` values can implement this method with custom behavior.
+//! If a visitor does not implement `record_value`, the [`valuable::Value`] will
+//! be forwarded to the visitor's [`record_debug`] method.
+//!
+//! [`fmt::Debug`]: std::fmt::Debug
+//! [`fmt::Display`]: std::fmt::Debug
+//! [`valuable`]: https://crates.io/crates/valuable
+//! [`valuable::Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
+//! [`as_value`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html#tymethod.as_value
+//! [`valuable::Value`]: https://docs.rs/valuable/latest/valuable/enum.Value.html
+//! [`Subscriber`]: crate::Subscriber
+//! [`record_value`]: Visit::record_value
+//! [`record_debug`]: Visit::record_debug
+//! [span]: mod@crate::span
+//! [`Event`]: crate::event::Event
+//! [`Metadata`]: crate::Metadata
+//! [`Attributes`]: crate::span::Attributes
+//! [`Record`]: crate::span::Record
+//! [`new_span`]: crate::Subscriber::new_span
+//! [`record`]: crate::Subscriber::record
+//! [`event`]: crate::Subscriber::event
+pub use tracing_core::field::*;
+
+use crate::Metadata;
+
+/// Trait implemented to allow a type to be used as a field key.
+///
+/// <pre class="ignore" style="white-space:normal;font:inherit;">
+/// <strong>Note</strong>: Although this is implemented for both the
+/// <a href="./struct.Field.html"><code>Field</code></a> type <em>and</em> any
+/// type that can be borrowed as an <code>&str</code>, only <code>Field</code>
+/// allows <em>O</em>(1) access.
+/// Indexing a field with a string results in an iterative search that performs
+/// string comparisons. Thus, if possible, once the key for a field is known, it
+/// should be used whenever possible.
+/// </pre>
+pub trait AsField: crate::sealed::Sealed {
+ /// Attempts to convert `&self` into a `Field` with the specified `metadata`.
+ ///
+ /// If `metadata` defines this field, then the field is returned. Otherwise,
+ /// this returns `None`.
+ fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field>;
+}
+
+// ===== impl AsField =====
+
+impl AsField for Field {
+ #[inline]
+ fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field> {
+ if self.callsite() == metadata.callsite() {
+ Some(self.clone())
+ } else {
+ None
+ }
+ }
+}
+
+impl<'a> AsField for &'a Field {
+ #[inline]
+ fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field> {
+ if self.callsite() == metadata.callsite() {
+ Some((*self).clone())
+ } else {
+ None
+ }
+ }
+}
+
+impl AsField for str {
+ #[inline]
+ fn as_field(&self, metadata: &Metadata<'_>) -> Option<Field> {
+ metadata.fields().field(&self)
+ }
+}
+
+impl crate::sealed::Sealed for Field {}
+impl<'a> crate::sealed::Sealed for &'a Field {}
+impl crate::sealed::Sealed for str {}
diff --git a/third_party/rust/tracing/src/instrument.rs b/third_party/rust/tracing/src/instrument.rs
new file mode 100644
index 0000000000..46e5f579cd
--- /dev/null
+++ b/third_party/rust/tracing/src/instrument.rs
@@ -0,0 +1,370 @@
+use crate::stdlib::pin::Pin;
+use crate::stdlib::task::{Context, Poll};
+use crate::stdlib::{future::Future, marker::Sized};
+use crate::{
+ dispatcher::{self, Dispatch},
+ span::Span,
+};
+use pin_project_lite::pin_project;
+
+/// Attaches spans to a [`std::future::Future`].
+///
+/// Extension trait allowing futures to be
+/// instrumented with a `tracing` [span].
+///
+/// [span]: super::Span
+pub trait Instrument: Sized {
+ /// Instruments this type with the provided [`Span`], returning an
+ /// `Instrumented` wrapper.
+ ///
+ /// The attached [`Span`] will be [entered] every time the instrumented
+ /// [`Future`] is polled.
+ ///
+ /// # Examples
+ ///
+ /// Instrumenting a future:
+ ///
+ /// ```rust
+ /// use tracing::Instrument;
+ ///
+ /// # async fn doc() {
+ /// let my_future = async {
+ /// // ...
+ /// };
+ ///
+ /// my_future
+ /// .instrument(tracing::info_span!("my_future"))
+ /// .await
+ /// # }
+ /// ```
+ ///
+ /// The [`Span::or_current`] combinator can be used in combination with
+ /// `instrument` to ensure that the [current span] is attached to the
+ /// future if the span passed to `instrument` is [disabled]:
+ ///
+ /// ```
+ /// use tracing::Instrument;
+ /// # mod tokio {
+ /// # pub(super) fn spawn(_: impl std::future::Future) {}
+ /// # }
+ ///
+ /// let my_future = async {
+ /// // ...
+ /// };
+ ///
+ /// let outer_span = tracing::info_span!("outer").entered();
+ ///
+ /// // If the "my_future" span is enabled, then the spawned task will
+ /// // be within both "my_future" *and* "outer", since "outer" is
+ /// // "my_future"'s parent. However, if "my_future" is disabled,
+ /// // the spawned task will *not* be in any span.
+ /// tokio::spawn(
+ /// my_future
+ /// .instrument(tracing::debug_span!("my_future"))
+ /// );
+ ///
+ /// // Using `Span::or_current` ensures the spawned task is instrumented
+ /// // with the current span, if the new span passed to `instrument` is
+ /// // not enabled. This means that if the "my_future" span is disabled,
+ /// // the spawned task will still be instrumented with the "outer" span:
+ /// # let my_future = async {};
+ /// tokio::spawn(
+ /// my_future
+ /// .instrument(tracing::debug_span!("my_future").or_current())
+ /// );
+ /// ```
+ ///
+ /// [entered]: super::Span::enter()
+ /// [`Span::or_current`]: super::Span::or_current()
+ /// [current span]: super::Span::current()
+ /// [disabled]: super::Span::is_disabled()
+ /// [`Future`]: std::future::Future
+ fn instrument(self, span: Span) -> Instrumented<Self> {
+ Instrumented { inner: self, span }
+ }
+
+ /// Instruments this type with the [current] [`Span`], returning an
+ /// `Instrumented` wrapper.
+ ///
+ /// The attached [`Span`] will be [entered] every time the instrumented
+ /// [`Future`] is polled.
+ ///
+ /// This can be used to propagate the current span when spawning a new future.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// use tracing::Instrument;
+ ///
+ /// # mod tokio {
+ /// # pub(super) fn spawn(_: impl std::future::Future) {}
+ /// # }
+ /// # async fn doc() {
+ /// let span = tracing::info_span!("my_span");
+ /// let _enter = span.enter();
+ ///
+ /// // ...
+ ///
+ /// let future = async {
+ /// tracing::debug!("this event will occur inside `my_span`");
+ /// // ...
+ /// };
+ /// tokio::spawn(future.in_current_span());
+ /// # }
+ /// ```
+ ///
+ /// [current]: super::Span::current()
+ /// [entered]: super::Span::enter()
+ /// [`Span`]: crate::Span
+ /// [`Future`]: std::future::Future
+ #[inline]
+ fn in_current_span(self) -> Instrumented<Self> {
+ self.instrument(Span::current())
+ }
+}
+
+/// Extension trait allowing futures to be instrumented with
+/// a `tracing` [`Subscriber`](crate::Subscriber).
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub trait WithSubscriber: Sized {
+ /// Attaches the provided [`Subscriber`] to this type, returning a
+ /// [`WithDispatch`] wrapper.
+ ///
+ /// The attached [`Subscriber`] will be set as the [default] when the returned
+ /// [`Future`] is polled.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use tracing::subscriber::NoSubscriber as MySubscriber;
+ /// # use tracing::subscriber::NoSubscriber as MyOtherSubscriber;
+ /// # async fn docs() {
+ /// use tracing::instrument::WithSubscriber;
+ ///
+ /// // Set the default `Subscriber`
+ /// let _default = tracing::subscriber::set_default(MySubscriber::default());
+ ///
+ /// tracing::info!("this event will be recorded by the default `Subscriber`");
+ ///
+ /// // Create a different `Subscriber` and attach it to a future.
+ /// let other_subscriber = MyOtherSubscriber::default();
+ /// let future = async {
+ /// tracing::info!("this event will be recorded by the other `Subscriber`");
+ /// // ...
+ /// };
+ ///
+ /// future
+ /// // Attach the other `Subscriber` to the future before awaiting it
+ /// .with_subscriber(other_subscriber)
+ /// .await;
+ ///
+ /// // Once the future has completed, we return to the default `Subscriber`.
+ /// tracing::info!("this event will be recorded by the default `Subscriber`");
+ /// # }
+ /// ```
+ ///
+ /// [`Subscriber`]: super::Subscriber
+ /// [default]: crate::dispatcher#setting-the-default-subscriber
+ /// [`Future`]: std::future::Future
+ fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
+ where
+ S: Into<Dispatch>,
+ {
+ WithDispatch {
+ inner: self,
+ dispatcher: subscriber.into(),
+ }
+ }
+
+ /// Attaches the current [default] [`Subscriber`] to this type, returning a
+ /// [`WithDispatch`] wrapper.
+ ///
+ /// The attached `Subscriber` will be set as the [default] when the returned
+ /// [`Future`] is polled.
+ ///
+ /// This can be used to propagate the current dispatcher context when
+ /// spawning a new future that may run on a different thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # mod tokio {
+ /// # pub(super) fn spawn(_: impl std::future::Future) {}
+ /// # }
+ /// # use tracing::subscriber::NoSubscriber as MySubscriber;
+ /// # async fn docs() {
+ /// use tracing::instrument::WithSubscriber;
+ ///
+ /// // Using `set_default` (rather than `set_global_default`) sets the
+ /// // default `Subscriber` for *this* thread only.
+ /// let _default = tracing::subscriber::set_default(MySubscriber::default());
+ ///
+ /// let future = async {
+ /// // ...
+ /// };
+ ///
+ /// // If a multi-threaded async runtime is in use, this spawned task may
+ /// // run on a different thread, in a different default `Subscriber`'s context.
+ /// tokio::spawn(future);
+ ///
+ /// // However, calling `with_current_subscriber` on the future before
+ /// // spawning it, ensures that the current thread's default `Subscriber` is
+ /// // propagated to the spawned task, regardless of where it executes:
+ /// # let future = async { };
+ /// tokio::spawn(future.with_current_subscriber());
+ /// # }
+ /// ```
+ /// [`Subscriber`]: super::Subscriber
+ /// [default]: crate::dispatcher#setting-the-default-subscriber
+ /// [`Future`]: std::future::Future
+ #[inline]
+ fn with_current_subscriber(self) -> WithDispatch<Self> {
+ WithDispatch {
+ inner: self,
+ dispatcher: crate::dispatcher::get_default(|default| default.clone()),
+ }
+ }
+}
+
+pin_project! {
+ /// A [`Future`] that has been instrumented with a `tracing` [`Subscriber`].
+ ///
+ /// This type is returned by the [`WithSubscriber`] extension trait. See that
+ /// trait's documentation for details.
+ ///
+ /// [`Future`]: std::future::Future
+ /// [`Subscriber`]: crate::Subscriber
+ #[derive(Clone, Debug)]
+ #[must_use = "futures do nothing unless you `.await` or poll them"]
+ #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+ pub struct WithDispatch<T> {
+ #[pin]
+ inner: T,
+ dispatcher: Dispatch,
+ }
+}
+
+pin_project! {
+ /// A [`Future`] that has been instrumented with a `tracing` [`Span`].
+ ///
+ /// This type is returned by the [`Instrument`] extension trait. See that
+ /// trait's documentation for details.
+ ///
+ /// [`Future`]: std::future::Future
+ /// [`Span`]: crate::Span
+ #[derive(Debug, Clone)]
+ #[must_use = "futures do nothing unless you `.await` or poll them"]
+ pub struct Instrumented<T> {
+ #[pin]
+ inner: T,
+ span: Span,
+ }
+}
+
+// === impl Instrumented ===
+
+impl<T: Future> Future for Instrumented<T> {
+ type Output = T::Output;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ let this = self.project();
+ let _enter = this.span.enter();
+ this.inner.poll(cx)
+ }
+}
+
+impl<T: Sized> Instrument for T {}
+
+impl<T> Instrumented<T> {
+ /// Borrows the `Span` that this type is instrumented by.
+ pub fn span(&self) -> &Span {
+ &self.span
+ }
+
+ /// Mutably borrows the `Span` that this type is instrumented by.
+ pub fn span_mut(&mut self) -> &mut Span {
+ &mut self.span
+ }
+
+ /// Borrows the wrapped type.
+ pub fn inner(&self) -> &T {
+ &self.inner
+ }
+
+ /// Mutably borrows the wrapped type.
+ pub fn inner_mut(&mut self) -> &mut T {
+ &mut self.inner
+ }
+
+ /// Get a pinned reference to the wrapped type.
+ pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
+ self.project_ref().inner
+ }
+
+ /// Get a pinned mutable reference to the wrapped type.
+ pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
+ self.project().inner
+ }
+
+ /// Consumes the `Instrumented`, returning the wrapped type.
+ ///
+ /// Note that this drops the span.
+ pub fn into_inner(self) -> T {
+ self.inner
+ }
+}
+
+// === impl WithDispatch ===
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl<T: Future> Future for WithDispatch<T> {
+ type Output = T::Output;
+
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+ let this = self.project();
+ let dispatcher = this.dispatcher;
+ let future = this.inner;
+ let _default = dispatcher::set_default(dispatcher);
+ future.poll(cx)
+ }
+}
+
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl<T: Sized> WithSubscriber for T {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl<T> WithDispatch<T> {
+ /// Borrows the [`Dispatch`] that is entered when this type is polled.
+ pub fn dispatcher(&self) -> &Dispatch {
+ &self.dispatcher
+ }
+
+ /// Borrows the wrapped type.
+ pub fn inner(&self) -> &T {
+ &self.inner
+ }
+
+ /// Mutably borrows the wrapped type.
+ pub fn inner_mut(&mut self) -> &mut T {
+ &mut self.inner
+ }
+
+ /// Get a pinned reference to the wrapped type.
+ pub fn inner_pin_ref(self: Pin<&Self>) -> Pin<&T> {
+ self.project_ref().inner
+ }
+
+ /// Get a pinned mutable reference to the wrapped type.
+ pub fn inner_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
+ self.project().inner
+ }
+
+ /// Consumes the `Instrumented`, returning the wrapped type.
+ ///
+ /// Note that this drops the span.
+ pub fn into_inner(self) -> T {
+ self.inner
+ }
+}
diff --git a/third_party/rust/tracing/src/level_filters.rs b/third_party/rust/tracing/src/level_filters.rs
new file mode 100644
index 0000000000..44f5e5f57a
--- /dev/null
+++ b/third_party/rust/tracing/src/level_filters.rs
@@ -0,0 +1,94 @@
+//! Trace verbosity level filtering.
+//!
+//! # Compile time filters
+//!
+//! Trace verbosity levels can be statically disabled at compile time via Cargo
+//! features, similar to the [`log` crate]. Trace instrumentation at disabled
+//! levels will be skipped and will not even be present in the resulting binary
+//! unless the verbosity level is specified dynamically. This level is
+//! configured separately for release and debug builds. The features are:
+//!
+//! * `max_level_off`
+//! * `max_level_error`
+//! * `max_level_warn`
+//! * `max_level_info`
+//! * `max_level_debug`
+//! * `max_level_trace`
+//! * `release_max_level_off`
+//! * `release_max_level_error`
+//! * `release_max_level_warn`
+//! * `release_max_level_info`
+//! * `release_max_level_debug`
+//! * `release_max_level_trace`
+//!
+//! These features control the value of the `STATIC_MAX_LEVEL` constant. The
+//! instrumentation macros macros check this value before recording an event or
+//! constructing a span. By default, no levels are disabled.
+//!
+//! For example, a crate can disable trace level instrumentation in debug builds
+//! and trace, debug, and info level instrumentation in release builds with the
+//! following configuration:
+//!
+//! ```toml
+//! [dependencies]
+//! tracing = { version = "0.1", features = ["max_level_debug", "release_max_level_warn"] }
+//! ```
+//! ## Notes
+//!
+//! Please note that `tracing`'s static max level features do *not* control the
+//! [`log`] records that may be emitted when [`tracing`'s "log" feature flag][f] is
+//! enabled. This is to allow `tracing` to be disabled entirely at compile time
+//! while still emitting `log` records --- such as when a library using
+//! `tracing` is used by an application using `log` that doesn't want to
+//! generate any `tracing`-related code, but does want to collect `log` records.
+//!
+//! This means that if the "log" feature is in use, some code may be generated
+//! for `log` records emitted by disabled `tracing` events. If this is not
+//! desirable, `log` records may be disabled separately using [`log`'s static
+//! max level features][`log` crate].
+//!
+//! [`log`]: https://docs.rs/log/
+//! [`log` crate]: https://docs.rs/log/latest/log/#compile-time-filters
+//! [f]: https://docs.rs/tracing/latest/tracing/#emitting-log-records
+pub use tracing_core::{metadata::ParseLevelFilterError, LevelFilter};
+
+/// The statically configured maximum trace level.
+///
+/// See the [module-level documentation] for information on how to configure
+/// this.
+///
+/// This value is checked by the `event!` and `span!` macros. Code that
+/// manually constructs events or spans via the `Event::record` function or
+/// `Span` constructors should compare the level against this value to
+/// determine if those spans or events are enabled.
+///
+/// [module-level documentation]: super#compile-time-filters
+pub const STATIC_MAX_LEVEL: LevelFilter = MAX_LEVEL;
+
+cfg_if::cfg_if! {
+ if #[cfg(all(not(debug_assertions), feature = "release_max_level_off"))] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::OFF;
+ } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_error"))] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::ERROR;
+ } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_warn"))] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::WARN;
+ } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_info"))] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::INFO;
+ } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_debug"))] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::DEBUG;
+ } else if #[cfg(all(not(debug_assertions), feature = "release_max_level_trace"))] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::TRACE;
+ } else if #[cfg(feature = "max_level_off")] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::OFF;
+ } else if #[cfg(feature = "max_level_error")] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::ERROR;
+ } else if #[cfg(feature = "max_level_warn")] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::WARN;
+ } else if #[cfg(feature = "max_level_info")] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::INFO;
+ } else if #[cfg(feature = "max_level_debug")] {
+ const MAX_LEVEL: LevelFilter = LevelFilter::DEBUG;
+ } else {
+ const MAX_LEVEL: LevelFilter = LevelFilter::TRACE;
+ }
+}
diff --git a/third_party/rust/tracing/src/lib.rs b/third_party/rust/tracing/src/lib.rs
new file mode 100644
index 0000000000..342e04a825
--- /dev/null
+++ b/third_party/rust/tracing/src/lib.rs
@@ -0,0 +1,1115 @@
+//! A scoped, structured logging and diagnostics system.
+//!
+//! # Overview
+//!
+//! `tracing` is a framework for instrumenting Rust programs to collect
+//! structured, event-based diagnostic information.
+//!
+//! In asynchronous systems like Tokio, interpreting traditional log messages can
+//! often be quite challenging. Since individual tasks are multiplexed on the same
+//! thread, associated events and log lines are intermixed making it difficult to
+//! trace the logic flow. `tracing` expands upon logging-style diagnostics by
+//! allowing libraries and applications to record structured events with additional
+//! information about *temporality* and *causality* — unlike a log message, a span
+//! in `tracing` has a beginning and end time, may be entered and exited by the
+//! flow of execution, and may exist within a nested tree of similar spans. In
+//! addition, `tracing` spans are *structured*, with the ability to record typed
+//! data as well as textual messages.
+//!
+//! The `tracing` crate provides the APIs necessary for instrumenting libraries
+//! and applications to emit trace data.
+//!
+//! *Compiler support: [requires `rustc` 1.49+][msrv]*
+//!
+//! [msrv]: #supported-rust-versions
+//! # Core Concepts
+//!
+//! The core of `tracing`'s API is composed of _spans_, _events_ and
+//! _subscribers_. We'll cover these in turn.
+//!
+//! ## Spans
+//!
+//! To record the flow of execution through a program, `tracing` introduces the
+//! concept of [spans]. Unlike a log line that represents a _moment in
+//! time_, a span represents a _period of time_ with a beginning and an end. When a
+//! program begins executing in a context or performing a unit of work, it
+//! _enters_ that context's span, and when it stops executing in that context,
+//! it _exits_ the span. The span in which a thread is currently executing is
+//! referred to as that thread's _current_ span.
+//!
+//! For example:
+//! ```
+//! use tracing::{span, Level};
+//! # fn main() {
+//! let span = span!(Level::TRACE, "my_span");
+//! // `enter` returns a RAII guard which, when dropped, exits the span. this
+//! // indicates that we are in the span for the current lexical scope.
+//! let _enter = span.enter();
+//! // perform some work in the context of `my_span`...
+//! # }
+//!```
+//!
+//! The [`span` module][span]'s documentation provides further details on how to
+//! use spans.
+//!
+//! <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
+//!
+//! **Warning**: In asynchronous code that uses async/await syntax,
+//! `Span::enter` may produce incorrect traces if the returned drop
+//! guard is held across an await point. See
+//! [the method documentation][Span#in-asynchronous-code] for details.
+//!
+//! </pre></div>
+//!
+//! ## Events
+//!
+//! An [`Event`] represents a _moment_ in time. It signifies something that
+//! happened while a trace was being recorded. `Event`s are comparable to the log
+//! records emitted by unstructured logging code, but unlike a typical log line,
+//! an `Event` may occur within the context of a span.
+//!
+//! For example:
+//! ```
+//! use tracing::{event, span, Level};
+//!
+//! # fn main() {
+//! // records an event outside of any span context:
+//! event!(Level::INFO, "something happened");
+//!
+//! let span = span!(Level::INFO, "my_span");
+//! let _guard = span.enter();
+//!
+//! // records an event within "my_span".
+//! event!(Level::DEBUG, "something happened inside my_span");
+//! # }
+//!```
+//!
+//! In general, events should be used to represent points in time _within_ a
+//! span — a request returned with a given status code, _n_ new items were
+//! taken from a queue, and so on.
+//!
+//! The [`Event` struct][`Event`] documentation provides further details on using
+//! events.
+//!
+//! ## Subscribers
+//!
+//! As `Span`s and `Event`s occur, they are recorded or aggregated by
+//! implementations of the [`Subscriber`] trait. `Subscriber`s are notified
+//! when an `Event` takes place and when a `Span` is entered or exited. These
+//! notifications are represented by the following `Subscriber` trait methods:
+//!
+//! + [`event`][Subscriber::event], called when an `Event` takes place,
+//! + [`enter`], called when execution enters a `Span`,
+//! + [`exit`], called when execution exits a `Span`
+//!
+//! In addition, subscribers may implement the [`enabled`] function to _filter_
+//! the notifications they receive based on [metadata] describing each `Span`
+//! or `Event`. If a call to `Subscriber::enabled` returns `false` for a given
+//! set of metadata, that `Subscriber` will *not* be notified about the
+//! corresponding `Span` or `Event`. For performance reasons, if no currently
+//! active subscribers express interest in a given set of metadata by returning
+//! `true`, then the corresponding `Span` or `Event` will never be constructed.
+//!
+//! # Usage
+//!
+//! First, add this to your `Cargo.toml`:
+//!
+//! ```toml
+//! [dependencies]
+//! tracing = "0.1"
+//! ```
+//!
+//! ## Recording Spans and Events
+//!
+//! Spans and events are recorded using macros.
+//!
+//! ### Spans
+//!
+//! The [`span!`] macro expands to a [`Span` struct][`Span`] which is used to
+//! record a span. The [`Span::enter`] method on that struct records that the
+//! span has been entered, and returns a [RAII] guard object, which will exit
+//! the span when dropped.
+//!
+//! For example:
+//!
+//! ```rust
+//! use tracing::{span, Level};
+//! # fn main() {
+//! // Construct a new span named "my span" with trace log level.
+//! let span = span!(Level::TRACE, "my span");
+//!
+//! // Enter the span, returning a guard object.
+//! let _enter = span.enter();
+//!
+//! // Any trace events that occur before the guard is dropped will occur
+//! // within the span.
+//!
+//! // Dropping the guard will exit the span.
+//! # }
+//! ```
+//!
+//! The [`#[instrument]`][instrument] attribute provides an easy way to
+//! add `tracing` spans to functions. A function annotated with `#[instrument]`
+//! will create and enter a span with that function's name every time the
+//! function is called, with arguments to that function will be recorded as
+//! fields using `fmt::Debug`.
+//!
+//! For example:
+//! ```ignore
+//! # // this doctest is ignored because we don't have a way to say
+//! # // that it should only be run with cfg(feature = "attributes")
+//! use tracing::{Level, event, instrument};
+//!
+//! #[instrument]
+//! pub fn my_function(my_arg: usize) {
+//! // This event will be recorded inside a span named `my_function` with the
+//! // field `my_arg`.
+//! event!(Level::INFO, "inside my_function!");
+//! // ...
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! For functions which don't have built-in tracing support and can't have
+//! the `#[instrument]` attribute applied (such as from an external crate),
+//! the [`Span` struct][`Span`] has a [`in_scope()` method][`in_scope`]
+//! which can be used to easily wrap synchonous code in a span.
+//!
+//! For example:
+//! ```rust
+//! use tracing::info_span;
+//!
+//! # fn doc() -> Result<(), ()> {
+//! # mod serde_json {
+//! # pub(crate) fn from_slice(buf: &[u8]) -> Result<(), ()> { Ok(()) }
+//! # }
+//! # let buf: [u8; 0] = [];
+//! let json = info_span!("json.parse").in_scope(|| serde_json::from_slice(&buf))?;
+//! # let _ = json; // suppress unused variable warning
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! You can find more examples showing how to use this crate [here][examples].
+//!
+//! [RAII]: https://github.com/rust-unofficial/patterns/blob/master/patterns/behavioural/RAII.md
+//! [examples]: https://github.com/tokio-rs/tracing/tree/master/examples
+//!
+//! ### Events
+//!
+//! [`Event`]s are recorded using the [`event!`] macro:
+//!
+//! ```rust
+//! # fn main() {
+//! use tracing::{event, Level};
+//! event!(Level::INFO, "something has happened!");
+//! # }
+//! ```
+//!
+//! ## Using the Macros
+//!
+//! The [`span!`] and [`event!`] macros as well as the `#[instrument]` attribute
+//! use fairly similar syntax, with some exceptions.
+//!
+//! ### Configuring Attributes
+//!
+//! Both macros require a [`Level`] specifying the verbosity of the span or
+//! event. Optionally, the [target] and [parent span] may be overridden. If the
+//! target and parent span are not overridden, they will default to the
+//! module path where the macro was invoked and the current span (as determined
+//! by the subscriber), respectively.
+//!
+//! For example:
+//!
+//! ```
+//! # use tracing::{span, event, Level};
+//! # fn main() {
+//! span!(target: "app_spans", Level::TRACE, "my span");
+//! event!(target: "app_events", Level::INFO, "something has happened!");
+//! # }
+//! ```
+//! ```
+//! # use tracing::{span, event, Level};
+//! # fn main() {
+//! let span = span!(Level::TRACE, "my span");
+//! event!(parent: &span, Level::INFO, "something has happened!");
+//! # }
+//! ```
+//!
+//! The span macros also take a string literal after the level, to set the name
+//! of the span.
+//!
+//! ### Recording Fields
+//!
+//! Structured fields on spans and events are specified using the syntax
+//! `field_name = field_value`. Fields are separated by commas.
+//!
+//! ```
+//! # use tracing::{event, Level};
+//! # fn main() {
+//! // records an event with two fields:
+//! // - "answer", with the value 42
+//! // - "question", with the value "life, the universe and everything"
+//! event!(Level::INFO, answer = 42, question = "life, the universe, and everything");
+//! # }
+//! ```
+//!
+//! As shorthand, local variables may be used as field values without an
+//! assignment, similar to [struct initializers]. For example:
+//!
+//! ```
+//! # use tracing::{span, Level};
+//! # fn main() {
+//! let user = "ferris";
+//!
+//! span!(Level::TRACE, "login", user);
+//! // is equivalent to:
+//! span!(Level::TRACE, "login", user = user);
+//! # }
+//!```
+//!
+//! Field names can include dots, but should not be terminated by them:
+//! ```
+//! # use tracing::{span, Level};
+//! # fn main() {
+//! let user = "ferris";
+//! let email = "ferris@rust-lang.org";
+//! span!(Level::TRACE, "login", user, user.email = email);
+//! # }
+//!```
+//!
+//! Since field names can include dots, fields on local structs can be used
+//! using the local variable shorthand:
+//! ```
+//! # use tracing::{span, Level};
+//! # fn main() {
+//! # struct User {
+//! # name: &'static str,
+//! # email: &'static str,
+//! # }
+//! let user = User {
+//! name: "ferris",
+//! email: "ferris@rust-lang.org",
+//! };
+//! // the span will have the fields `user.name = "ferris"` and
+//! // `user.email = "ferris@rust-lang.org"`.
+//! span!(Level::TRACE, "login", user.name, user.email);
+//! # }
+//!```
+//!
+//! Fields with names that are not Rust identifiers, or with names that are Rust reserved words,
+//! may be created using quoted string literals. However, this may not be used with the local
+//! variable shorthand.
+//! ```
+//! # use tracing::{span, Level};
+//! # fn main() {
+//! // records an event with fields whose names are not Rust identifiers
+//! // - "guid:x-request-id", containing a `:`, with the value "abcdef"
+//! // - "type", which is a reserved word, with the value "request"
+//! span!(Level::TRACE, "api", "guid:x-request-id" = "abcdef", "type" = "request");
+//! # }
+//!```
+//!
+//! The `?` sigil is shorthand that specifies a field should be recorded using
+//! its [`fmt::Debug`] implementation:
+//! ```
+//! # use tracing::{event, Level};
+//! # fn main() {
+//! #[derive(Debug)]
+//! struct MyStruct {
+//! field: &'static str,
+//! }
+//!
+//! let my_struct = MyStruct {
+//! field: "Hello world!"
+//! };
+//!
+//! // `my_struct` will be recorded using its `fmt::Debug` implementation.
+//! event!(Level::TRACE, greeting = ?my_struct);
+//! // is equivalent to:
+//! event!(Level::TRACE, greeting = tracing::field::debug(&my_struct));
+//! # }
+//! ```
+//!
+//! The `%` sigil operates similarly, but indicates that the value should be
+//! recorded using its [`fmt::Display`] implementation:
+//! ```
+//! # use tracing::{event, Level};
+//! # fn main() {
+//! # #[derive(Debug)]
+//! # struct MyStruct {
+//! # field: &'static str,
+//! # }
+//! #
+//! # let my_struct = MyStruct {
+//! # field: "Hello world!"
+//! # };
+//! // `my_struct.field` will be recorded using its `fmt::Display` implementation.
+//! event!(Level::TRACE, greeting = %my_struct.field);
+//! // is equivalent to:
+//! event!(Level::TRACE, greeting = tracing::field::display(&my_struct.field));
+//! # }
+//! ```
+//!
+//! The `%` and `?` sigils may also be used with local variable shorthand:
+//!
+//! ```
+//! # use tracing::{event, Level};
+//! # fn main() {
+//! # #[derive(Debug)]
+//! # struct MyStruct {
+//! # field: &'static str,
+//! # }
+//! #
+//! # let my_struct = MyStruct {
+//! # field: "Hello world!"
+//! # };
+//! // `my_struct.field` will be recorded using its `fmt::Display` implementation.
+//! event!(Level::TRACE, %my_struct.field);
+//! # }
+//! ```
+//!
+//! Additionally, a span may declare fields with the special value [`Empty`],
+//! which indicates that that the value for that field does not currently exist
+//! but may be recorded later. For example:
+//!
+//! ```
+//! use tracing::{trace_span, field};
+//!
+//! // Create a span with two fields: `greeting`, with the value "hello world", and
+//! // `parting`, without a value.
+//! let span = trace_span!("my_span", greeting = "hello world", parting = field::Empty);
+//!
+//! // ...
+//!
+//! // Now, record a value for parting as well.
+//! span.record("parting", &"goodbye world!");
+//! ```
+//!
+//! Note that a span may have up to 32 fields. The following will not compile:
+//!
+//! ```rust,compile_fail
+//! # use tracing::Level;
+//! # fn main() {
+//! let bad_span = span!(
+//! Level::TRACE,
+//! "too many fields!",
+//! a = 1, b = 2, c = 3, d = 4, e = 5, f = 6, g = 7, h = 8, i = 9,
+//! j = 10, k = 11, l = 12, m = 13, n = 14, o = 15, p = 16, q = 17,
+//! r = 18, s = 19, t = 20, u = 21, v = 22, w = 23, x = 24, y = 25,
+//! z = 26, aa = 27, bb = 28, cc = 29, dd = 30, ee = 31, ff = 32, gg = 33
+//! );
+//! # }
+//! ```
+//!
+//! Finally, events may also include human-readable messages, in the form of a
+//! [format string][fmt] and (optional) arguments, **after** the event's
+//! key-value fields. If a format string and arguments are provided,
+//! they will implicitly create a new field named `message` whose value is the
+//! provided set of format arguments.
+//!
+//! For example:
+//!
+//! ```
+//! # use tracing::{event, Level};
+//! # fn main() {
+//! let question = "the ultimate question of life, the universe, and everything";
+//! let answer = 42;
+//! // records an event with the following fields:
+//! // - `question.answer` with the value 42,
+//! // - `question.tricky` with the value `true`,
+//! // - "message", with the value "the answer to the ultimate question of life, the
+//! // universe, and everything is 42."
+//! event!(
+//! Level::DEBUG,
+//! question.answer = answer,
+//! question.tricky = true,
+//! "the answer to {} is {}.", question, answer
+//! );
+//! # }
+//! ```
+//!
+//! Specifying a formatted message in this manner does not allocate by default.
+//!
+//! [struct initializers]: https://doc.rust-lang.org/book/ch05-01-defining-structs.html#using-the-field-init-shorthand-when-variables-and-fields-have-the-same-name
+//! [target]: Metadata::target
+//! [parent span]: span::Attributes::parent
+//! [determined contextually]: span::Attributes::is_contextual
+//! [`fmt::Debug`]: std::fmt::Debug
+//! [`fmt::Display`]: std::fmt::Display
+//! [fmt]: std::fmt#usage
+//! [`Empty`]: field::Empty
+//!
+//! ### Shorthand Macros
+//!
+//! `tracing` also offers a number of macros with preset verbosity levels.
+//! The [`trace!`], [`debug!`], [`info!`], [`warn!`], and [`error!`] behave
+//! similarly to the [`event!`] macro, but with the [`Level`] argument already
+//! specified, while the corresponding [`trace_span!`], [`debug_span!`],
+//! [`info_span!`], [`warn_span!`], and [`error_span!`] macros are the same,
+//! but for the [`span!`] macro.
+//!
+//! These are intended both as a shorthand, and for compatibility with the [`log`]
+//! crate (see the next section).
+//!
+//! [`span!`]: span!
+//! [`event!`]: event!
+//! [`trace!`]: trace!
+//! [`debug!`]: debug!
+//! [`info!`]: info!
+//! [`warn!`]: warn!
+//! [`error!`]: error!
+//! [`trace_span!`]: trace_span!
+//! [`debug_span!`]: debug_span!
+//! [`info_span!`]: info_span!
+//! [`warn_span!`]: warn_span!
+//! [`error_span!`]: error_span!
+//!
+//! ### For `log` Users
+//!
+//! Users of the [`log`] crate should note that `tracing` exposes a set of
+//! macros for creating `Event`s (`trace!`, `debug!`, `info!`, `warn!`, and
+//! `error!`) which may be invoked with the same syntax as the similarly-named
+//! macros from the `log` crate. Often, the process of converting a project to
+//! use `tracing` can begin with a simple drop-in replacement.
+//!
+//! Let's consider the `log` crate's yak-shaving example:
+//!
+//! ```rust,ignore
+//! use std::{error::Error, io};
+//! use tracing::{debug, error, info, span, warn, Level};
+//!
+//! // the `#[tracing::instrument]` attribute creates and enters a span
+//! // every time the instrumented function is called. The span is named after the
+//! // the function or method. Parameters passed to the function are recorded as fields.
+//! #[tracing::instrument]
+//! pub fn shave(yak: usize) -> Result<(), Box<dyn Error + 'static>> {
+//! // this creates an event at the DEBUG level with two fields:
+//! // - `excitement`, with the key "excitement" and the value "yay!"
+//! // - `message`, with the key "message" and the value "hello! I'm gonna shave a yak."
+//! //
+//! // unlike other fields, `message`'s shorthand initialization is just the string itself.
+//! debug!(excitement = "yay!", "hello! I'm gonna shave a yak.");
+//! if yak == 3 {
+//! warn!("could not locate yak!");
+//! // note that this is intended to demonstrate `tracing`'s features, not idiomatic
+//! // error handling! in a library or application, you should consider returning
+//! // a dedicated `YakError`. libraries like snafu or thiserror make this easy.
+//! return Err(io::Error::new(io::ErrorKind::Other, "shaving yak failed!").into());
+//! } else {
+//! debug!("yak shaved successfully");
+//! }
+//! Ok(())
+//! }
+//!
+//! pub fn shave_all(yaks: usize) -> usize {
+//! // Constructs a new span named "shaving_yaks" at the TRACE level,
+//! // and a field whose key is "yaks". This is equivalent to writing:
+//! //
+//! // let span = span!(Level::TRACE, "shaving_yaks", yaks = yaks);
+//! //
+//! // local variables (`yaks`) can be used as field values
+//! // without an assignment, similar to struct initializers.
+//! let _span = span!(Level::TRACE, "shaving_yaks", yaks).entered();
+//!
+//! info!("shaving yaks");
+//!
+//! let mut yaks_shaved = 0;
+//! for yak in 1..=yaks {
+//! let res = shave(yak);
+//! debug!(yak, shaved = res.is_ok());
+//!
+//! if let Err(ref error) = res {
+//! // Like spans, events can also use the field initialization shorthand.
+//! // In this instance, `yak` is the field being initalized.
+//! error!(yak, error = error.as_ref(), "failed to shave yak!");
+//! } else {
+//! yaks_shaved += 1;
+//! }
+//! debug!(yaks_shaved);
+//! }
+//!
+//! yaks_shaved
+//! }
+//! ```
+//!
+//! ## In libraries
+//!
+//! Libraries should link only to the `tracing` crate, and use the provided
+//! macros to record whatever information will be useful to downstream
+//! consumers.
+//!
+//! ## In executables
+//!
+//! In order to record trace events, executables have to use a `Subscriber`
+//! implementation compatible with `tracing`. A `Subscriber` implements a
+//! way of collecting trace data, such as by logging it to standard output.
+//!
+//! This library does not contain any `Subscriber` implementations; these are
+//! provided by [other crates](#related-crates).
+//!
+//! The simplest way to use a subscriber is to call the [`set_global_default`]
+//! function:
+//!
+//! ```
+//! extern crate tracing;
+//! # pub struct FooSubscriber;
+//! # use tracing::{span::{Id, Attributes, Record}, Metadata};
+//! # impl tracing::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &tracing::Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber {
+//! # fn new() -> Self { FooSubscriber }
+//! # }
+//! # fn main() {
+//!
+//! let my_subscriber = FooSubscriber::new();
+//! tracing::subscriber::set_global_default(my_subscriber)
+//! .expect("setting tracing default failed");
+//! # }
+//! ```
+//!
+//! <pre class="compile_fail" style="white-space:normal;font:inherit;">
+//! <strong>Warning</strong>: In general, libraries should <em>not</em> call
+//! <code>set_global_default()</code>! Doing so will cause conflicts when
+//! executables that depend on the library try to set the default later.
+//! </pre>
+//!
+//! This subscriber will be used as the default in all threads for the
+//! remainder of the duration of the program, similar to setting the logger
+//! in the `log` crate.
+//!
+//! In addition, the default subscriber can be set through using the
+//! [`with_default`] function. This follows the `tokio` pattern of using
+//! closures to represent executing code in a context that is exited at the end
+//! of the closure. For example:
+//!
+//! ```rust
+//! # pub struct FooSubscriber;
+//! # use tracing::{span::{Id, Attributes, Record}, Metadata};
+//! # impl tracing::Subscriber for FooSubscriber {
+//! # fn new_span(&self, _: &Attributes) -> Id { Id::from_u64(0) }
+//! # fn record(&self, _: &Id, _: &Record) {}
+//! # fn event(&self, _: &tracing::Event) {}
+//! # fn record_follows_from(&self, _: &Id, _: &Id) {}
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn enter(&self, _: &Id) {}
+//! # fn exit(&self, _: &Id) {}
+//! # }
+//! # impl FooSubscriber {
+//! # fn new() -> Self { FooSubscriber }
+//! # }
+//! # fn main() {
+//!
+//! let my_subscriber = FooSubscriber::new();
+//! # #[cfg(feature = "std")]
+//! tracing::subscriber::with_default(my_subscriber, || {
+//! // Any trace events generated in this closure or by functions it calls
+//! // will be collected by `my_subscriber`.
+//! })
+//! # }
+//! ```
+//!
+//! This approach allows trace data to be collected by multiple subscribers
+//! within different contexts in the program. Note that the override only applies to the
+//! currently executing thread; other threads will not see the change from with_default.
+//!
+//! Any trace events generated outside the context of a subscriber will not be collected.
+//!
+//! Once a subscriber has been set, instrumentation points may be added to the
+//! executable using the `tracing` crate's macros.
+//!
+//! ## `log` Compatibility
+//!
+//! The [`log`] crate provides a simple, lightweight logging facade for Rust.
+//! While `tracing` builds upon `log`'s foundation with richer structured
+//! diagnostic data, `log`'s simplicity and ubiquity make it the "lowest common
+//! denominator" for text-based logging in Rust — a vast majority of Rust
+//! libraries and applications either emit or consume `log` records. Therefore,
+//! `tracing` provides multiple forms of interoperability with `log`: `tracing`
+//! instrumentation can emit `log` records, and a compatibility layer enables
+//! `tracing` [`Subscriber`]s to consume `log` records as `tracing` [`Event`]s.
+//!
+//! ### Emitting `log` Records
+//!
+//! This crate provides two feature flags, "log" and "log-always", which will
+//! cause [spans] and [events] to emit `log` records. When the "log" feature is
+//! enabled, if no `tracing` `Subscriber` is active, invoking an event macro or
+//! creating a span with fields will emit a `log` record. This is intended
+//! primarily for use in libraries which wish to emit diagnostics that can be
+//! consumed by applications using `tracing` *or* `log`, without paying the
+//! additional overhead of emitting both forms of diagnostics when `tracing` is
+//! in use.
+//!
+//! Enabling the "log-always" feature will cause `log` records to be emitted
+//! even if a `tracing` `Subscriber` _is_ set. This is intended to be used in
+//! applications where a `log` `Logger` is being used to record a textual log,
+//! and `tracing` is used only to record other forms of diagnostics (such as
+//! metrics, profiling, or distributed tracing data). Unlike the "log" feature,
+//! libraries generally should **not** enable the "log-always" feature, as doing
+//! so will prevent applications from being able to opt out of the `log` records.
+//!
+//! See [here][flags] for more details on this crate's feature flags.
+//!
+//! The generated `log` records' messages will be a string representation of the
+//! span or event's fields, and all additional information recorded by `log`
+//! (target, verbosity level, module path, file, and line number) will also be
+//! populated. Additionally, `log` records are also generated when spans are
+//! entered, exited, and closed. Since these additional span lifecycle logs have
+//! the potential to be very verbose, and don't include additional fields, they
+//! will always be emitted at the `Trace` level, rather than inheriting the
+//! level of the span that generated them. Furthermore, they are are categorized
+//! under a separate `log` target, "tracing::span" (and its sub-target,
+//! "tracing::span::active", for the logs on entering and exiting a span), which
+//! may be enabled or disabled separately from other `log` records emitted by
+//! `tracing`.
+//!
+//! ### Consuming `log` Records
+//!
+//! The [`tracing-log`] crate provides a compatibility layer which
+//! allows a `tracing` [`Subscriber`] to consume `log` records as though they
+//! were `tracing` [events]. This allows applications using `tracing` to record
+//! the logs emitted by dependencies using `log` as events within the context of
+//! the application's trace tree. See [that crate's documentation][log-tracer]
+//! for details.
+//!
+//! [log-tracer]: https://docs.rs/tracing-log/latest/tracing_log/#convert-log-records-to-tracing-events
+//!
+//! ## Related Crates
+//!
+//! In addition to `tracing` and `tracing-core`, the [`tokio-rs/tracing`] repository
+//! contains several additional crates designed to be used with the `tracing` ecosystem.
+//! This includes a collection of `Subscriber` implementations, as well as utility
+//! and adapter crates to assist in writing `Subscriber`s and instrumenting
+//! applications.
+//!
+//! In particular, the following crates are likely to be of interest:
+//!
+//! - [`tracing-futures`] provides a compatibility layer with the `futures`
+//! crate, allowing spans to be attached to `Future`s, `Stream`s, and `Executor`s.
+//! - [`tracing-subscriber`] provides `Subscriber` implementations and
+//! utilities for working with `Subscriber`s. This includes a [`FmtSubscriber`]
+//! `FmtSubscriber` for logging formatted trace data to stdout, with similar
+//! filtering and formatting to the [`env_logger`] crate.
+//! - [`tracing-log`] provides a compatibility layer with the [`log`] crate,
+//! allowing log messages to be recorded as `tracing` `Event`s within the
+//! trace tree. This is useful when a project using `tracing` have
+//! dependencies which use `log`. Note that if you're using
+//! `tracing-subscriber`'s `FmtSubscriber`, you don't need to depend on
+//! `tracing-log` directly.
+//! - [`tracing-appender`] provides utilities for outputting tracing data,
+//! including a file appender and non blocking writer.
+//!
+//! Additionally, there are also several third-party crates which are not
+//! maintained by the `tokio` project. These include:
+//!
+//! - [`tracing-timing`] implements inter-event timing metrics on top of `tracing`.
+//! It provides a subscriber that records the time elapsed between pairs of
+//! `tracing` events and generates histograms.
+//! - [`tracing-opentelemetry`] provides a subscriber for emitting traces to
+//! [OpenTelemetry]-compatible distributed tracing systems.
+//! - [`tracing-honeycomb`] Provides a layer that reports traces spanning multiple machines to [honeycomb.io]. Backed by [`tracing-distributed`].
+//! - [`tracing-distributed`] Provides a generic implementation of a layer that reports traces spanning multiple machines to some backend.
+//! - [`tracing-actix-web`] provides `tracing` integration for the `actix-web` web framework.
+//! - [`tracing-actix`] provides `tracing` integration for the `actix` actor
+//! framework.
+//! - [`tracing-gelf`] implements a subscriber for exporting traces in Greylog
+//! GELF format.
+//! - [`tracing-coz`] provides integration with the [coz] causal profiler
+//! (Linux-only).
+//! - [`tracing-bunyan-formatter`] provides a layer implementation that reports events and spans
+//! in [bunyan] format, enriched with timing information.
+//! - [`tracing-wasm`] provides a `Subscriber`/`Layer` implementation that reports
+//! events and spans via browser `console.log` and [User Timing API (`window.performance`)].
+//! - [`tracing-web`] provides a layer implementation of level-aware logging of events
+//! to web browsers' `console.*` and span events to the [User Timing API (`window.performance`)].
+//! - [`tide-tracing`] provides a [tide] middleware to trace all incoming requests and responses.
+//! - [`test-log`] takes care of initializing `tracing` for tests, based on
+//! environment variables with an `env_logger` compatible syntax.
+//! - [`tracing-unwrap`] provides convenience methods to report failed unwraps
+//! on `Result` or `Option` types to a `Subscriber`.
+//! - [`diesel-tracing`] provides integration with [`diesel`] database connections.
+//! - [`tracing-tracy`] provides a way to collect [Tracy] profiles in instrumented
+//! applications.
+//! - [`tracing-elastic-apm`] provides a layer for reporting traces to [Elastic APM].
+//! - [`tracing-etw`] provides a layer for emitting Windows [ETW] events.
+//! - [`tracing-fluent-assertions`] provides a fluent assertions-style testing
+//! framework for validating the behavior of `tracing` spans.
+//! - [`sentry-tracing`] provides a layer for reporting events and traces to [Sentry].
+//! - [`tracing-forest`] provides a subscriber that preserves contextual coherence by
+//! grouping together logs from the same spans during writing.
+//! - [`tracing-loki`] provides a layer for shipping logs to [Grafana Loki].
+//! - [`tracing-logfmt`] provides a layer that formats events and spans into the logfmt format.
+//! - [`reqwest-tracing`] provides a middleware to trace [`reqwest`] HTTP requests.
+//!
+//! If you're the maintainer of a `tracing` ecosystem crate not listed above,
+//! please let us know! We'd love to add your project to the list!
+//!
+//! [`tracing-opentelemetry`]: https://crates.io/crates/tracing-opentelemetry
+//! [OpenTelemetry]: https://opentelemetry.io/
+//! [`tracing-honeycomb`]: https://crates.io/crates/tracing-honeycomb
+//! [`tracing-distributed`]: https://crates.io/crates/tracing-distributed
+//! [honeycomb.io]: https://www.honeycomb.io/
+//! [`tracing-actix-web`]: https://crates.io/crates/tracing-actix-web
+//! [`tracing-actix`]: https://crates.io/crates/tracing-actix
+//! [`tracing-gelf`]: https://crates.io/crates/tracing-gelf
+//! [`tracing-coz`]: https://crates.io/crates/tracing-coz
+//! [coz]: https://github.com/plasma-umass/coz
+//! [`tracing-bunyan-formatter`]: https://crates.io/crates/tracing-bunyan-formatter
+//! [bunyan]: https://github.com/trentm/node-bunyan
+//! [`tracing-wasm`]: https://docs.rs/tracing-wasm
+//! [`tracing-web`]: https://docs.rs/tracing-web
+//! [User Timing API (`window.performance`)]: https://developer.mozilla.org/en-US/docs/Web/API/User_Timing_API
+//! [`tide-tracing`]: https://crates.io/crates/tide-tracing
+//! [tide]: https://crates.io/crates/tide
+//! [`test-log`]: https://crates.io/crates/test-log
+//! [`tracing-unwrap`]: https://docs.rs/tracing-unwrap
+//! [`diesel`]: https://crates.io/crates/diesel
+//! [`diesel-tracing`]: https://crates.io/crates/diesel-tracing
+//! [`tracing-tracy`]: https://crates.io/crates/tracing-tracy
+//! [Tracy]: https://github.com/wolfpld/tracy
+//! [`tracing-elastic-apm`]: https://crates.io/crates/tracing-elastic-apm
+//! [Elastic APM]: https://www.elastic.co/apm
+//! [`tracing-etw`]: https://github.com/microsoft/tracing-etw
+//! [ETW]: https://docs.microsoft.com/en-us/windows/win32/etw/about-event-tracing
+//! [`tracing-fluent-assertions`]: https://crates.io/crates/tracing-fluent-assertions
+//! [`sentry-tracing`]: https://crates.io/crates/sentry-tracing
+//! [Sentry]: https://sentry.io/welcome/
+//! [`tracing-forest`]: https://crates.io/crates/tracing-forest
+//! [`tracing-loki`]: https://crates.io/crates/tracing-loki
+//! [Grafana Loki]: https://grafana.com/oss/loki/
+//! [`tracing-logfmt`]: https://crates.io/crates/tracing-logfmt
+//! [`reqwest-tracing`]: https://crates.io/crates/reqwest-tracing
+//! [`reqwest`]: https://crates.io/crates/reqwest
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>: Some of these ecosystem crates are currently
+//! unreleased and/or in earlier stages of development. They may be less stable
+//! than <code>tracing</code> and <code>tracing-core</code>.
+//! </pre>
+//!
+//! ## Crate Feature Flags
+//!
+//! The following crate [feature flags] are available:
+//!
+//! * A set of features controlling the [static verbosity level].
+//! * `log`: causes trace instrumentation points to emit [`log`] records as well
+//! as trace events, if a default `tracing` subscriber has not been set. This
+//! is intended for use in libraries whose users may be using either `tracing`
+//! or `log`.
+//! * `log-always`: Emit `log` records from all `tracing` spans and events, even
+//! if a `tracing` subscriber has been set. This should be set only by
+//! applications which intend to collect traces and logs separately; if an
+//! adapter is used to convert `log` records into `tracing` events, this will
+//! cause duplicate events to occur.
+//! * `attributes`: Includes support for the `#[instrument]` attribute.
+//! This is on by default, but does bring in the `syn` crate as a dependency,
+//! which may add to the compile time of crates that do not already use it.
+//! * `std`: Depend on the Rust standard library (enabled by default).
+//!
+//! `no_std` users may disable this feature with `default-features = false`:
+//!
+//! ```toml
+//! [dependencies]
+//! tracing = { version = "0.1.37", default-features = false }
+//! ```
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>: <code>tracing</code>'s <code>no_std</code> support
+//! requires <code>liballoc</code>.
+//! </pre>
+//!
+//! ### Unstable Features
+//!
+//! These feature flags enable **unstable** features. The public API may break in 0.1.x
+//! releases. To enable these features, the `--cfg tracing_unstable` must be passed to
+//! `rustc` when compiling.
+//!
+//! The following unstable feature flags are currently available:
+//!
+//! * `valuable`: Enables support for recording [field values] using the
+//! [`valuable`] crate.
+//!
+//! #### Enabling Unstable Features
+//!
+//! The easiest way to set the `tracing_unstable` cfg is to use the `RUSTFLAGS`
+//! env variable when running `cargo` commands:
+//!
+//! ```shell
+//! RUSTFLAGS="--cfg tracing_unstable" cargo build
+//! ```
+//! Alternatively, the following can be added to the `.cargo/config` file in a
+//! project to automatically enable the cfg flag for that project:
+//!
+//! ```toml
+//! [build]
+//! rustflags = ["--cfg", "tracing_unstable"]
+//! ```
+//!
+//! [feature flags]: https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section
+//! [field values]: crate::field
+//! [`valuable`]: https://crates.io/crates/valuable
+//!
+//! ## Supported Rust Versions
+//!
+//! Tracing is built against the latest stable release. The minimum supported
+//! version is 1.49. The current Tracing version is not guaranteed to build on
+//! Rust versions earlier than the minimum supported version.
+//!
+//! Tracing follows the same compiler support policies as the rest of the Tokio
+//! project. The current stable Rust compiler and the three most recent minor
+//! versions before it will always be supported. For example, if the current
+//! stable compiler version is 1.45, the minimum supported version will not be
+//! increased past 1.42, three minor versions prior. Increasing the minimum
+//! supported compiler version is not considered a semver breaking change as
+//! long as doing so complies with this policy.
+//!
+//! [`log`]: https://docs.rs/log/0.4.6/log/
+//! [span]: mod@span
+//! [spans]: mod@span
+//! [`Span`]: span::Span
+//! [`in_scope`]: span::Span::in_scope
+//! [event]: Event
+//! [events]: Event
+//! [`Subscriber`]: subscriber::Subscriber
+//! [Subscriber::event]: subscriber::Subscriber::event
+//! [`enter`]: subscriber::Subscriber::enter
+//! [`exit`]: subscriber::Subscriber::exit
+//! [`enabled`]: subscriber::Subscriber::enabled
+//! [metadata]: Metadata
+//! [`field::display`]: field::display
+//! [`field::debug`]: field::debug
+//! [`set_global_default`]: subscriber::set_global_default
+//! [`with_default`]: subscriber::with_default
+//! [`tokio-rs/tracing`]: https://github.com/tokio-rs/tracing
+//! [`tracing-futures`]: https://crates.io/crates/tracing-futures
+//! [`tracing-subscriber`]: https://crates.io/crates/tracing-subscriber
+//! [`tracing-log`]: https://crates.io/crates/tracing-log
+//! [`tracing-timing`]: https://crates.io/crates/tracing-timing
+//! [`tracing-appender`]: https://crates.io/crates/tracing-appender
+//! [`env_logger`]: https://crates.io/crates/env_logger
+//! [`FmtSubscriber`]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/struct.Subscriber.html
+//! [static verbosity level]: level_filters#compile-time-filters
+//! [instrument]: https://docs.rs/tracing-attributes/latest/tracing_attributes/attr.instrument.html
+//! [flags]: #crate-feature-flags
+#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(docsrs, feature(doc_cfg), deny(rustdoc::broken_intra_doc_links))]
+#![doc(html_root_url = "https://docs.rs/tracing/0.1.37")]
+#![doc(
+ html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png",
+ issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/"
+)]
+#![warn(
+ missing_debug_implementations,
+ missing_docs,
+ rust_2018_idioms,
+ unreachable_pub,
+ bad_style,
+ const_err,
+ dead_code,
+ improper_ctypes,
+ non_shorthand_field_patterns,
+ no_mangle_generic_items,
+ overflowing_literals,
+ path_statements,
+ patterns_in_fns_without_body,
+ private_in_public,
+ unconditional_recursion,
+ unused,
+ unused_allocation,
+ unused_comparisons,
+ unused_parens,
+ while_true
+)]
+
+#[cfg(not(feature = "std"))]
+extern crate alloc;
+
+// Somehow this `use` statement is necessary for us to re-export the `core`
+// macros on Rust 1.26.0. I'm not sure how this makes it work, but it does.
+#[allow(unused_imports)]
+#[doc(hidden)]
+use tracing_core::*;
+
+#[doc(inline)]
+pub use self::instrument::Instrument;
+pub use self::{dispatcher::Dispatch, event::Event, field::Value, subscriber::Subscriber};
+
+#[doc(hidden)]
+pub use self::span::Id;
+
+#[doc(hidden)]
+pub use tracing_core::{
+ callsite::{self, Callsite},
+ metadata,
+};
+pub use tracing_core::{event, Level, Metadata};
+
+#[doc(inline)]
+pub use self::span::Span;
+#[cfg(feature = "attributes")]
+#[cfg_attr(docsrs, doc(cfg(feature = "attributes")))]
+#[doc(inline)]
+pub use tracing_attributes::instrument;
+
+#[macro_use]
+mod macros;
+
+pub mod dispatcher;
+pub mod field;
+/// Attach a span to a `std::future::Future`.
+pub mod instrument;
+pub mod level_filters;
+pub mod span;
+pub(crate) mod stdlib;
+pub mod subscriber;
+
+#[doc(hidden)]
+pub mod __macro_support {
+ pub use crate::callsite::Callsite;
+ use crate::{subscriber::Interest, Metadata};
+ pub use core::concat;
+
+ /// Callsite implementation used by macro-generated code.
+ ///
+ /// /!\ WARNING: This is *not* a stable API! /!\
+ /// This type, and all code contained in the `__macro_support` module, is
+ /// a *private* API of `tracing`. It is exposed publicly because it is used
+ /// by the `tracing` macros, but it is not part of the stable versioned API.
+ /// Breaking changes to this module may occur in small-numbered versions
+ /// without warning.
+ pub use tracing_core::callsite::DefaultCallsite as MacroCallsite;
+
+ /// /!\ WARNING: This is *not* a stable API! /!\
+ /// This function, and all code contained in the `__macro_support` module, is
+ /// a *private* API of `tracing`. It is exposed publicly because it is used
+ /// by the `tracing` macros, but it is not part of the stable versioned API.
+ /// Breaking changes to this module may occur in small-numbered versions
+ /// without warning.
+ pub fn __is_enabled(meta: &Metadata<'static>, interest: Interest) -> bool {
+ interest.is_always() || crate::dispatcher::get_default(|default| default.enabled(meta))
+ }
+
+ /// /!\ WARNING: This is *not* a stable API! /!\
+ /// This function, and all code contained in the `__macro_support` module, is
+ /// a *private* API of `tracing`. It is exposed publicly because it is used
+ /// by the `tracing` macros, but it is not part of the stable versioned API.
+ /// Breaking changes to this module may occur in small-numbered versions
+ /// without warning.
+ #[inline]
+ #[cfg(feature = "log")]
+ pub fn __disabled_span(meta: &'static Metadata<'static>) -> crate::Span {
+ crate::Span::new_disabled(meta)
+ }
+
+ /// /!\ WARNING: This is *not* a stable API! /!\
+ /// This function, and all code contained in the `__macro_support` module, is
+ /// a *private* API of `tracing`. It is exposed publicly because it is used
+ /// by the `tracing` macros, but it is not part of the stable versioned API.
+ /// Breaking changes to this module may occur in small-numbered versions
+ /// without warning.
+ #[inline]
+ #[cfg(not(feature = "log"))]
+ pub fn __disabled_span(_: &'static Metadata<'static>) -> crate::Span {
+ crate::Span::none()
+ }
+
+ /// /!\ WARNING: This is *not* a stable API! /!\
+ /// This function, and all code contained in the `__macro_support` module, is
+ /// a *private* API of `tracing`. It is exposed publicly because it is used
+ /// by the `tracing` macros, but it is not part of the stable versioned API.
+ /// Breaking changes to this module may occur in small-numbered versions
+ /// without warning.
+ #[cfg(feature = "log")]
+ pub fn __tracing_log(
+ meta: &Metadata<'static>,
+ logger: &'static dyn log::Log,
+ log_meta: log::Metadata<'_>,
+ values: &tracing_core::field::ValueSet<'_>,
+ ) {
+ logger.log(
+ &crate::log::Record::builder()
+ .file(meta.file())
+ .module_path(meta.module_path())
+ .line(meta.line())
+ .metadata(log_meta)
+ .args(format_args!(
+ "{}",
+ crate::log::LogValueSet {
+ values,
+ is_first: true
+ }
+ ))
+ .build(),
+ );
+ }
+}
+
+#[cfg(feature = "log")]
+#[doc(hidden)]
+pub mod log {
+ use core::fmt;
+ pub use log::*;
+ use tracing_core::field::{Field, ValueSet, Visit};
+
+ /// Utility to format [`ValueSet`]s for logging.
+ pub(crate) struct LogValueSet<'a> {
+ pub(crate) values: &'a ValueSet<'a>,
+ pub(crate) is_first: bool,
+ }
+
+ impl<'a> fmt::Display for LogValueSet<'a> {
+ #[inline]
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ struct LogVisitor<'a, 'b> {
+ f: &'a mut fmt::Formatter<'b>,
+ is_first: bool,
+ result: fmt::Result,
+ }
+
+ impl Visit for LogVisitor<'_, '_> {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ let res = if self.is_first {
+ self.is_first = false;
+ if field.name() == "message" {
+ write!(self.f, "{:?}", value)
+ } else {
+ write!(self.f, "{}={:?}", field.name(), value)
+ }
+ } else {
+ write!(self.f, " {}={:?}", field.name(), value)
+ };
+ if let Err(err) = res {
+ self.result = self.result.and(Err(err));
+ }
+ }
+
+ fn record_str(&mut self, field: &Field, value: &str) {
+ if field.name() == "message" {
+ self.record_debug(field, &format_args!("{}", value))
+ } else {
+ self.record_debug(field, &value)
+ }
+ }
+ }
+
+ let mut visit = LogVisitor {
+ f,
+ is_first: self.is_first,
+ result: Ok(()),
+ };
+ self.values.record(&mut visit);
+ visit.result
+ }
+ }
+}
+
+mod sealed {
+ pub trait Sealed {}
+}
diff --git a/third_party/rust/tracing/src/macros.rs b/third_party/rust/tracing/src/macros.rs
new file mode 100644
index 0000000000..f3968e5c11
--- /dev/null
+++ b/third_party/rust/tracing/src/macros.rs
@@ -0,0 +1,2504 @@
+/// Constructs a new span.
+///
+/// See [the top-level documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [lib]: crate#using-the-macros
+///
+/// # Examples
+///
+/// Creating a new span:
+/// ```
+/// # use tracing::{span, Level};
+/// # fn main() {
+/// let span = span!(Level::TRACE, "my span");
+/// let _enter = span.enter();
+/// // do work inside the span...
+/// # }
+/// ```
+#[macro_export]
+macro_rules! span {
+ (target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => {
+ $crate::span!(target: $target, parent: $parent, $lvl, $name,)
+ };
+ (target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+ {
+ use $crate::__macro_support::Callsite as _;
+ static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+ name: $name,
+ kind: $crate::metadata::Kind::SPAN,
+ target: $target,
+ level: $lvl,
+ fields: $($fields)*
+ };
+ let mut interest = $crate::subscriber::Interest::never();
+ if $crate::level_enabled!($lvl)
+ && { interest = CALLSITE.interest(); !interest.is_never() }
+ && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+ {
+ let meta = CALLSITE.metadata();
+ // span with explicit parent
+ $crate::Span::child_of(
+ $parent,
+ meta,
+ &$crate::valueset!(meta.fields(), $($fields)*),
+ )
+ } else {
+ let span = $crate::__macro_support::__disabled_span(CALLSITE.metadata());
+ $crate::if_log_enabled! { $lvl, {
+ span.record_all(&$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+ }};
+ span
+ }
+ }
+ };
+ (target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+ {
+ use $crate::__macro_support::Callsite as _;
+ static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+ name: $name,
+ kind: $crate::metadata::Kind::SPAN,
+ target: $target,
+ level: $lvl,
+ fields: $($fields)*
+ };
+ let mut interest = $crate::subscriber::Interest::never();
+ if $crate::level_enabled!($lvl)
+ && { interest = CALLSITE.interest(); !interest.is_never() }
+ && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+ {
+ let meta = CALLSITE.metadata();
+ // span with contextual parent
+ $crate::Span::new(
+ meta,
+ &$crate::valueset!(meta.fields(), $($fields)*),
+ )
+ } else {
+ let span = $crate::__macro_support::__disabled_span(CALLSITE.metadata());
+ $crate::if_log_enabled! { $lvl, {
+ span.record_all(&$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+ }};
+ span
+ }
+ }
+ };
+ (target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => {
+ $crate::span!(target: $target, parent: $parent, $lvl, $name,)
+ };
+ (parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ $name,
+ $($fields)*
+ )
+ };
+ (parent: $parent:expr, $lvl:expr, $name:expr) => {
+ $crate::span!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ $name,
+ )
+ };
+ (target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => {
+ $crate::span!(
+ target: $target,
+ $lvl,
+ $name,
+ $($fields)*
+ )
+ };
+ (target: $target:expr, $lvl:expr, $name:expr) => {
+ $crate::span!(target: $target, $lvl, $name,)
+ };
+ ($lvl:expr, $name:expr, $($fields:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ $lvl,
+ $name,
+ $($fields)*
+ )
+ };
+ ($lvl:expr, $name:expr) => {
+ $crate::span!(
+ target: module_path!(),
+ $lvl,
+ $name,
+ )
+ };
+}
+
+/// Constructs a span at the trace level.
+///
+/// [Fields] and [attributes] are set using the same syntax as the [`span!`]
+/// macro.
+///
+/// See [the top-level documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [lib]: crate#using-the-macros
+/// [attributes]: crate#configuring-attributes
+/// [Fields]: crate#recording-fields
+/// [`span!`]: crate::span!
+///
+/// # Examples
+///
+/// ```rust
+/// # use tracing::{trace_span, span, Level};
+/// # fn main() {
+/// trace_span!("my_span");
+/// // is equivalent to:
+/// span!(Level::TRACE, "my_span");
+/// # }
+/// ```
+///
+/// ```rust
+/// # use tracing::{trace_span, span, Level};
+/// # fn main() {
+/// let span = trace_span!("my span");
+/// span.in_scope(|| {
+/// // do work inside the span...
+/// });
+/// # }
+/// ```
+#[macro_export]
+macro_rules! trace_span {
+ (target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ parent: $parent,
+ $crate::Level::TRACE,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, parent: $parent:expr, $name:expr) => {
+ $crate::trace_span!(target: $target, parent: $parent, $name,)
+ };
+ (parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ $name,
+ $($field)*
+ )
+ };
+ (parent: $parent:expr, $name:expr) => {
+ $crate::trace_span!(parent: $parent, $name,)
+ };
+ (target: $target:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ $crate::Level::TRACE,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, $name:expr) => {
+ $crate::trace_span!(target: $target, $name,)
+ };
+ ($name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ $name,
+ $($field)*
+ )
+ };
+ ($name:expr) => { $crate::trace_span!($name,) };
+}
+
+/// Constructs a span at the debug level.
+///
+/// [Fields] and [attributes] are set using the same syntax as the [`span!`]
+/// macro.
+///
+/// See [the top-level documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [lib]: crate#using-the-macros
+/// [attributes]: crate#configuring-attributes
+/// [Fields]: crate#recording-fields
+/// [`span!`]: crate::span!
+///
+/// # Examples
+///
+/// ```rust
+/// # use tracing::{debug_span, span, Level};
+/// # fn main() {
+/// debug_span!("my_span");
+/// // is equivalent to:
+/// span!(Level::DEBUG, "my_span");
+/// # }
+/// ```
+///
+/// ```rust
+/// # use tracing::debug_span;
+/// # fn main() {
+/// let span = debug_span!("my span");
+/// span.in_scope(|| {
+/// // do work inside the span...
+/// });
+/// # }
+/// ```
+#[macro_export]
+macro_rules! debug_span {
+ (target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ parent: $parent,
+ $crate::Level::DEBUG,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, parent: $parent:expr, $name:expr) => {
+ $crate::debug_span!(target: $target, parent: $parent, $name,)
+ };
+ (parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ $name,
+ $($field)*
+ )
+ };
+ (parent: $parent:expr, $name:expr) => {
+ $crate::debug_span!(parent: $parent, $name,)
+ };
+ (target: $target:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ $crate::Level::DEBUG,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, $name:expr) => {
+ $crate::debug_span!(target: $target, $name,)
+ };
+ ($name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ $name,
+ $($field)*
+ )
+ };
+ ($name:expr) => {$crate::debug_span!($name,)};
+}
+
+/// Constructs a span at the info level.
+///
+/// [Fields] and [attributes] are set using the same syntax as the [`span!`]
+/// macro.
+///
+/// See [the top-level documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [lib]: crate#using-the-macros
+/// [attributes]: crate#configuring-attributes
+/// [Fields]: crate#recording-fields
+/// [`span!`]: crate::span!
+///
+/// # Examples
+///
+/// ```rust
+/// # use tracing::{span, info_span, Level};
+/// # fn main() {
+/// info_span!("my_span");
+/// // is equivalent to:
+/// span!(Level::INFO, "my_span");
+/// # }
+/// ```
+///
+/// ```rust
+/// # use tracing::info_span;
+/// # fn main() {
+/// let span = info_span!("my span");
+/// span.in_scope(|| {
+/// // do work inside the span...
+/// });
+/// # }
+/// ```
+#[macro_export]
+macro_rules! info_span {
+ (target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ parent: $parent,
+ $crate::Level::INFO,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, parent: $parent:expr, $name:expr) => {
+ $crate::info_span!(target: $target, parent: $parent, $name,)
+ };
+ (parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ $name,
+ $($field)*
+ )
+ };
+ (parent: $parent:expr, $name:expr) => {
+ $crate::info_span!(parent: $parent, $name,)
+ };
+ (target: $target:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ $crate::Level::INFO,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, $name:expr) => {
+ $crate::info_span!(target: $target, $name,)
+ };
+ ($name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ $name,
+ $($field)*
+ )
+ };
+ ($name:expr) => {$crate::info_span!($name,)};
+}
+
+/// Constructs a span at the warn level.
+///
+/// [Fields] and [attributes] are set using the same syntax as the [`span!`]
+/// macro.
+///
+/// See [the top-level documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [lib]: crate#using-the-macros
+/// [attributes]: crate#configuring-attributes
+/// [Fields]: crate#recording-fields
+/// [`span!`]: crate::span!
+///
+/// # Examples
+///
+/// ```rust
+/// # use tracing::{warn_span, span, Level};
+/// # fn main() {
+/// warn_span!("my_span");
+/// // is equivalent to:
+/// span!(Level::WARN, "my_span");
+/// # }
+/// ```
+///
+/// ```rust
+/// use tracing::warn_span;
+/// # fn main() {
+/// let span = warn_span!("my span");
+/// span.in_scope(|| {
+/// // do work inside the span...
+/// });
+/// # }
+/// ```
+#[macro_export]
+macro_rules! warn_span {
+ (target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ parent: $parent,
+ $crate::Level::WARN,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, parent: $parent:expr, $name:expr) => {
+ $crate::warn_span!(target: $target, parent: $parent, $name,)
+ };
+ (parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ $name,
+ $($field)*
+ )
+ };
+ (parent: $parent:expr, $name:expr) => {
+ $crate::warn_span!(parent: $parent, $name,)
+ };
+ (target: $target:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ $crate::Level::WARN,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, $name:expr) => {
+ $crate::warn_span!(target: $target, $name,)
+ };
+ ($name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ $name,
+ $($field)*
+ )
+ };
+ ($name:expr) => {$crate::warn_span!($name,)};
+}
+/// Constructs a span at the error level.
+///
+/// [Fields] and [attributes] are set using the same syntax as the [`span!`]
+/// macro.
+///
+/// See [the top-level documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [lib]: crate#using-the-macros
+/// [attributes]: crate#configuring-attributes
+/// [Fields]: crate#recording-fields
+/// [`span!`]: crate::span!
+///
+/// # Examples
+///
+/// ```rust
+/// # use tracing::{span, error_span, Level};
+/// # fn main() {
+/// error_span!("my_span");
+/// // is equivalent to:
+/// span!(Level::ERROR, "my_span");
+/// # }
+/// ```
+///
+/// ```rust
+/// # use tracing::error_span;
+/// # fn main() {
+/// let span = error_span!("my span");
+/// span.in_scope(|| {
+/// // do work inside the span...
+/// });
+/// # }
+/// ```
+#[macro_export]
+macro_rules! error_span {
+ (target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ parent: $parent,
+ $crate::Level::ERROR,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, parent: $parent:expr, $name:expr) => {
+ $crate::error_span!(target: $target, parent: $parent, $name,)
+ };
+ (parent: $parent:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ $name,
+ $($field)*
+ )
+ };
+ (parent: $parent:expr, $name:expr) => {
+ $crate::error_span!(parent: $parent, $name,)
+ };
+ (target: $target:expr, $name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: $target,
+ $crate::Level::ERROR,
+ $name,
+ $($field)*
+ )
+ };
+ (target: $target:expr, $name:expr) => {
+ $crate::error_span!(target: $target, $name,)
+ };
+ ($name:expr, $($field:tt)*) => {
+ $crate::span!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ $name,
+ $($field)*
+ )
+ };
+ ($name:expr) => {$crate::error_span!($name,)};
+}
+
+/// Constructs a new `Event`.
+///
+/// The event macro is invoked with a `Level` and up to 32 key-value fields.
+/// Optionally, a format string and arguments may follow the fields; this will
+/// be used to construct an implicit field named "message".
+///
+/// See [the top-level documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [lib]: crate#using-the-macros
+///
+/// # Examples
+///
+/// ```rust
+/// use tracing::{event, Level};
+///
+/// # fn main() {
+/// let data = (42, "forty-two");
+/// let private_data = "private";
+/// let error = "a bad error";
+///
+/// event!(Level::ERROR, %error, "Received error");
+/// event!(
+/// target: "app_events",
+/// Level::WARN,
+/// private_data,
+/// ?data,
+/// "App warning: {}",
+/// error
+/// );
+/// event!(Level::INFO, the_answer = data.0);
+/// # }
+/// ```
+///
+// /// Note that *unlike `span!`*, `event!` requires a value for all fields. As
+// /// events are recorded immediately when the macro is invoked, there is no
+// /// opportunity for fields to be recorded later. A trailing comma on the final
+// /// field is valid.
+// ///
+// /// For example, the following does not compile:
+// /// ```rust,compile_fail
+// /// # use tracing::{Level, event};
+// /// # fn main() {
+// /// event!(Level::INFO, foo = 5, bad_field, bar = "hello")
+// /// #}
+// /// ```
+#[macro_export]
+macro_rules! event {
+ (target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+ use $crate::__macro_support::Callsite as _;
+ static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+ name: $crate::__macro_support::concat!(
+ "event ",
+ file!(),
+ ":",
+ line!()
+ ),
+ kind: $crate::metadata::Kind::EVENT,
+ target: $target,
+ level: $lvl,
+ fields: $($fields)*
+ };
+
+ let enabled = $crate::level_enabled!($lvl) && {
+ let interest = CALLSITE.interest();
+ !interest.is_never() && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+ };
+ if enabled {
+ (|value_set: $crate::field::ValueSet| {
+ $crate::__tracing_log!(
+ $lvl,
+ CALLSITE,
+ &value_set
+ );
+ let meta = CALLSITE.metadata();
+ // event with explicit parent
+ $crate::Event::child_of(
+ $parent,
+ meta,
+ &value_set
+ );
+ })($crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+ } else {
+ $crate::__tracing_log!(
+ $lvl,
+ CALLSITE,
+ &$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*)
+ );
+ }
+ });
+
+ (target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: $target,
+ parent: $parent,
+ $lvl,
+ { message = format_args!($($arg)+), $($fields)* }
+ )
+ );
+ (target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+ $crate::event!(target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* })
+ );
+ (target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => (
+ $crate::event!(target: $target, parent: $parent, $lvl, { $($arg)+ })
+ );
+ (target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+ use $crate::__macro_support::Callsite as _;
+ static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+ name: $crate::__macro_support::concat!(
+ "event ",
+ file!(),
+ ":",
+ line!()
+ ),
+ kind: $crate::metadata::Kind::EVENT,
+ target: $target,
+ level: $lvl,
+ fields: $($fields)*
+ };
+ let enabled = $crate::level_enabled!($lvl) && {
+ let interest = CALLSITE.interest();
+ !interest.is_never() && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest)
+ };
+ if enabled {
+ (|value_set: $crate::field::ValueSet| {
+ let meta = CALLSITE.metadata();
+ // event with contextual parent
+ $crate::Event::dispatch(
+ meta,
+ &value_set
+ );
+ $crate::__tracing_log!(
+ $lvl,
+ CALLSITE,
+ &value_set
+ );
+ })($crate::valueset!(CALLSITE.metadata().fields(), $($fields)*));
+ } else {
+ $crate::__tracing_log!(
+ $lvl,
+ CALLSITE,
+ &$crate::valueset!(CALLSITE.metadata().fields(), $($fields)*)
+ );
+ }
+ });
+ (target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: $target,
+ $lvl,
+ { message = format_args!($($arg)+), $($fields)* }
+ )
+ );
+ (target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => (
+ $crate::event!(target: $target, $lvl, { $($k).+ = $($fields)* })
+ );
+ (target: $target:expr, $lvl:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, $lvl, { $($arg)+ })
+ );
+ (parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ { message = format_args!($($arg)+), $($fields)* }
+ )
+ );
+ (parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $lvl:expr, ?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $lvl:expr, %$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $lvl:expr, $($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ { $($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $lvl:expr, %$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $lvl:expr, ?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $lvl,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $lvl:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: module_path!(), parent: $parent, $lvl, { $($arg)+ })
+ );
+ ( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ $lvl,
+ { message = format_args!($($arg)+), $($fields)* }
+ )
+ );
+ ( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ $lvl,
+ { message = format_args!($($arg)+), $($fields)* }
+ )
+ );
+ ($lvl:expr, $($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $lvl,
+ { $($k).+ = $($field)*}
+ )
+ );
+ ($lvl:expr, $($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $lvl,
+ { $($k).+, $($field)*}
+ )
+ );
+ ($lvl:expr, ?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $lvl,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ ($lvl:expr, %$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $lvl,
+ { %$($k).+, $($field)*}
+ )
+ );
+ ($lvl:expr, ?$($k:ident).+) => (
+ $crate::event!($lvl, ?$($k).+,)
+ );
+ ($lvl:expr, %$($k:ident).+) => (
+ $crate::event!($lvl, %$($k).+,)
+ );
+ ($lvl:expr, $($k:ident).+) => (
+ $crate::event!($lvl, $($k).+,)
+ );
+ ( $lvl:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: module_path!(), $lvl, { $($arg)+ })
+ );
+}
+
+/// Tests whether an event with the specified level and target would be enabled.
+///
+/// This is similar to [`enabled!`], but queries the current subscriber specifically for
+/// an event, whereas [`enabled!`] queries for an event _or_ span.
+///
+/// See the documentation for [`enabled!]` for more details on using this macro.
+/// See also [`span_enabled!`].
+///
+/// # Examples
+///
+/// ```rust
+/// # use tracing::{event_enabled, Level};
+/// if event_enabled!(target: "my_crate", Level::DEBUG) {
+/// // some expensive work...
+/// }
+/// // simpler
+/// if event_enabled!(Level::DEBUG) {
+/// // some expensive work...
+/// }
+/// // with fields
+/// if event_enabled!(Level::DEBUG, foo_field) {
+/// // some expensive work...
+/// }
+/// ```
+///
+/// [`enabled!`]: crate::enabled
+/// [`span_enabled!`]: crate::span_enabled
+#[macro_export]
+macro_rules! event_enabled {
+ ($($rest:tt)*)=> (
+ $crate::enabled!(kind: $crate::metadata::Kind::EVENT, $($rest)*)
+ )
+}
+
+/// Tests whether a span with the specified level and target would be enabled.
+///
+/// This is similar to [`enabled!`], but queries the current subscriber specifically for
+/// an event, whereas [`enabled!`] queries for an event _or_ span.
+///
+/// See the documentation for [`enabled!]` for more details on using this macro.
+/// See also [`span_enabled!`].
+///
+/// # Examples
+///
+/// ```rust
+/// # use tracing::{span_enabled, Level};
+/// if span_enabled!(target: "my_crate", Level::DEBUG) {
+/// // some expensive work...
+/// }
+/// // simpler
+/// if span_enabled!(Level::DEBUG) {
+/// // some expensive work...
+/// }
+/// // with fields
+/// if span_enabled!(Level::DEBUG, foo_field) {
+/// // some expensive work...
+/// }
+/// ```
+///
+/// [`enabled!`]: crate::enabled
+/// [`span_enabled!`]: crate::span_enabled
+#[macro_export]
+macro_rules! span_enabled {
+ ($($rest:tt)*)=> (
+ $crate::enabled!(kind: $crate::metadata::Kind::SPAN, $($rest)*)
+ )
+}
+
+/// Checks whether a span or event is [enabled] based on the provided [metadata].
+///
+/// [enabled]: crate::Subscriber::enabled
+/// [metadata]: crate::Metadata
+///
+/// This macro is a specialized tool: it is intended to be used prior
+/// to an expensive computation required *just* for that event, but
+/// *cannot* be done as part of an argument to that event, such as
+/// when multiple events are emitted (e.g., iterating over a collection
+/// and emitting an event for each item).
+///
+/// # Usage
+///
+/// [Subscribers] can make filtering decisions based all the data included in a
+/// span or event's [`Metadata`]. This means that it is possible for `enabled!`
+/// to return a _false positive_ (indicating that something would be enabled
+/// when it actually would not be) or a _false negative_ (indicating that
+/// something would be disabled when it would actually be enabled).
+///
+/// [Subscribers]: crate::subscriber::Subscriber
+/// [`Metadata`]: crate::metadata::Metadata
+///
+/// This occurs when a subscriber is using a _more specific_ filter than the
+/// metadata provided to the `enabled!` macro. Some situations that can result
+/// in false positives or false negatives include:
+///
+/// - If a subscriber is using a filter which may enable a span or event based
+/// on field names, but `enabled!` is invoked without listing field names,
+/// `enabled!` may return a false negative if a specific field name would
+/// cause the subscriber to enable something that would otherwise be disabled.
+/// - If a subscriber is using a filter which enables or disables specific events by
+/// file path and line number, a particular event may be enabled/disabled
+/// even if an `enabled!` invocation with the same level, target, and fields
+/// indicated otherwise.
+/// - The subscriber can choose to enable _only_ spans or _only_ events, which `enabled`
+/// will not reflect.
+///
+/// `enabled!()` requires a [level](crate::Level) argument, an optional `target:`
+/// argument, and an optional set of field names. If the fields are not provided,
+/// they are considered to be unknown. `enabled!` attempts to match the
+/// syntax of `event!()` as closely as possible, which can be seen in the
+/// examples below.
+///
+/// # Examples
+///
+/// If the current subscriber is interested in recording `DEBUG`-level spans and
+/// events in the current file and module path, this will evaluate to true:
+/// ```rust
+/// use tracing::{enabled, Level};
+///
+/// if enabled!(Level::DEBUG) {
+/// // some expensive work...
+/// }
+/// ```
+///
+/// If the current subscriber is interested in recording spans and events
+/// in the current file and module path, with the target "my_crate", and at the
+/// level `DEBUG`, this will evaluate to true:
+/// ```rust
+/// # use tracing::{enabled, Level};
+/// if enabled!(target: "my_crate", Level::DEBUG) {
+/// // some expensive work...
+/// }
+/// ```
+///
+/// If the current subscriber is interested in recording spans and events
+/// in the current file and module path, with the target "my_crate", at
+/// the level `DEBUG`, and with a field named "hello", this will evaluate
+/// to true:
+///
+/// ```rust
+/// # use tracing::{enabled, Level};
+/// if enabled!(target: "my_crate", Level::DEBUG, hello) {
+/// // some expensive work...
+/// }
+/// ```
+///
+/// # Alternatives
+///
+/// `enabled!` queries subscribers with [`Metadata`] where
+/// [`is_event`] and [`is_span`] both return `false`. Alternatively,
+/// use [`event_enabled!`] or [`span_enabled!`] to ensure one of these
+/// returns true.
+///
+///
+/// [`Metadata`]: crate::Metadata
+/// [`is_event`]: crate::Metadata::is_event
+/// [`is_span`]: crate::Metadata::is_span
+/// [`enabled!`]: crate::enabled
+/// [`span_enabled!`]: crate::span_enabled
+#[macro_export]
+macro_rules! enabled {
+ (kind: $kind:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({
+ if $crate::level_enabled!($lvl) {
+ use $crate::__macro_support::Callsite as _;
+ static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! {
+ name: $crate::__macro_support::concat!(
+ "enabled ",
+ file!(),
+ ":",
+ line!()
+ ),
+ kind: $kind.hint(),
+ target: $target,
+ level: $lvl,
+ fields: $($fields)*
+ };
+ let interest = CALLSITE.interest();
+ if !interest.is_never() && $crate::__macro_support::__is_enabled(CALLSITE.metadata(), interest) {
+ let meta = CALLSITE.metadata();
+ $crate::dispatcher::get_default(|current| current.enabled(meta))
+ } else {
+ false
+ }
+ } else {
+ false
+ }
+ });
+ // Just target and level
+ (kind: $kind:expr, target: $target:expr, $lvl:expr ) => (
+ $crate::enabled!(kind: $kind, target: $target, $lvl, { })
+ );
+ (target: $target:expr, $lvl:expr ) => (
+ $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: $target, $lvl, { })
+ );
+
+ // These four cases handle fields with no values
+ (kind: $kind:expr, target: $target:expr, $lvl:expr, $($field:tt)*) => (
+ $crate::enabled!(
+ kind: $kind,
+ target: $target,
+ $lvl,
+ { $($field)*}
+ )
+ );
+ (target: $target:expr, $lvl:expr, $($field:tt)*) => (
+ $crate::enabled!(
+ kind: $crate::metadata::Kind::HINT,
+ target: $target,
+ $lvl,
+ { $($field)*}
+ )
+ );
+
+ // Level and field case
+ (kind: $kind:expr, $lvl:expr, $($field:tt)*) => (
+ $crate::enabled!(
+ kind: $kind,
+ target: module_path!(),
+ $lvl,
+ { $($field)*}
+ )
+ );
+
+ // Simplest `enabled!` case
+ (kind: $kind:expr, $lvl:expr) => (
+ $crate::enabled!(kind: $kind, target: module_path!(), $lvl, { })
+ );
+ ($lvl:expr) => (
+ $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: module_path!(), $lvl, { })
+ );
+
+ // Fallthrough from above
+ ($lvl:expr, $($field:tt)*) => (
+ $crate::enabled!(
+ kind: $crate::metadata::Kind::HINT,
+ target: module_path!(),
+ $lvl,
+ { $($field)*}
+ )
+ );
+}
+
+/// Constructs an event at the trace level.
+///
+/// This functions similarly to the [`event!`] macro. See [the top-level
+/// documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [`event!`]: crate::event!
+/// [lib]: crate#using-the-macros
+///
+/// # Examples
+///
+/// ```rust
+/// use tracing::trace;
+/// # #[derive(Debug, Copy, Clone)] struct Position { x: f32, y: f32 }
+/// # impl Position {
+/// # const ORIGIN: Self = Self { x: 0.0, y: 0.0 };
+/// # fn dist(&self, other: Position) -> f32 {
+/// # let x = (other.x - self.x).exp2(); let y = (self.y - other.y).exp2();
+/// # (x + y).sqrt()
+/// # }
+/// # }
+/// # fn main() {
+/// let pos = Position { x: 3.234, y: -1.223 };
+/// let origin_dist = pos.dist(Position::ORIGIN);
+///
+/// trace!(position = ?pos, ?origin_dist);
+/// trace!(
+/// target: "app_events",
+/// position = ?pos,
+/// "x is {} and y is {}",
+/// if pos.x >= 0.0 { "positive" } else { "negative" },
+/// if pos.y >= 0.0 { "positive" } else { "negative" }
+/// );
+/// # }
+/// ```
+#[macro_export]
+macro_rules! trace {
+ (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+)
+ );
+ (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ { $($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::TRACE,
+ {},
+ $($arg)+
+ )
+ );
+ (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::TRACE, { $($k).+ $($field)* })
+ );
+ (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* })
+ );
+ (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* })
+ );
+ (target: $target:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, $crate::Level::TRACE, {}, $($arg)+)
+ );
+ ({ $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ ($($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { $($k).+ = $($field)*}
+ )
+ );
+ ($($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { $($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (%$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { ?$($k).+ }
+ )
+ );
+ (%$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { %$($k).+ }
+ )
+ );
+ ($($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ { $($k).+ }
+ )
+ );
+ ($($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::TRACE,
+ {},
+ $($arg)+
+ )
+ );
+}
+
+/// Constructs an event at the debug level.
+///
+/// This functions similarly to the [`event!`] macro. See [the top-level
+/// documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [`event!`]: crate::event!
+/// [lib]: crate#using-the-macros
+///
+/// # Examples
+///
+/// ```rust
+/// use tracing::debug;
+/// # fn main() {
+/// # #[derive(Debug)] struct Position { x: f32, y: f32 }
+///
+/// let pos = Position { x: 3.234, y: -1.223 };
+///
+/// debug!(?pos.x, ?pos.y);
+/// debug!(target: "app_events", position = ?pos, "New position");
+/// # }
+/// ```
+#[macro_export]
+macro_rules! debug {
+ (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+)
+ );
+ (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ { $($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::DEBUG,
+ {},
+ $($arg)+
+ )
+ );
+ (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* })
+ );
+ (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* })
+ );
+ (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* })
+ );
+ (target: $target:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+)
+ );
+ ({ $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ ($($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (%$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ ($($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { $($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (%$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { ?$($k).+ }
+ )
+ );
+ (%$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { %$($k).+ }
+ )
+ );
+ ($($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ { $($k).+ }
+ )
+ );
+ ($($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::DEBUG,
+ {},
+ $($arg)+
+ )
+ );
+}
+
+/// Constructs an event at the info level.
+///
+/// This functions similarly to the [`event!`] macro. See [the top-level
+/// documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [`event!`]: crate::event!
+/// [lib]: crate#using-the-macros
+///
+/// # Examples
+///
+/// ```rust
+/// use tracing::info;
+/// # // this is so the test will still work in no-std mode
+/// # #[derive(Debug)]
+/// # pub struct Ipv4Addr;
+/// # impl Ipv4Addr { fn new(o1: u8, o2: u8, o3: u8, o4: u8) -> Self { Self } }
+/// # fn main() {
+/// # struct Connection { port: u32, speed: f32 }
+/// use tracing::field;
+///
+/// let addr = Ipv4Addr::new(127, 0, 0, 1);
+/// let conn = Connection { port: 40, speed: 3.20 };
+///
+/// info!(conn.port, "connected to {:?}", addr);
+/// info!(
+/// target: "connection_events",
+/// ip = ?addr,
+/// conn.port,
+/// ?conn.speed,
+/// );
+/// # }
+/// ```
+#[macro_export]
+macro_rules! info {
+ (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+)
+ );
+ (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ { $($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::INFO,
+ {},
+ $($arg)+
+ )
+ );
+ (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
+ );
+ (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* })
+ );
+ (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* })
+ );
+ (target: $target:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, $crate::Level::INFO, {}, $($arg)+)
+ );
+ ({ $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ ($($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (%$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ ($($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { $($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (%$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { ?$($k).+ }
+ )
+ );
+ (%$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { %$($k).+ }
+ )
+ );
+ ($($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ { $($k).+ }
+ )
+ );
+ ($($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::INFO,
+ {},
+ $($arg)+
+ )
+ );
+}
+
+/// Constructs an event at the warn level.
+///
+/// This functions similarly to the [`event!`] macro. See [the top-level
+/// documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [`event!`]: crate::event!
+/// [lib]: crate#using-the-macros
+///
+/// # Examples
+///
+/// ```rust
+/// use tracing::warn;
+/// # fn main() {
+///
+/// let warn_description = "Invalid Input";
+/// let input = &[0x27, 0x45];
+///
+/// warn!(?input, warning = warn_description);
+/// warn!(
+/// target: "input_events",
+/// warning = warn_description,
+/// "Received warning for input: {:?}", input,
+/// );
+/// # }
+/// ```
+#[macro_export]
+macro_rules! warn {
+ (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+)
+ );
+ (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ { $($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::WARN,
+ {},
+ $($arg)+
+ )
+ );
+ (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::WARN, { $($k).+ $($field)* })
+ );
+ (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* })
+ );
+ (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::WARN, { %$($k).+ $($field)* })
+ );
+ (target: $target:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, $crate::Level::WARN, {}, $($arg)+)
+ );
+ ({ $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ ($($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (%$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ ($($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { $($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (%$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { ?$($k).+ }
+ )
+ );
+ (%$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { %$($k).+ }
+ )
+ );
+ ($($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ { $($k).+ }
+ )
+ );
+ ($($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::WARN,
+ {},
+ $($arg)+
+ )
+ );
+}
+
+/// Constructs an event at the error level.
+///
+/// This functions similarly to the [`event!`] macro. See [the top-level
+/// documentation][lib] for details on the syntax accepted by
+/// this macro.
+///
+/// [`event!`]: crate::event!
+/// [lib]: crate#using-the-macros
+///
+/// # Examples
+///
+/// ```rust
+/// use tracing::error;
+/// # fn main() {
+///
+/// let (err_info, port) = ("No connection", 22);
+///
+/// error!(port, error = %err_info);
+/// error!(target: "app_events", "App Error: {}", err_info);
+/// error!({ info = err_info }, "error on port: {}", port);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! error {
+ (target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)+ })
+ );
+ (target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+)
+ );
+ (parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ { $($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (parent: $parent:expr, $($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ parent: $parent,
+ $crate::Level::ERROR,
+ {},
+ $($arg)+
+ )
+ );
+ (target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*)
+ );
+ (target: $target:expr, $($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::ERROR, { $($k).+ $($field)* })
+ );
+ (target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* })
+ );
+ (target: $target:expr, %$($k:ident).+ $($field:tt)* ) => (
+ $crate::event!(target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* })
+ );
+ (target: $target:expr, $($arg:tt)+ ) => (
+ $crate::event!(target: $target, $crate::Level::ERROR, {}, $($arg)+)
+ );
+ ({ $($field:tt)+ }, $($arg:tt)+ ) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { $($field)+ },
+ $($arg)+
+ )
+ );
+ ($($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { $($k).+ = $($field)*}
+ )
+ );
+ (?$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { ?$($k).+ = $($field)*}
+ )
+ );
+ (%$($k:ident).+ = $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { %$($k).+ = $($field)*}
+ )
+ );
+ ($($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { $($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { ?$($k).+, $($field)*}
+ )
+ );
+ (%$($k:ident).+, $($field:tt)*) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { %$($k).+, $($field)*}
+ )
+ );
+ (?$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { ?$($k).+ }
+ )
+ );
+ (%$($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { %$($k).+ }
+ )
+ );
+ ($($k:ident).+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ { $($k).+ }
+ )
+ );
+ ($($arg:tt)+) => (
+ $crate::event!(
+ target: module_path!(),
+ $crate::Level::ERROR,
+ {},
+ $($arg)+
+ )
+ );
+}
+
+/// Constructs a new static callsite for a span or event.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! callsite {
+ (name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{
+ $crate::callsite! {
+ name: $name,
+ kind: $kind,
+ target: module_path!(),
+ level: $crate::Level::TRACE,
+ fields: $($fields)*
+ }
+ }};
+ (
+ name: $name:expr,
+ kind: $kind:expr,
+ level: $lvl:expr,
+ fields: $($fields:tt)*
+ ) => {{
+ $crate::callsite! {
+ name: $name,
+ kind: $kind,
+ target: module_path!(),
+ level: $lvl,
+ fields: $($fields)*
+ }
+ }};
+ (
+ name: $name:expr,
+ kind: $kind:expr,
+ target: $target:expr,
+ level: $lvl:expr,
+ fields: $($fields:tt)*
+ ) => {{
+ static META: $crate::Metadata<'static> = {
+ $crate::metadata! {
+ name: $name,
+ target: $target,
+ level: $lvl,
+ fields: $crate::fieldset!( $($fields)* ),
+ callsite: &CALLSITE,
+ kind: $kind,
+ }
+ };
+ static CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite::DefaultCallsite::new(&META);
+ CALLSITE.register();
+ &CALLSITE
+ }};
+}
+
+/// Constructs a new static callsite for a span or event.
+#[doc(hidden)]
+#[macro_export]
+macro_rules! callsite2 {
+ (name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{
+ $crate::callsite2! {
+ name: $name,
+ kind: $kind,
+ target: module_path!(),
+ level: $crate::Level::TRACE,
+ fields: $($fields)*
+ }
+ }};
+ (
+ name: $name:expr,
+ kind: $kind:expr,
+ level: $lvl:expr,
+ fields: $($fields:tt)*
+ ) => {{
+ $crate::callsite2! {
+ name: $name,
+ kind: $kind,
+ target: module_path!(),
+ level: $lvl,
+ fields: $($fields)*
+ }
+ }};
+ (
+ name: $name:expr,
+ kind: $kind:expr,
+ target: $target:expr,
+ level: $lvl:expr,
+ fields: $($fields:tt)*
+ ) => {{
+ static META: $crate::Metadata<'static> = {
+ $crate::metadata! {
+ name: $name,
+ target: $target,
+ level: $lvl,
+ fields: $crate::fieldset!( $($fields)* ),
+ callsite: &CALLSITE,
+ kind: $kind,
+ }
+ };
+ $crate::callsite::DefaultCallsite::new(&META)
+ }};
+}
+
+#[macro_export]
+// TODO: determine if this ought to be public API?`
+#[doc(hidden)]
+macro_rules! level_enabled {
+ ($lvl:expr) => {
+ $lvl <= $crate::level_filters::STATIC_MAX_LEVEL
+ && $lvl <= $crate::level_filters::LevelFilter::current()
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! valueset {
+
+ // === base case ===
+ (@ { $(,)* $($val:expr),* $(,)* }, $next:expr $(,)*) => {
+ &[ $($val),* ]
+ };
+
+ // === recursive case (more tts) ===
+
+ // TODO(#1138): determine a new syntax for uninitialized span fields, and
+ // re-enable this.
+ // (@{ $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = _, $($rest:tt)*) => {
+ // $crate::valueset!(@ { $($out),*, (&$next, None) }, $next, $($rest)*)
+ // };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&$($k).+ as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&debug(&$($k).+) as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&display(&$($k).+) as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+ $next,
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+ $next,
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+ $next,
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&$($k).+ as &dyn Value)) },
+ $next,
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&debug(&$($k).+) as &dyn Value)) },
+ $next,
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&display(&$($k).+) as &dyn Value)) },
+ $next,
+ )
+ };
+
+ // Handle literal names
+ (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr, $($rest:tt)*) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+ $next,
+ $($rest)*
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) },
+ $next,
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) },
+ $next,
+ )
+ };
+ (@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr) => {
+ $crate::valueset!(
+ @ { $($out),*, (&$next, Some(&$val as &dyn Value)) },
+ $next,
+ )
+ };
+
+ // Remainder is unparseable, but exists --- must be format args!
+ (@ { $(,)* $($out:expr),* }, $next:expr, $($rest:tt)+) => {
+ $crate::valueset!(@ { (&$next, Some(&format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, )
+ };
+
+ // === entry ===
+ ($fields:expr, $($kvs:tt)+) => {
+ {
+ #[allow(unused_imports)]
+ use $crate::field::{debug, display, Value};
+ let mut iter = $fields.iter();
+ $fields.value_set($crate::valueset!(
+ @ { },
+ iter.next().expect("FieldSet corrupted (this is a bug)"),
+ $($kvs)+
+ ))
+ }
+ };
+ ($fields:expr,) => {
+ {
+ $fields.value_set(&[])
+ }
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! fieldset {
+ // == base case ==
+ (@ { $(,)* $($out:expr),* $(,)* } $(,)*) => {
+ &[ $($out),* ]
+ };
+
+ // == recursive cases (more tts) ==
+ (@ { $(,)* $($out:expr),* } $($k:ident).+ = ?$val:expr, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+ };
+ (@ { $(,)* $($out:expr),* } $($k:ident).+ = %$val:expr, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+ };
+ (@ { $(,)* $($out:expr),* } $($k:ident).+ = $val:expr, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+ };
+ // TODO(#1138): determine a new syntax for uninitialized span fields, and
+ // re-enable this.
+ // (@ { $($out:expr),* } $($k:ident).+ = _, $($rest:tt)*) => {
+ // $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+ // };
+ (@ { $(,)* $($out:expr),* } ?$($k:ident).+, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+ };
+ (@ { $(,)* $($out:expr),* } %$($k:ident).+, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+ };
+ (@ { $(,)* $($out:expr),* } $($k:ident).+, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*)
+ };
+
+ // Handle literal names
+ (@ { $(,)* $($out:expr),* } $k:literal = ?$val:expr, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+ };
+ (@ { $(,)* $($out:expr),* } $k:literal = %$val:expr, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+ };
+ (@ { $(,)* $($out:expr),* } $k:literal = $val:expr, $($rest:tt)*) => {
+ $crate::fieldset!(@ { $($out),*, $k } $($rest)*)
+ };
+
+ // Remainder is unparseable, but exists --- must be format args!
+ (@ { $(,)* $($out:expr),* } $($rest:tt)+) => {
+ $crate::fieldset!(@ { "message", $($out),*, })
+ };
+
+ // == entry ==
+ ($($args:tt)*) => {
+ $crate::fieldset!(@ { } $($args)*,)
+ };
+
+}
+
+#[cfg(feature = "log")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! level_to_log {
+ ($level:expr) => {
+ match $level {
+ $crate::Level::ERROR => $crate::log::Level::Error,
+ $crate::Level::WARN => $crate::log::Level::Warn,
+ $crate::Level::INFO => $crate::log::Level::Info,
+ $crate::Level::DEBUG => $crate::log::Level::Debug,
+ _ => $crate::log::Level::Trace,
+ }
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __tracing_stringify {
+ ($s:expr) => {
+ stringify!($s)
+ };
+}
+
+#[cfg(not(feature = "log"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __tracing_log {
+ ($level:expr, $callsite:expr, $value_set:expr) => {};
+}
+
+#[cfg(feature = "log")]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! __tracing_log {
+ ($level:expr, $callsite:expr, $value_set:expr) => {
+ $crate::if_log_enabled! { $level, {
+ use $crate::log;
+ let level = $crate::level_to_log!($level);
+ if level <= log::max_level() {
+ let meta = $callsite.metadata();
+ let log_meta = log::Metadata::builder()
+ .level(level)
+ .target(meta.target())
+ .build();
+ let logger = log::logger();
+ if logger.enabled(&log_meta) {
+ $crate::__macro_support::__tracing_log(meta, logger, log_meta, $value_set)
+ }
+ }
+ }}
+ };
+}
+
+#[cfg(not(feature = "log"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! if_log_enabled {
+ ($lvl:expr, $e:expr;) => {
+ $crate::if_log_enabled! { $lvl, $e }
+ };
+ ($lvl:expr, $if_log:block) => {
+ $crate::if_log_enabled! { $lvl, $if_log else {} }
+ };
+ ($lvl:expr, $if_log:block else $else_block:block) => {
+ $else_block
+ };
+}
+
+#[cfg(all(feature = "log", not(feature = "log-always")))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! if_log_enabled {
+ ($lvl:expr, $e:expr;) => {
+ $crate::if_log_enabled! { $lvl, $e }
+ };
+ ($lvl:expr, $if_log:block) => {
+ $crate::if_log_enabled! { $lvl, $if_log else {} }
+ };
+ ($lvl:expr, $if_log:block else $else_block:block) => {
+ if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL {
+ if !$crate::dispatcher::has_been_set() {
+ $if_log
+ } else {
+ $else_block
+ }
+ } else {
+ $else_block
+ }
+ };
+}
+
+#[cfg(all(feature = "log", feature = "log-always"))]
+#[doc(hidden)]
+#[macro_export]
+macro_rules! if_log_enabled {
+ ($lvl:expr, $e:expr;) => {
+ $crate::if_log_enabled! { $lvl, $e }
+ };
+ ($lvl:expr, $if_log:block) => {
+ $crate::if_log_enabled! { $lvl, $if_log else {} }
+ };
+ ($lvl:expr, $if_log:block else $else_block:block) => {
+ if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL {
+ #[allow(unused_braces)]
+ $if_log
+ } else {
+ $else_block
+ }
+ };
+}
diff --git a/third_party/rust/tracing/src/span.rs b/third_party/rust/tracing/src/span.rs
new file mode 100644
index 0000000000..58822f4d9b
--- /dev/null
+++ b/third_party/rust/tracing/src/span.rs
@@ -0,0 +1,1623 @@
+//! Spans represent periods of time in which a program was executing in a
+//! particular context.
+//!
+//! A span consists of [fields], user-defined key-value pairs of arbitrary data
+//! that describe the context the span represents, and a set of fixed attributes
+//! that describe all `tracing` spans and events. Attributes describing spans
+//! include:
+//!
+//! - An [`Id`] assigned by the subscriber that uniquely identifies it in relation
+//! to other spans.
+//! - The span's [parent] in the trace tree.
+//! - [Metadata] that describes static characteristics of all spans
+//! originating from that callsite, such as its name, source code location,
+//! [verbosity level], and the names of its fields.
+//!
+//! # Creating Spans
+//!
+//! Spans are created using the [`span!`] macro. This macro is invoked with the
+//! following arguments, in order:
+//!
+//! - The [`target`] and/or [`parent`][parent] attributes, if the user wishes to
+//! override their default values.
+//! - The span's [verbosity level]
+//! - A string literal providing the span's name.
+//! - Finally, between zero and 32 arbitrary key/value fields.
+//!
+//! [`target`]: super::Metadata::target
+//!
+//! For example:
+//! ```rust
+//! use tracing::{span, Level};
+//!
+//! /// Construct a new span at the `INFO` level named "my_span", with a single
+//! /// field named answer , with the value `42`.
+//! let my_span = span!(Level::INFO, "my_span", answer = 42);
+//! ```
+//!
+//! The documentation for the [`span!`] macro provides additional examples of
+//! the various options that exist when creating spans.
+//!
+//! The [`trace_span!`], [`debug_span!`], [`info_span!`], [`warn_span!`], and
+//! [`error_span!`] exist as shorthand for constructing spans at various
+//! verbosity levels.
+//!
+//! ## Recording Span Creation
+//!
+//! The [`Attributes`] type contains data associated with a span, and is
+//! provided to the [`Subscriber`] when a new span is created. It contains
+//! the span's metadata, the ID of [the span's parent][parent] if one was
+//! explicitly set, and any fields whose values were recorded when the span was
+//! constructed. The subscriber, which is responsible for recording `tracing`
+//! data, can then store or record these values.
+//!
+//! # The Span Lifecycle
+//!
+//! ## Entering a Span
+//!
+//! A thread of execution is said to _enter_ a span when it begins executing,
+//! and _exit_ the span when it switches to another context. Spans may be
+//! entered through the [`enter`], [`entered`], and [`in_scope`] methods.
+//!
+//! The [`enter`] method enters a span, returning a [guard] that exits the span
+//! when dropped
+//! ```
+//! # use tracing::{span, Level};
+//! let my_var: u64 = 5;
+//! let my_span = span!(Level::TRACE, "my_span", my_var);
+//!
+//! // `my_span` exists but has not been entered.
+//!
+//! // Enter `my_span`...
+//! let _enter = my_span.enter();
+//!
+//! // Perform some work inside of the context of `my_span`...
+//! // Dropping the `_enter` guard will exit the span.
+//!```
+//!
+//! <div class="example-wrap" style="display:inline-block"><pre class="compile_fail" style="white-space:normal;font:inherit;">
+//! <strong>Warning</strong>: In asynchronous code that uses async/await syntax,
+//! <code>Span::enter</code> may produce incorrect traces if the returned drop
+//! guard is held across an await point. See
+//! <a href="struct.Span.html#in-asynchronous-code">the method documentation</a>
+//! for details.
+//! </pre></div>
+//!
+//! The [`entered`] method is analogous to [`enter`], but moves the span into
+//! the returned guard, rather than borrowing it. This allows creating and
+//! entering a span in a single expression:
+//!
+//! ```
+//! # use tracing::{span, Level};
+//! // Create a span and enter it, returning a guard:
+//! let span = span!(Level::INFO, "my_span").entered();
+//!
+//! // We are now inside the span! Like `enter()`, the guard returned by
+//! // `entered()` will exit the span when it is dropped...
+//!
+//! // ...but, it can also be exited explicitly, returning the `Span`
+//! // struct:
+//! let span = span.exit();
+//! ```
+//!
+//! Finally, [`in_scope`] takes a closure or function pointer and executes it
+//! inside the span:
+//!
+//! ```
+//! # use tracing::{span, Level};
+//! let my_var: u64 = 5;
+//! let my_span = span!(Level::TRACE, "my_span", my_var = &my_var);
+//!
+//! my_span.in_scope(|| {
+//! // perform some work in the context of `my_span`...
+//! });
+//!
+//! // Perform some work outside of the context of `my_span`...
+//!
+//! my_span.in_scope(|| {
+//! // Perform some more work in the context of `my_span`.
+//! });
+//! ```
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>: Since entering a span takes <code>&self</code>, and
+//! <code>Span</code>s are <code>Clone</code>, <code>Send</code>, and
+//! <code>Sync</code>, it is entirely valid for multiple threads to enter the
+//! same span concurrently.
+//! </pre>
+//!
+//! ## Span Relationships
+//!
+//! Spans form a tree structure — unless it is a root span, all spans have a
+//! _parent_, and may have one or more _children_. When a new span is created,
+//! the current span becomes the new span's parent. The total execution time of
+//! a span consists of the time spent in that span and in the entire subtree
+//! represented by its children. Thus, a parent span always lasts for at least
+//! as long as the longest-executing span in its subtree.
+//!
+//! ```
+//! # use tracing::{Level, span};
+//! // this span is considered the "root" of a new trace tree:
+//! span!(Level::INFO, "root").in_scope(|| {
+//! // since we are now inside "root", this span is considered a child
+//! // of "root":
+//! span!(Level::DEBUG, "outer_child").in_scope(|| {
+//! // this span is a child of "outer_child", which is in turn a
+//! // child of "root":
+//! span!(Level::TRACE, "inner_child").in_scope(|| {
+//! // and so on...
+//! });
+//! });
+//! // another span created here would also be a child of "root".
+//! });
+//!```
+//!
+//! In addition, the parent of a span may be explicitly specified in
+//! the `span!` macro. For example:
+//!
+//! ```rust
+//! # use tracing::{Level, span};
+//! // Create, but do not enter, a span called "foo".
+//! let foo = span!(Level::INFO, "foo");
+//!
+//! // Create and enter a span called "bar".
+//! let bar = span!(Level::INFO, "bar");
+//! let _enter = bar.enter();
+//!
+//! // Although we have currently entered "bar", "baz"'s parent span
+//! // will be "foo".
+//! let baz = span!(parent: &foo, Level::INFO, "baz");
+//! ```
+//!
+//! A child span should typically be considered _part_ of its parent. For
+//! example, if a subscriber is recording the length of time spent in various
+//! spans, it should generally include the time spent in a span's children as
+//! part of that span's duration.
+//!
+//! In addition to having zero or one parent, a span may also _follow from_ any
+//! number of other spans. This indicates a causal relationship between the span
+//! and the spans that it follows from, but a follower is *not* typically
+//! considered part of the duration of the span it follows. Unlike the parent, a
+//! span may record that it follows from another span after it is created, using
+//! the [`follows_from`] method.
+//!
+//! As an example, consider a listener task in a server. As the listener accepts
+//! incoming connections, it spawns new tasks that handle those connections. We
+//! might want to have a span representing the listener, and instrument each
+//! spawned handler task with its own span. We would want our instrumentation to
+//! record that the handler tasks were spawned as a result of the listener task.
+//! However, we might not consider the handler tasks to be _part_ of the time
+//! spent in the listener task, so we would not consider those spans children of
+//! the listener span. Instead, we would record that the handler tasks follow
+//! from the listener, recording the causal relationship but treating the spans
+//! as separate durations.
+//!
+//! ## Closing Spans
+//!
+//! Execution may enter and exit a span multiple times before that span is
+//! _closed_. Consider, for example, a future which has an associated
+//! span and enters that span every time it is polled:
+//! ```rust
+//! # use std::future::Future;
+//! # use std::task::{Context, Poll};
+//! # use std::pin::Pin;
+//! struct MyFuture {
+//! // data
+//! span: tracing::Span,
+//! }
+//!
+//! impl Future for MyFuture {
+//! type Output = ();
+//!
+//! fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
+//! let _enter = self.span.enter();
+//! // Do actual future work...
+//! # Poll::Ready(())
+//! }
+//! }
+//! ```
+//!
+//! If this future was spawned on an executor, it might yield one or more times
+//! before `poll` returns [`Poll::Ready`]. If the future were to yield, then
+//! the executor would move on to poll the next future, which may _also_ enter
+//! an associated span or series of spans. Therefore, it is valid for a span to
+//! be entered repeatedly before it completes. Only the time when that span or
+//! one of its children was the current span is considered to be time spent in
+//! that span. A span which is not executing and has not yet been closed is said
+//! to be _idle_.
+//!
+//! Because spans may be entered and exited multiple times before they close,
+//! [`Subscriber`]s have separate trait methods which are called to notify them
+//! of span exits and when span handles are dropped. When execution exits a
+//! span, [`exit`] will always be called with that span's ID to notify the
+//! subscriber that the span has been exited. When span handles are dropped, the
+//! [`drop_span`] method is called with that span's ID. The subscriber may use
+//! this to determine whether or not the span will be entered again.
+//!
+//! If there is only a single handle with the capacity to exit a span, dropping
+//! that handle "closes" the span, since the capacity to enter it no longer
+//! exists. For example:
+//! ```
+//! # use tracing::{Level, span};
+//! {
+//! span!(Level::TRACE, "my_span").in_scope(|| {
+//! // perform some work in the context of `my_span`...
+//! }); // --> Subscriber::exit(my_span)
+//!
+//! // The handle to `my_span` only lives inside of this block; when it is
+//! // dropped, the subscriber will be informed via `drop_span`.
+//!
+//! } // --> Subscriber::drop_span(my_span)
+//! ```
+//!
+//! However, if multiple handles exist, the span can still be re-entered even if
+//! one or more is dropped. For determining when _all_ handles to a span have
+//! been dropped, `Subscriber`s have a [`clone_span`] method, which is called
+//! every time a span handle is cloned. Combined with `drop_span`, this may be
+//! used to track the number of handles to a given span — if `drop_span` has
+//! been called one more time than the number of calls to `clone_span` for a
+//! given ID, then no more handles to the span with that ID exist. The
+//! subscriber may then treat it as closed.
+//!
+//! # When to use spans
+//!
+//! As a rule of thumb, spans should be used to represent discrete units of work
+//! (e.g., a given request's lifetime in a server) or periods of time spent in a
+//! given context (e.g., time spent interacting with an instance of an external
+//! system, such as a database).
+//!
+//! Which scopes in a program correspond to new spans depend somewhat on user
+//! intent. For example, consider the case of a loop in a program. Should we
+//! construct one span and perform the entire loop inside of that span, like:
+//!
+//! ```rust
+//! # use tracing::{Level, span};
+//! # let n = 1;
+//! let span = span!(Level::TRACE, "my_loop");
+//! let _enter = span.enter();
+//! for i in 0..n {
+//! # let _ = i;
+//! // ...
+//! }
+//! ```
+//! Or, should we create a new span for each iteration of the loop, as in:
+//! ```rust
+//! # use tracing::{Level, span};
+//! # let n = 1u64;
+//! for i in 0..n {
+//! let span = span!(Level::TRACE, "my_loop", iteration = i);
+//! let _enter = span.enter();
+//! // ...
+//! }
+//! ```
+//!
+//! Depending on the circumstances, we might want to do either, or both. For
+//! example, if we want to know how long was spent in the loop overall, we would
+//! create a single span around the entire loop; whereas if we wanted to know how
+//! much time was spent in each individual iteration, we would enter a new span
+//! on every iteration.
+//!
+//! [fields]: super::field
+//! [Metadata]: super::Metadata
+//! [verbosity level]: super::Level
+//! [`Poll::Ready`]: std::task::Poll::Ready
+//! [`span!`]: super::span!
+//! [`trace_span!`]: super::trace_span!
+//! [`debug_span!`]: super::debug_span!
+//! [`info_span!`]: super::info_span!
+//! [`warn_span!`]: super::warn_span!
+//! [`error_span!`]: super::error_span!
+//! [`clone_span`]: super::subscriber::Subscriber::clone_span()
+//! [`drop_span`]: super::subscriber::Subscriber::drop_span()
+//! [`exit`]: super::subscriber::Subscriber::exit
+//! [`Subscriber`]: super::subscriber::Subscriber
+//! [`enter`]: Span::enter()
+//! [`entered`]: Span::entered()
+//! [`in_scope`]: Span::in_scope()
+//! [`follows_from`]: Span::follows_from()
+//! [guard]: Entered
+//! [parent]: #span-relationships
+pub use tracing_core::span::{Attributes, Id, Record};
+
+use crate::stdlib::{
+ cmp, fmt,
+ hash::{Hash, Hasher},
+ marker::PhantomData,
+ mem,
+ ops::Deref,
+};
+use crate::{
+ dispatcher::{self, Dispatch},
+ field, Metadata,
+};
+
+/// Trait implemented by types which have a span `Id`.
+pub trait AsId: crate::sealed::Sealed {
+ /// Returns the `Id` of the span that `self` corresponds to, or `None` if
+ /// this corresponds to a disabled span.
+ fn as_id(&self) -> Option<&Id>;
+}
+
+/// A handle representing a span, with the capability to enter the span if it
+/// exists.
+///
+/// If the span was rejected by the current `Subscriber`'s filter, entering the
+/// span will silently do nothing. Thus, the handle can be used in the same
+/// manner regardless of whether or not the trace is currently being collected.
+#[derive(Clone)]
+pub struct Span {
+ /// A handle used to enter the span when it is not executing.
+ ///
+ /// If this is `None`, then the span has either closed or was never enabled.
+ inner: Option<Inner>,
+ /// Metadata describing the span.
+ ///
+ /// This might be `Some` even if `inner` is `None`, in the case that the
+ /// span is disabled but the metadata is needed for `log` support.
+ meta: Option<&'static Metadata<'static>>,
+}
+
+/// A handle representing the capacity to enter a span which is known to exist.
+///
+/// Unlike `Span`, this type is only constructed for spans which _have_ been
+/// enabled by the current filter. This type is primarily used for implementing
+/// span handles; users should typically not need to interact with it directly.
+#[derive(Debug)]
+pub(crate) struct Inner {
+ /// The span's ID, as provided by `subscriber`.
+ id: Id,
+
+ /// The subscriber that will receive events relating to this span.
+ ///
+ /// This should be the same subscriber that provided this span with its
+ /// `id`.
+ subscriber: Dispatch,
+}
+
+/// A guard representing a span which has been entered and is currently
+/// executing.
+///
+/// When the guard is dropped, the span will be exited.
+///
+/// This is returned by the [`Span::enter`] function.
+///
+/// [`Span::enter`]: super::Span::enter
+#[derive(Debug)]
+#[must_use = "once a span has been entered, it should be exited"]
+pub struct Entered<'a> {
+ span: &'a Span,
+}
+
+/// An owned version of [`Entered`], a guard representing a span which has been
+/// entered and is currently executing.
+///
+/// When the guard is dropped, the span will be exited.
+///
+/// This is returned by the [`Span::entered`] function.
+///
+/// [`Span::entered`]: super::Span::entered()
+#[derive(Debug)]
+#[must_use = "once a span has been entered, it should be exited"]
+pub struct EnteredSpan {
+ span: Span,
+
+ /// ```compile_fail
+ /// use tracing::span::*;
+ /// trait AssertSend: Send {}
+ ///
+ /// impl AssertSend for EnteredSpan {}
+ /// ```
+ _not_send: PhantomNotSend,
+}
+
+/// `log` target for all span lifecycle (creation/enter/exit/close) records.
+#[cfg(feature = "log")]
+const LIFECYCLE_LOG_TARGET: &str = "tracing::span";
+/// `log` target for span activity (enter/exit) records.
+#[cfg(feature = "log")]
+const ACTIVITY_LOG_TARGET: &str = "tracing::span::active";
+
+// ===== impl Span =====
+
+impl Span {
+ /// Constructs a new `Span` with the given [metadata] and set of
+ /// [field values].
+ ///
+ /// The new span will be constructed by the currently-active [`Subscriber`],
+ /// with the current span as its parent (if one exists).
+ ///
+ /// After the span is constructed, [field values] and/or [`follows_from`]
+ /// annotations may be added to it.
+ ///
+ /// [metadata]: super::Metadata
+ /// [`Subscriber`]: super::subscriber::Subscriber
+ /// [field values]: super::field::ValueSet
+ /// [`follows_from`]: super::Span::follows_from
+ pub fn new(meta: &'static Metadata<'static>, values: &field::ValueSet<'_>) -> Span {
+ dispatcher::get_default(|dispatch| Self::new_with(meta, values, dispatch))
+ }
+
+ #[inline]
+ #[doc(hidden)]
+ pub fn new_with(
+ meta: &'static Metadata<'static>,
+ values: &field::ValueSet<'_>,
+ dispatch: &Dispatch,
+ ) -> Span {
+ let new_span = Attributes::new(meta, values);
+ Self::make_with(meta, new_span, dispatch)
+ }
+
+ /// Constructs a new `Span` as the root of its own trace tree, with the
+ /// given [metadata] and set of [field values].
+ ///
+ /// After the span is constructed, [field values] and/or [`follows_from`]
+ /// annotations may be added to it.
+ ///
+ /// [metadata]: super::Metadata
+ /// [field values]: super::field::ValueSet
+ /// [`follows_from`]: super::Span::follows_from
+ pub fn new_root(meta: &'static Metadata<'static>, values: &field::ValueSet<'_>) -> Span {
+ dispatcher::get_default(|dispatch| Self::new_root_with(meta, values, dispatch))
+ }
+
+ #[inline]
+ #[doc(hidden)]
+ pub fn new_root_with(
+ meta: &'static Metadata<'static>,
+ values: &field::ValueSet<'_>,
+ dispatch: &Dispatch,
+ ) -> Span {
+ let new_span = Attributes::new_root(meta, values);
+ Self::make_with(meta, new_span, dispatch)
+ }
+
+ /// Constructs a new `Span` as child of the given parent span, with the
+ /// given [metadata] and set of [field values].
+ ///
+ /// After the span is constructed, [field values] and/or [`follows_from`]
+ /// annotations may be added to it.
+ ///
+ /// [metadata]: super::Metadata
+ /// [field values]: super::field::ValueSet
+ /// [`follows_from`]: super::Span::follows_from
+ pub fn child_of(
+ parent: impl Into<Option<Id>>,
+ meta: &'static Metadata<'static>,
+ values: &field::ValueSet<'_>,
+ ) -> Span {
+ let mut parent = parent.into();
+ dispatcher::get_default(move |dispatch| {
+ Self::child_of_with(Option::take(&mut parent), meta, values, dispatch)
+ })
+ }
+
+ #[inline]
+ #[doc(hidden)]
+ pub fn child_of_with(
+ parent: impl Into<Option<Id>>,
+ meta: &'static Metadata<'static>,
+ values: &field::ValueSet<'_>,
+ dispatch: &Dispatch,
+ ) -> Span {
+ let new_span = match parent.into() {
+ Some(parent) => Attributes::child_of(parent, meta, values),
+ None => Attributes::new_root(meta, values),
+ };
+ Self::make_with(meta, new_span, dispatch)
+ }
+
+ /// Constructs a new disabled span with the given `Metadata`.
+ ///
+ /// This should be used when a span is constructed from a known callsite,
+ /// but the subscriber indicates that it is disabled.
+ ///
+ /// Entering, exiting, and recording values on this span will not notify the
+ /// `Subscriber` but _may_ record log messages if the `log` feature flag is
+ /// enabled.
+ #[inline(always)]
+ pub fn new_disabled(meta: &'static Metadata<'static>) -> Span {
+ Self {
+ inner: None,
+ meta: Some(meta),
+ }
+ }
+
+ /// Constructs a new span that is *completely disabled*.
+ ///
+ /// This can be used rather than `Option<Span>` to represent cases where a
+ /// span is not present.
+ ///
+ /// Entering, exiting, and recording values on this span will do nothing.
+ #[inline(always)]
+ pub const fn none() -> Span {
+ Self {
+ inner: None,
+ meta: None,
+ }
+ }
+
+ /// Returns a handle to the span [considered by the `Subscriber`] to be the
+ /// current span.
+ ///
+ /// If the subscriber indicates that it does not track the current span, or
+ /// that the thread from which this function is called is not currently
+ /// inside a span, the returned span will be disabled.
+ ///
+ /// [considered by the `Subscriber`]:
+ /// super::subscriber::Subscriber::current_span
+ pub fn current() -> Span {
+ dispatcher::get_default(|dispatch| {
+ if let Some((id, meta)) = dispatch.current_span().into_inner() {
+ let id = dispatch.clone_span(&id);
+ Self {
+ inner: Some(Inner::new(id, dispatch)),
+ meta: Some(meta),
+ }
+ } else {
+ Self::none()
+ }
+ })
+ }
+
+ fn make_with(
+ meta: &'static Metadata<'static>,
+ new_span: Attributes<'_>,
+ dispatch: &Dispatch,
+ ) -> Span {
+ let attrs = &new_span;
+ let id = dispatch.new_span(attrs);
+ let inner = Some(Inner::new(id, dispatch));
+
+ let span = Self {
+ inner,
+ meta: Some(meta),
+ };
+
+ if_log_enabled! { *meta.level(), {
+ let target = if attrs.is_empty() {
+ LIFECYCLE_LOG_TARGET
+ } else {
+ meta.target()
+ };
+ let values = attrs.values();
+ span.log(
+ target,
+ level_to_log!(*meta.level()),
+ format_args!("++ {};{}", meta.name(), crate::log::LogValueSet { values, is_first: false }),
+ );
+ }}
+
+ span
+ }
+
+ /// Enters this span, returning a guard that will exit the span when dropped.
+ ///
+ /// If this span is enabled by the current subscriber, then this function will
+ /// call [`Subscriber::enter`] with the span's [`Id`], and dropping the guard
+ /// will call [`Subscriber::exit`]. If the span is disabled, this does
+ /// nothing.
+ ///
+ /// # In Asynchronous Code
+ ///
+ /// **Warning**: in asynchronous code that uses [async/await syntax][syntax],
+ /// `Span::enter` should be used very carefully or avoided entirely. Holding
+ /// the drop guard returned by `Span::enter` across `.await` points will
+ /// result in incorrect traces. For example,
+ ///
+ /// ```
+ /// # use tracing::info_span;
+ /// # async fn some_other_async_function() {}
+ /// async fn my_async_function() {
+ /// let span = info_span!("my_async_function");
+ ///
+ /// // WARNING: This span will remain entered until this
+ /// // guard is dropped...
+ /// let _enter = span.enter();
+ /// // ...but the `await` keyword may yield, causing the
+ /// // runtime to switch to another task, while remaining in
+ /// // this span!
+ /// some_other_async_function().await
+ ///
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// The drop guard returned by `Span::enter` exits the span when it is
+ /// dropped. When an async function or async block yields at an `.await`
+ /// point, the current scope is _exited_, but values in that scope are
+ /// **not** dropped (because the async block will eventually resume
+ /// execution from that await point). This means that _another_ task will
+ /// begin executing while _remaining_ in the entered span. This results in
+ /// an incorrect trace.
+ ///
+ /// Instead of using `Span::enter` in asynchronous code, prefer the
+ /// following:
+ ///
+ /// * To enter a span for a synchronous section of code within an async
+ /// block or function, prefer [`Span::in_scope`]. Since `in_scope` takes a
+ /// synchronous closure and exits the span when the closure returns, the
+ /// span will always be exited before the next await point. For example:
+ /// ```
+ /// # use tracing::info_span;
+ /// # async fn some_other_async_function(_: ()) {}
+ /// async fn my_async_function() {
+ /// let span = info_span!("my_async_function");
+ ///
+ /// let some_value = span.in_scope(|| {
+ /// // run some synchronous code inside the span...
+ /// });
+ ///
+ /// // This is okay! The span has already been exited before we reach
+ /// // the await point.
+ /// some_other_async_function(some_value).await;
+ ///
+ /// // ...
+ /// }
+ /// ```
+ /// * For instrumenting asynchronous code, `tracing` provides the
+ /// [`Future::instrument` combinator][instrument] for
+ /// attaching a span to a future (async function or block). This will
+ /// enter the span _every_ time the future is polled, and exit it whenever
+ /// the future yields.
+ ///
+ /// `Instrument` can be used with an async block inside an async function:
+ /// ```ignore
+ /// # use tracing::info_span;
+ /// use tracing::Instrument;
+ ///
+ /// # async fn some_other_async_function() {}
+ /// async fn my_async_function() {
+ /// let span = info_span!("my_async_function");
+ /// async move {
+ /// // This is correct! If we yield here, the span will be exited,
+ /// // and re-entered when we resume.
+ /// some_other_async_function().await;
+ ///
+ /// //more asynchronous code inside the span...
+ ///
+ /// }
+ /// // instrument the async block with the span...
+ /// .instrument(span)
+ /// // ...and await it.
+ /// .await
+ /// }
+ /// ```
+ ///
+ /// It can also be used to instrument calls to async functions at the
+ /// callsite:
+ /// ```ignore
+ /// # use tracing::debug_span;
+ /// use tracing::Instrument;
+ ///
+ /// # async fn some_other_async_function() {}
+ /// async fn my_async_function() {
+ /// let some_value = some_other_async_function()
+ /// .instrument(debug_span!("some_other_async_function"))
+ /// .await;
+ ///
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// * The [`#[instrument]` attribute macro][attr] can automatically generate
+ /// correct code when used on an async function:
+ ///
+ /// ```ignore
+ /// # async fn some_other_async_function() {}
+ /// #[tracing::instrument(level = "info")]
+ /// async fn my_async_function() {
+ ///
+ /// // This is correct! If we yield here, the span will be exited,
+ /// // and re-entered when we resume.
+ /// some_other_async_function().await;
+ ///
+ /// // ...
+ ///
+ /// }
+ /// ```
+ ///
+ /// [syntax]: https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html
+ /// [`Span::in_scope`]: Span::in_scope()
+ /// [instrument]: crate::Instrument
+ /// [attr]: macro@crate::instrument
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use tracing::{span, Level};
+ /// let span = span!(Level::INFO, "my_span");
+ /// let guard = span.enter();
+ ///
+ /// // code here is within the span
+ ///
+ /// drop(guard);
+ ///
+ /// // code here is no longer within the span
+ ///
+ /// ```
+ ///
+ /// Guards need not be explicitly dropped:
+ ///
+ /// ```
+ /// # use tracing::trace_span;
+ /// fn my_function() -> String {
+ /// // enter a span for the duration of this function.
+ /// let span = trace_span!("my_function");
+ /// let _enter = span.enter();
+ ///
+ /// // anything happening in functions we call is still inside the span...
+ /// my_other_function();
+ ///
+ /// // returning from the function drops the guard, exiting the span.
+ /// return "Hello world".to_owned();
+ /// }
+ ///
+ /// fn my_other_function() {
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// Sub-scopes may be created to limit the duration for which the span is
+ /// entered:
+ ///
+ /// ```
+ /// # use tracing::{info, info_span};
+ /// let span = info_span!("my_great_span");
+ ///
+ /// {
+ /// let _enter = span.enter();
+ ///
+ /// // this event occurs inside the span.
+ /// info!("i'm in the span!");
+ ///
+ /// // exiting the scope drops the guard, exiting the span.
+ /// }
+ ///
+ /// // this event is not inside the span.
+ /// info!("i'm outside the span!")
+ /// ```
+ ///
+ /// [`Subscriber::enter`]: super::subscriber::Subscriber::enter()
+ /// [`Subscriber::exit`]: super::subscriber::Subscriber::exit()
+ /// [`Id`]: super::Id
+ #[inline(always)]
+ pub fn enter(&self) -> Entered<'_> {
+ self.do_enter();
+ Entered { span: self }
+ }
+
+ /// Enters this span, consuming it and returning a [guard][`EnteredSpan`]
+ /// that will exit the span when dropped.
+ ///
+ /// <pre class="compile_fail" style="white-space:normal;font:inherit;">
+ /// <strong>Warning</strong>: In asynchronous code that uses async/await syntax,
+ /// <code>Span::entered</code> may produce incorrect traces if the returned drop
+ /// guard is held across an await point. See <a href="#in-asynchronous-code">the
+ /// <code>Span::enter</code> documentation</a> for details.
+ /// </pre>
+ ///
+ ///
+ /// If this span is enabled by the current subscriber, then this function will
+ /// call [`Subscriber::enter`] with the span's [`Id`], and dropping the guard
+ /// will call [`Subscriber::exit`]. If the span is disabled, this does
+ /// nothing.
+ ///
+ /// This is similar to the [`Span::enter`] method, except that it moves the
+ /// span by value into the returned guard, rather than borrowing it.
+ /// Therefore, this method can be used to create and enter a span in a
+ /// single expression, without requiring a `let`-binding. For example:
+ ///
+ /// ```
+ /// # use tracing::info_span;
+ /// let _span = info_span!("something_interesting").entered();
+ /// ```
+ /// rather than:
+ /// ```
+ /// # use tracing::info_span;
+ /// let span = info_span!("something_interesting");
+ /// let _e = span.enter();
+ /// ```
+ ///
+ /// Furthermore, `entered` may be used when the span must be stored in some
+ /// other struct or be passed to a function while remaining entered.
+ ///
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ /// <strong>Note</strong>: The returned <a href="../struct.EnteredSpan.html">
+ /// <code>EnteredSpan</a></code> guard does not implement <code>Send</code>.
+ /// Dropping the guard will exit <em>this</em> span, and if the guard is sent
+ /// to another thread and dropped there, that thread may never have entered
+ /// this span. Thus, <code>EnteredSpan</code>s should not be sent between threads.
+ /// </pre>
+ ///
+ /// [syntax]: https://rust-lang.github.io/async-book/01_getting_started/04_async_await_primer.html
+ ///
+ /// # Examples
+ ///
+ /// The returned guard can be [explicitly exited][EnteredSpan::exit],
+ /// returning the un-entered span:
+ ///
+ /// ```
+ /// # use tracing::{Level, span};
+ /// let span = span!(Level::INFO, "doing_something").entered();
+ ///
+ /// // code here is within the span
+ ///
+ /// // explicitly exit the span, returning it
+ /// let span = span.exit();
+ ///
+ /// // code here is no longer within the span
+ ///
+ /// // enter the span again
+ /// let span = span.entered();
+ ///
+ /// // now we are inside the span once again
+ /// ```
+ ///
+ /// Guards need not be explicitly dropped:
+ ///
+ /// ```
+ /// # use tracing::trace_span;
+ /// fn my_function() -> String {
+ /// // enter a span for the duration of this function.
+ /// let span = trace_span!("my_function").entered();
+ ///
+ /// // anything happening in functions we call is still inside the span...
+ /// my_other_function();
+ ///
+ /// // returning from the function drops the guard, exiting the span.
+ /// return "Hello world".to_owned();
+ /// }
+ ///
+ /// fn my_other_function() {
+ /// // ...
+ /// }
+ /// ```
+ ///
+ /// Since the [`EnteredSpan`] guard can dereference to the [`Span`] itself,
+ /// the span may still be accessed while entered. For example:
+ ///
+ /// ```rust
+ /// # use tracing::info_span;
+ /// use tracing::field;
+ ///
+ /// // create the span with an empty field, and enter it.
+ /// let span = info_span!("my_span", some_field = field::Empty).entered();
+ ///
+ /// // we can still record a value for the field while the span is entered.
+ /// span.record("some_field", &"hello world!");
+ /// ```
+ ///
+
+ /// [`Subscriber::enter`]: super::subscriber::Subscriber::enter()
+ /// [`Subscriber::exit`]: super::subscriber::Subscriber::exit()
+ /// [`Id`]: super::Id
+ #[inline(always)]
+ pub fn entered(self) -> EnteredSpan {
+ self.do_enter();
+ EnteredSpan {
+ span: self,
+ _not_send: PhantomNotSend,
+ }
+ }
+
+ /// Returns this span, if it was [enabled] by the current [`Subscriber`], or
+ /// the [current span] (whose lexical distance may be further than expected),
+ /// if this span [is disabled].
+ ///
+ /// This method can be useful when propagating spans to spawned threads or
+ /// [async tasks]. Consider the following:
+ ///
+ /// ```
+ /// let _parent_span = tracing::info_span!("parent").entered();
+ ///
+ /// // ...
+ ///
+ /// let child_span = tracing::debug_span!("child");
+ ///
+ /// std::thread::spawn(move || {
+ /// let _entered = child_span.entered();
+ ///
+ /// tracing::info!("spawned a thread!");
+ ///
+ /// // ...
+ /// });
+ /// ```
+ ///
+ /// If the current [`Subscriber`] enables the [`DEBUG`] level, then both
+ /// the "parent" and "child" spans will be enabled. Thus, when the "spawaned
+ /// a thread!" event occurs, it will be inside of the "child" span. Because
+ /// "parent" is the parent of "child", the event will _also_ be inside of
+ /// "parent".
+ ///
+ /// However, if the [`Subscriber`] only enables the [`INFO`] level, the "child"
+ /// span will be disabled. When the thread is spawned, the
+ /// `child_span.entered()` call will do nothing, since "child" is not
+ /// enabled. In this case, the "spawned a thread!" event occurs outside of
+ /// *any* span, since the "child" span was responsible for propagating its
+ /// parent to the spawned thread.
+ ///
+ /// If this is not the desired behavior, `Span::or_current` can be used to
+ /// ensure that the "parent" span is propagated in both cases, either as a
+ /// parent of "child" _or_ directly. For example:
+ ///
+ /// ```
+ /// let _parent_span = tracing::info_span!("parent").entered();
+ ///
+ /// // ...
+ ///
+ /// // If DEBUG is enabled, then "child" will be enabled, and `or_current`
+ /// // returns "child". Otherwise, if DEBUG is not enabled, "child" will be
+ /// // disabled, and `or_current` returns "parent".
+ /// let child_span = tracing::debug_span!("child").or_current();
+ ///
+ /// std::thread::spawn(move || {
+ /// let _entered = child_span.entered();
+ ///
+ /// tracing::info!("spawned a thread!");
+ ///
+ /// // ...
+ /// });
+ /// ```
+ ///
+ /// When spawning [asynchronous tasks][async tasks], `Span::or_current` can
+ /// be used similarly, in combination with [`instrument`]:
+ ///
+ /// ```
+ /// use tracing::Instrument;
+ /// # // lol
+ /// # mod tokio {
+ /// # pub(super) fn spawn(_: impl std::future::Future) {}
+ /// # }
+ ///
+ /// let _parent_span = tracing::info_span!("parent").entered();
+ ///
+ /// // ...
+ ///
+ /// let child_span = tracing::debug_span!("child");
+ ///
+ /// tokio::spawn(
+ /// async {
+ /// tracing::info!("spawned a task!");
+ ///
+ /// // ...
+ ///
+ /// }.instrument(child_span.or_current())
+ /// );
+ /// ```
+ ///
+ /// In general, `or_current` should be preferred over nesting an
+ /// [`instrument`] call inside of an [`in_current_span`] call, as using
+ /// `or_current` will be more efficient.
+ ///
+ /// ```
+ /// use tracing::Instrument;
+ /// # // lol
+ /// # mod tokio {
+ /// # pub(super) fn spawn(_: impl std::future::Future) {}
+ /// # }
+ /// async fn my_async_fn() {
+ /// // ...
+ /// }
+ ///
+ /// let _parent_span = tracing::info_span!("parent").entered();
+ ///
+ /// // Do this:
+ /// tokio::spawn(
+ /// my_async_fn().instrument(tracing::debug_span!("child").or_current())
+ /// );
+ ///
+ /// // ...rather than this:
+ /// tokio::spawn(
+ /// my_async_fn()
+ /// .instrument(tracing::debug_span!("child"))
+ /// .in_current_span()
+ /// );
+ /// ```
+ ///
+ /// [enabled]: crate::Subscriber::enabled
+ /// [`Subscriber`]: crate::Subscriber
+ /// [current span]: Span::current
+ /// [is disabled]: Span::is_disabled
+ /// [`INFO`]: crate::Level::INFO
+ /// [`DEBUG`]: crate::Level::DEBUG
+ /// [async tasks]: std::task
+ /// [`instrument`]: crate::instrument::Instrument::instrument
+ /// [`in_current_span`]: crate::instrument::Instrument::in_current_span
+ pub fn or_current(self) -> Self {
+ if self.is_disabled() {
+ return Self::current();
+ }
+ self
+ }
+
+ #[inline(always)]
+ fn do_enter(&self) {
+ if let Some(inner) = self.inner.as_ref() {
+ inner.subscriber.enter(&inner.id);
+ }
+
+ if_log_enabled! { crate::Level::TRACE, {
+ if let Some(_meta) = self.meta {
+ self.log(ACTIVITY_LOG_TARGET, log::Level::Trace, format_args!("-> {};", _meta.name()));
+ }
+ }}
+ }
+
+ // Called from [`Entered`] and [`EnteredSpan`] drops.
+ //
+ // Running this behaviour on drop rather than with an explicit function
+ // call means that spans may still be exited when unwinding.
+ #[inline(always)]
+ fn do_exit(&self) {
+ if let Some(inner) = self.inner.as_ref() {
+ inner.subscriber.exit(&inner.id);
+ }
+
+ if_log_enabled! { crate::Level::TRACE, {
+ if let Some(_meta) = self.meta {
+ self.log(ACTIVITY_LOG_TARGET, log::Level::Trace, format_args!("<- {};", _meta.name()));
+ }
+ }}
+ }
+
+ /// Executes the given function in the context of this span.
+ ///
+ /// If this span is enabled, then this function enters the span, invokes `f`
+ /// and then exits the span. If the span is disabled, `f` will still be
+ /// invoked, but in the context of the currently-executing span (if there is
+ /// one).
+ ///
+ /// Returns the result of evaluating `f`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// # use tracing::{trace, span, Level};
+ /// let my_span = span!(Level::TRACE, "my_span");
+ ///
+ /// my_span.in_scope(|| {
+ /// // this event occurs within the span.
+ /// trace!("i'm in the span!");
+ /// });
+ ///
+ /// // this event occurs outside the span.
+ /// trace!("i'm not in the span!");
+ /// ```
+ ///
+ /// Calling a function and returning the result:
+ /// ```
+ /// # use tracing::{info_span, Level};
+ /// fn hello_world() -> String {
+ /// "Hello world!".to_owned()
+ /// }
+ ///
+ /// let span = info_span!("hello_world");
+ /// // the span will be entered for the duration of the call to
+ /// // `hello_world`.
+ /// let a_string = span.in_scope(hello_world);
+ ///
+ pub fn in_scope<F: FnOnce() -> T, T>(&self, f: F) -> T {
+ let _enter = self.enter();
+ f()
+ }
+
+ /// Returns a [`Field`][super::field::Field] for the field with the
+ /// given `name`, if one exists,
+ pub fn field<Q: ?Sized>(&self, field: &Q) -> Option<field::Field>
+ where
+ Q: field::AsField,
+ {
+ self.metadata().and_then(|meta| field.as_field(meta))
+ }
+
+ /// Returns true if this `Span` has a field for the given
+ /// [`Field`][super::field::Field] or field name.
+ #[inline]
+ pub fn has_field<Q: ?Sized>(&self, field: &Q) -> bool
+ where
+ Q: field::AsField,
+ {
+ self.field(field).is_some()
+ }
+
+ /// Records that the field described by `field` has the value `value`.
+ ///
+ /// This may be used with [`field::Empty`] to declare fields whose values
+ /// are not known when the span is created, and record them later:
+ /// ```
+ /// use tracing::{trace_span, field};
+ ///
+ /// // Create a span with two fields: `greeting`, with the value "hello world", and
+ /// // `parting`, without a value.
+ /// let span = trace_span!("my_span", greeting = "hello world", parting = field::Empty);
+ ///
+ /// // ...
+ ///
+ /// // Now, record a value for parting as well.
+ /// // (note that the field name is passed as a string slice)
+ /// span.record("parting", "goodbye world!");
+ /// ```
+ /// However, it may also be used to record a _new_ value for a field whose
+ /// value was already recorded:
+ /// ```
+ /// use tracing::info_span;
+ /// # fn do_something() -> Result<(), ()> { Err(()) }
+ ///
+ /// // Initially, let's assume that our attempt to do something is going okay...
+ /// let span = info_span!("doing_something", is_okay = true);
+ /// let _e = span.enter();
+ ///
+ /// match do_something() {
+ /// Ok(something) => {
+ /// // ...
+ /// }
+ /// Err(_) => {
+ /// // Things are no longer okay!
+ /// span.record("is_okay", false);
+ /// }
+ /// }
+ /// ```
+ ///
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ /// <strong>Note</strong>: The fields associated with a span are part
+ /// of its <a href="../struct.Metadata.html"><code>Metadata</code></a>.
+ /// The <a href="../struct.Metadata.html"><code>Metadata</code></a>
+ /// describing a particular span is constructed statically when the span
+ /// is created and cannot be extended later to add new fields. Therefore,
+ /// you cannot record a value for a field that was not specified when the
+ /// span was created:
+ /// </pre>
+ ///
+ /// ```
+ /// use tracing::{trace_span, field};
+ ///
+ /// // Create a span with two fields: `greeting`, with the value "hello world", and
+ /// // `parting`, without a value.
+ /// let span = trace_span!("my_span", greeting = "hello world", parting = field::Empty);
+ ///
+ /// // ...
+ ///
+ /// // Now, you try to record a value for a new field, `new_field`, which was not
+ /// // declared as `Empty` or populated when you created `span`.
+ /// // You won't get any error, but the assignment will have no effect!
+ /// span.record("new_field", "interesting_value_you_really_need");
+ ///
+ /// // Instead, all fields that may be recorded after span creation should be declared up front,
+ /// // using field::Empty when a value is not known, as we did for `parting`.
+ /// // This `record` call will indeed replace field::Empty with "you will be remembered".
+ /// span.record("parting", "you will be remembered");
+ /// ```
+ ///
+ /// [`field::Empty`]: super::field::Empty
+ /// [`Metadata`]: super::Metadata
+ pub fn record<Q: ?Sized, V>(&self, field: &Q, value: V) -> &Self
+ where
+ Q: field::AsField,
+ V: field::Value,
+ {
+ if let Some(meta) = self.meta {
+ if let Some(field) = field.as_field(meta) {
+ self.record_all(
+ &meta
+ .fields()
+ .value_set(&[(&field, Some(&value as &dyn field::Value))]),
+ );
+ }
+ }
+
+ self
+ }
+
+ /// Records all the fields in the provided `ValueSet`.
+ pub fn record_all(&self, values: &field::ValueSet<'_>) -> &Self {
+ let record = Record::new(values);
+ if let Some(ref inner) = self.inner {
+ inner.record(&record);
+ }
+
+ if let Some(_meta) = self.meta {
+ if_log_enabled! { *_meta.level(), {
+ let target = if record.is_empty() {
+ LIFECYCLE_LOG_TARGET
+ } else {
+ _meta.target()
+ };
+ self.log(
+ target,
+ level_to_log!(*_meta.level()),
+ format_args!("{};{}", _meta.name(), crate::log::LogValueSet { values, is_first: false }),
+ );
+ }}
+ }
+
+ self
+ }
+
+ /// Returns `true` if this span was disabled by the subscriber and does not
+ /// exist.
+ ///
+ /// See also [`is_none`].
+ ///
+ /// [`is_none`]: Span::is_none()
+ #[inline]
+ pub fn is_disabled(&self) -> bool {
+ self.inner.is_none()
+ }
+
+ /// Returns `true` if this span was constructed by [`Span::none`] and is
+ /// empty.
+ ///
+ /// If `is_none` returns `true` for a given span, then [`is_disabled`] will
+ /// also return `true`. However, when a span is disabled by the subscriber
+ /// rather than constructed by `Span::none`, this method will return
+ /// `false`, while `is_disabled` will return `true`.
+ ///
+ /// [`Span::none`]: Span::none()
+ /// [`is_disabled`]: Span::is_disabled()
+ #[inline]
+ pub fn is_none(&self) -> bool {
+ self.is_disabled() && self.meta.is_none()
+ }
+
+ /// Indicates that the span with the given ID has an indirect causal
+ /// relationship with this span.
+ ///
+ /// This relationship differs somewhat from the parent-child relationship: a
+ /// span may have any number of prior spans, rather than a single one; and
+ /// spans are not considered to be executing _inside_ of the spans they
+ /// follow from. This means that a span may close even if subsequent spans
+ /// that follow from it are still open, and time spent inside of a
+ /// subsequent span should not be included in the time its precedents were
+ /// executing. This is used to model causal relationships such as when a
+ /// single future spawns several related background tasks, et cetera.
+ ///
+ /// If this span is disabled, or the resulting follows-from relationship
+ /// would be invalid, this function will do nothing.
+ ///
+ /// # Examples
+ ///
+ /// Setting a `follows_from` relationship with a `Span`:
+ /// ```
+ /// # use tracing::{span, Id, Level, Span};
+ /// let span1 = span!(Level::INFO, "span_1");
+ /// let span2 = span!(Level::DEBUG, "span_2");
+ /// span2.follows_from(span1);
+ /// ```
+ ///
+ /// Setting a `follows_from` relationship with the current span:
+ /// ```
+ /// # use tracing::{span, Id, Level, Span};
+ /// let span = span!(Level::INFO, "hello!");
+ /// span.follows_from(Span::current());
+ /// ```
+ ///
+ /// Setting a `follows_from` relationship with a `Span` reference:
+ /// ```
+ /// # use tracing::{span, Id, Level, Span};
+ /// let span = span!(Level::INFO, "hello!");
+ /// let curr = Span::current();
+ /// span.follows_from(&curr);
+ /// ```
+ ///
+ /// Setting a `follows_from` relationship with an `Id`:
+ /// ```
+ /// # use tracing::{span, Id, Level, Span};
+ /// let span = span!(Level::INFO, "hello!");
+ /// let id = span.id();
+ /// span.follows_from(id);
+ /// ```
+ pub fn follows_from(&self, from: impl Into<Option<Id>>) -> &Self {
+ if let Some(ref inner) = self.inner {
+ if let Some(from) = from.into() {
+ inner.follows_from(&from);
+ }
+ }
+ self
+ }
+
+ /// Returns this span's `Id`, if it is enabled.
+ pub fn id(&self) -> Option<Id> {
+ self.inner.as_ref().map(Inner::id)
+ }
+
+ /// Returns this span's `Metadata`, if it is enabled.
+ pub fn metadata(&self) -> Option<&'static Metadata<'static>> {
+ self.meta
+ }
+
+ #[cfg(feature = "log")]
+ #[inline]
+ fn log(&self, target: &str, level: log::Level, message: fmt::Arguments<'_>) {
+ if let Some(meta) = self.meta {
+ if level_to_log!(*meta.level()) <= log::max_level() {
+ let logger = log::logger();
+ let log_meta = log::Metadata::builder().level(level).target(target).build();
+ if logger.enabled(&log_meta) {
+ if let Some(ref inner) = self.inner {
+ logger.log(
+ &log::Record::builder()
+ .metadata(log_meta)
+ .module_path(meta.module_path())
+ .file(meta.file())
+ .line(meta.line())
+ .args(format_args!("{} span={}", message, inner.id.into_u64()))
+ .build(),
+ );
+ } else {
+ logger.log(
+ &log::Record::builder()
+ .metadata(log_meta)
+ .module_path(meta.module_path())
+ .file(meta.file())
+ .line(meta.line())
+ .args(message)
+ .build(),
+ );
+ }
+ }
+ }
+ }
+ }
+
+ /// Invokes a function with a reference to this span's ID and subscriber.
+ ///
+ /// if this span is enabled, the provided function is called, and the result is returned.
+ /// If the span is disabled, the function is not called, and this method returns `None`
+ /// instead.
+ pub fn with_subscriber<T>(&self, f: impl FnOnce((&Id, &Dispatch)) -> T) -> Option<T> {
+ self.inner
+ .as_ref()
+ .map(|inner| f((&inner.id, &inner.subscriber)))
+ }
+}
+
+impl cmp::PartialEq for Span {
+ fn eq(&self, other: &Self) -> bool {
+ match (&self.meta, &other.meta) {
+ (Some(this), Some(that)) => {
+ this.callsite() == that.callsite() && self.inner == other.inner
+ }
+ _ => false,
+ }
+ }
+}
+
+impl Hash for Span {
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ self.inner.hash(hasher);
+ }
+}
+
+impl fmt::Debug for Span {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut span = f.debug_struct("Span");
+ if let Some(meta) = self.meta {
+ span.field("name", &meta.name())
+ .field("level", &meta.level())
+ .field("target", &meta.target());
+
+ if let Some(ref inner) = self.inner {
+ span.field("id", &inner.id());
+ } else {
+ span.field("disabled", &true);
+ }
+
+ if let Some(ref path) = meta.module_path() {
+ span.field("module_path", &path);
+ }
+
+ if let Some(ref line) = meta.line() {
+ span.field("line", &line);
+ }
+
+ if let Some(ref file) = meta.file() {
+ span.field("file", &file);
+ }
+ } else {
+ span.field("none", &true);
+ }
+
+ span.finish()
+ }
+}
+
+impl<'a> From<&'a Span> for Option<&'a Id> {
+ fn from(span: &'a Span) -> Self {
+ span.inner.as_ref().map(|inner| &inner.id)
+ }
+}
+
+impl<'a> From<&'a Span> for Option<Id> {
+ fn from(span: &'a Span) -> Self {
+ span.inner.as_ref().map(Inner::id)
+ }
+}
+
+impl From<Span> for Option<Id> {
+ fn from(span: Span) -> Self {
+ span.inner.as_ref().map(Inner::id)
+ }
+}
+
+impl<'a> From<&'a EnteredSpan> for Option<&'a Id> {
+ fn from(span: &'a EnteredSpan) -> Self {
+ span.inner.as_ref().map(|inner| &inner.id)
+ }
+}
+
+impl<'a> From<&'a EnteredSpan> for Option<Id> {
+ fn from(span: &'a EnteredSpan) -> Self {
+ span.inner.as_ref().map(Inner::id)
+ }
+}
+
+impl Drop for Span {
+ #[inline(always)]
+ fn drop(&mut self) {
+ if let Some(Inner {
+ ref id,
+ ref subscriber,
+ }) = self.inner
+ {
+ subscriber.try_close(id.clone());
+ }
+
+ if_log_enabled! { crate::Level::TRACE, {
+ if let Some(meta) = self.meta {
+ self.log(
+ LIFECYCLE_LOG_TARGET,
+ log::Level::Trace,
+ format_args!("-- {};", meta.name()),
+ );
+ }
+ }}
+ }
+}
+
+// ===== impl Inner =====
+
+impl Inner {
+ /// Indicates that the span with the given ID has an indirect causal
+ /// relationship with this span.
+ ///
+ /// This relationship differs somewhat from the parent-child relationship: a
+ /// span may have any number of prior spans, rather than a single one; and
+ /// spans are not considered to be executing _inside_ of the spans they
+ /// follow from. This means that a span may close even if subsequent spans
+ /// that follow from it are still open, and time spent inside of a
+ /// subsequent span should not be included in the time its precedents were
+ /// executing. This is used to model causal relationships such as when a
+ /// single future spawns several related background tasks, et cetera.
+ ///
+ /// If this span is disabled, this function will do nothing. Otherwise, it
+ /// returns `Ok(())` if the other span was added as a precedent of this
+ /// span, or an error if this was not possible.
+ fn follows_from(&self, from: &Id) {
+ self.subscriber.record_follows_from(&self.id, from)
+ }
+
+ /// Returns the span's ID.
+ fn id(&self) -> Id {
+ self.id.clone()
+ }
+
+ fn record(&self, values: &Record<'_>) {
+ self.subscriber.record(&self.id, values)
+ }
+
+ fn new(id: Id, subscriber: &Dispatch) -> Self {
+ Inner {
+ id,
+ subscriber: subscriber.clone(),
+ }
+ }
+}
+
+impl cmp::PartialEq for Inner {
+ fn eq(&self, other: &Self) -> bool {
+ self.id == other.id
+ }
+}
+
+impl Hash for Inner {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.id.hash(state);
+ }
+}
+
+impl Clone for Inner {
+ fn clone(&self) -> Self {
+ Inner {
+ id: self.subscriber.clone_span(&self.id),
+ subscriber: self.subscriber.clone(),
+ }
+ }
+}
+
+// ===== impl Entered =====
+
+impl EnteredSpan {
+ /// Returns this span's `Id`, if it is enabled.
+ pub fn id(&self) -> Option<Id> {
+ self.inner.as_ref().map(Inner::id)
+ }
+
+ /// Exits this span, returning the underlying [`Span`].
+ #[inline]
+ pub fn exit(mut self) -> Span {
+ // One does not simply move out of a struct with `Drop`.
+ let span = mem::replace(&mut self.span, Span::none());
+ span.do_exit();
+ span
+ }
+}
+
+impl Deref for EnteredSpan {
+ type Target = Span;
+
+ #[inline]
+ fn deref(&self) -> &Span {
+ &self.span
+ }
+}
+
+impl<'a> Drop for Entered<'a> {
+ #[inline(always)]
+ fn drop(&mut self) {
+ self.span.do_exit()
+ }
+}
+
+impl Drop for EnteredSpan {
+ #[inline(always)]
+ fn drop(&mut self) {
+ self.span.do_exit()
+ }
+}
+
+/// Technically, `EnteredSpan` _can_ implement both `Send` *and*
+/// `Sync` safely. It doesn't, because it has a `PhantomNotSend` field,
+/// specifically added in order to make it `!Send`.
+///
+/// Sending an `EnteredSpan` guard between threads cannot cause memory unsafety.
+/// However, it *would* result in incorrect behavior, so we add a
+/// `PhantomNotSend` to prevent it from being sent between threads. This is
+/// because it must be *dropped* on the same thread that it was created;
+/// otherwise, the span will never be exited on the thread where it was entered,
+/// and it will attempt to exit the span on a thread that may never have entered
+/// it. However, we still want them to be `Sync` so that a struct holding an
+/// `Entered` guard can be `Sync`.
+///
+/// Thus, this is totally safe.
+#[derive(Debug)]
+struct PhantomNotSend {
+ ghost: PhantomData<*mut ()>,
+}
+
+#[allow(non_upper_case_globals)]
+const PhantomNotSend: PhantomNotSend = PhantomNotSend { ghost: PhantomData };
+
+/// # Safety
+///
+/// Trivially safe, as `PhantomNotSend` doesn't have any API.
+unsafe impl Sync for PhantomNotSend {}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ trait AssertSend: Send {}
+ impl AssertSend for Span {}
+
+ trait AssertSync: Sync {}
+ impl AssertSync for Span {}
+ impl AssertSync for Entered<'_> {}
+ impl AssertSync for EnteredSpan {}
+
+ #[test]
+ fn test_record_backwards_compat() {
+ Span::current().record("some-key", &"some text");
+ Span::current().record("some-key", &false);
+ }
+}
diff --git a/third_party/rust/tracing/src/stdlib.rs b/third_party/rust/tracing/src/stdlib.rs
new file mode 100644
index 0000000000..12b54084d4
--- /dev/null
+++ b/third_party/rust/tracing/src/stdlib.rs
@@ -0,0 +1,55 @@
+//! Re-exports either the Rust `std` library or `core` and `alloc` when `std` is
+//! disabled.
+//!
+//! `crate::stdlib::...` should be used rather than `std::` when adding code that
+//! will be available with the standard library disabled.
+//!
+//! Note that this module is called `stdlib` rather than `std`, as Rust 1.34.0
+//! does not permit redefining the name `stdlib` (although this works on the
+//! latest stable Rust).
+#[cfg(feature = "std")]
+pub(crate) use std::*;
+
+#[cfg(not(feature = "std"))]
+pub(crate) use self::no_std::*;
+
+#[cfg(not(feature = "std"))]
+mod no_std {
+ // We pre-emptively export everything from libcore/liballoc, (even modules
+ // we aren't using currently) to make adding new code easier. Therefore,
+ // some of these imports will be unused.
+ #![allow(unused_imports)]
+
+ pub(crate) use core::{
+ any, array, ascii, cell, char, clone, cmp, convert, default, f32, f64, ffi, future, hash,
+ hint, i128, i16, i8, isize, iter, marker, mem, num, ops, option, pin, ptr, result, task,
+ time, u128, u16, u32, u8, usize,
+ };
+
+ pub(crate) use alloc::{boxed, collections, rc, string, vec};
+
+ pub(crate) mod borrow {
+ pub(crate) use alloc::borrow::*;
+ pub(crate) use core::borrow::*;
+ }
+
+ pub(crate) mod fmt {
+ pub(crate) use alloc::fmt::*;
+ pub(crate) use core::fmt::*;
+ }
+
+ pub(crate) mod slice {
+ pub(crate) use alloc::slice::*;
+ pub(crate) use core::slice::*;
+ }
+
+ pub(crate) mod str {
+ pub(crate) use alloc::str::*;
+ pub(crate) use core::str::*;
+ }
+
+ pub(crate) mod sync {
+ pub(crate) use alloc::sync::*;
+ pub(crate) use core::sync::*;
+ }
+}
diff --git a/third_party/rust/tracing/src/subscriber.rs b/third_party/rust/tracing/src/subscriber.rs
new file mode 100644
index 0000000000..f55698d13f
--- /dev/null
+++ b/third_party/rust/tracing/src/subscriber.rs
@@ -0,0 +1,65 @@
+//! Collects and records trace data.
+pub use tracing_core::subscriber::*;
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub use tracing_core::dispatcher::DefaultGuard;
+
+/// Sets this [`Subscriber`] as the default for the current thread for the
+/// duration of a closure.
+///
+/// The default subscriber is used when creating a new [`Span`] or
+/// [`Event`].
+///
+///
+/// [`Span`]: super::span::Span
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [`Event`]: super::event::Event
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+pub fn with_default<T, S>(subscriber: S, f: impl FnOnce() -> T) -> T
+where
+ S: Subscriber + Send + Sync + 'static,
+{
+ crate::dispatcher::with_default(&crate::Dispatch::new(subscriber), f)
+}
+
+/// Sets this subscriber as the global default for the duration of the entire program.
+/// Will be used as a fallback if no thread-local subscriber has been set in a thread (using `with_default`.)
+///
+/// Can only be set once; subsequent attempts to set the global default will fail.
+/// Returns whether the initialization was successful.
+///
+/// Note: Libraries should *NOT* call `set_global_default()`! That will cause conflicts when
+/// executables try to set them later.
+///
+/// [span]: super::span
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [`Event`]: super::event::Event
+pub fn set_global_default<S>(subscriber: S) -> Result<(), SetGlobalDefaultError>
+where
+ S: Subscriber + Send + Sync + 'static,
+{
+ crate::dispatcher::set_global_default(crate::Dispatch::new(subscriber))
+}
+
+/// Sets the [`Subscriber`] as the default for the current thread for the
+/// duration of the lifetime of the returned [`DefaultGuard`].
+///
+/// The default subscriber is used when creating a new [`Span`] or [`Event`].
+///
+/// [`Span`]: super::span::Span
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [`Event`]: super::event::Event
+/// [`DefaultGuard`]: super::dispatcher::DefaultGuard
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+#[must_use = "Dropping the guard unregisters the subscriber."]
+pub fn set_default<S>(subscriber: S) -> DefaultGuard
+where
+ S: Subscriber + Send + Sync + 'static,
+{
+ crate::dispatcher::set_default(&crate::Dispatch::new(subscriber))
+}
+
+pub use tracing_core::dispatcher::SetGlobalDefaultError;
diff --git a/third_party/rust/tracing/tests/enabled.rs b/third_party/rust/tracing/tests/enabled.rs
new file mode 100644
index 0000000000..ea1c69804d
--- /dev/null
+++ b/third_party/rust/tracing/tests/enabled.rs
@@ -0,0 +1,54 @@
+#![cfg(feature = "std")]
+use tracing::Level;
+use tracing_mock::*;
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn level_and_target() {
+ let subscriber = subscriber::mock()
+ .with_filter(|meta| {
+ if meta.target() == "debug_module" {
+ meta.level() <= &Level::DEBUG
+ } else {
+ meta.level() <= &Level::INFO
+ }
+ })
+ .done()
+ .run();
+
+ let _guard = tracing::subscriber::set_default(subscriber);
+
+ assert!(tracing::enabled!(target: "debug_module", Level::DEBUG));
+ assert!(tracing::enabled!(Level::ERROR));
+ assert!(!tracing::enabled!(Level::DEBUG));
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span_and_event() {
+ let subscriber = subscriber::mock()
+ .with_filter(|meta| {
+ if meta.target() == "debug_module" {
+ meta.level() <= &Level::DEBUG
+ } else if meta.is_span() {
+ meta.level() <= &Level::TRACE
+ } else if meta.is_event() {
+ meta.level() <= &Level::DEBUG
+ } else {
+ meta.level() <= &Level::INFO
+ }
+ })
+ .done()
+ .run();
+
+ let _guard = tracing::subscriber::set_default(subscriber);
+
+ // Ensure that the `_event` and `_span` alternatives work corretly
+ assert!(!tracing::event_enabled!(Level::TRACE));
+ assert!(tracing::event_enabled!(Level::DEBUG));
+ assert!(tracing::span_enabled!(Level::TRACE));
+
+ // target variants
+ assert!(tracing::span_enabled!(target: "debug_module", Level::DEBUG));
+ assert!(tracing::event_enabled!(target: "debug_module", Level::DEBUG));
+}
diff --git a/third_party/rust/tracing/tests/event.rs b/third_party/rust/tracing/tests/event.rs
new file mode 100644
index 0000000000..61df19ad3c
--- /dev/null
+++ b/third_party/rust/tracing/tests/event.rs
@@ -0,0 +1,500 @@
+// These tests require the thread-local scoped dispatcher, which only works when
+// we have a standard library. The behaviour being tested should be the same
+// with the standard lib disabled.
+//
+// The alternative would be for each of these tests to be defined in a separate
+// file, which is :(
+#![cfg(feature = "std")]
+
+use tracing::{
+ debug, error,
+ field::{debug, display},
+ info,
+ subscriber::with_default,
+ trace, warn, Level,
+};
+use tracing_mock::*;
+
+macro_rules! event_without_message {
+ ($name:ident: $e:expr) => {
+ #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+ #[test]
+ fn $name() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("answer")
+ .with_value(&42)
+ .and(
+ field::mock("to_question")
+ .with_value(&"life, the universe, and everything"),
+ )
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ info!(
+ answer = $e,
+ to_question = "life, the universe, and everything"
+ );
+ });
+
+ handle.assert_finished();
+ }
+ };
+}
+
+event_without_message! {event_without_message: 42}
+event_without_message! {wrapping_event_without_message: std::num::Wrapping(42)}
+event_without_message! {nonzeroi32_event_without_message: std::num::NonZeroI32::new(42).unwrap()}
+// needs API breakage
+//event_without_message!{nonzerou128_event_without_message: std::num::NonZeroU128::new(42).unwrap()}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event_with_message() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(event::msg(format_args!(
+ "hello from my event! yak shaved = {:?}",
+ true
+ )))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ debug!("hello from my event! yak shaved = {:?}", true);
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn message_without_delims() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("answer")
+ .with_value(&42)
+ .and(field::mock("question").with_value(&"life, the universe, and everything"))
+ .and(field::msg(format_args!(
+ "hello from my event! tricky? {:?}!",
+ true
+ )))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let question = "life, the universe, and everything";
+ debug!(answer = 42, question, "hello from {where}! tricky? {:?}!", true, where = "my event");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn string_message_without_delims() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("answer")
+ .with_value(&42)
+ .and(field::mock("question").with_value(&"life, the universe, and everything"))
+ .and(field::msg(format_args!("hello from my event")))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let question = "life, the universe, and everything";
+ debug!(answer = 42, question, "hello from my event");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn one_with_everything() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock()
+ .with_fields(
+ field::mock("message")
+ .with_value(&tracing::field::debug(format_args!(
+ "{:#x} make me one with{what:.>20}",
+ 4_277_009_102u64,
+ what = "everything"
+ )))
+ .and(field::mock("foo").with_value(&666))
+ .and(field::mock("bar").with_value(&false))
+ .and(field::mock("like_a_butterfly").with_value(&42.0))
+ .only(),
+ )
+ .at_level(Level::ERROR)
+ .with_target("whatever"),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::event!(
+ target: "whatever",
+ Level::ERROR,
+ { foo = 666, bar = false, like_a_butterfly = 42.0 },
+ "{:#x} make me one with{what:.>20}", 4_277_009_102u64, what = "everything"
+ );
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn moved_field() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("foo")
+ .with_value(&display("hello from my event"))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let from = "my event";
+ tracing::event!(Level::INFO, foo = display(format!("hello from {}", from)))
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn dotted_field_name() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("foo.bar")
+ .with_value(&true)
+ .and(field::mock("foo.baz").with_value(&false))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::event!(Level::INFO, foo.bar = true, foo.baz = false);
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn borrowed_field() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("foo")
+ .with_value(&display("hello from my event"))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let from = "my event";
+ let mut message = format!("hello from {}", from);
+ tracing::event!(Level::INFO, foo = display(&message));
+ message.push_str(", which happened!");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+// If emitting log instrumentation, this gets moved anyway, breaking the test.
+#[cfg(not(feature = "log"))]
+fn move_field_out_of_struct() {
+ use tracing::field::debug;
+
+ #[derive(Debug)]
+ struct Position {
+ x: f32,
+ y: f32,
+ }
+
+ let pos = Position {
+ x: 3.234,
+ y: -1.223,
+ };
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("x")
+ .with_value(&debug(3.234))
+ .and(field::mock("y").with_value(&debug(-1.223)))
+ .only(),
+ ),
+ )
+ .event(event::mock().with_fields(field::mock("position").with_value(&debug(&pos))))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let pos = Position {
+ x: 3.234,
+ y: -1.223,
+ };
+ debug!(x = debug(pos.x), y = debug(pos.y));
+ debug!(target: "app_events", { position = debug(pos) }, "New position");
+ });
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn display_shorthand() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("my_field")
+ .with_value(&display("hello world"))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::event!(Level::TRACE, my_field = %"hello world");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug_shorthand() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("my_field")
+ .with_value(&debug("hello world"))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::event!(Level::TRACE, my_field = ?"hello world");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn both_shorthands() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("display_field")
+ .with_value(&display("hello world"))
+ .and(field::mock("debug_field").with_value(&debug("hello world")))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::event!(Level::TRACE, display_field = %"hello world", debug_field = ?"hello world");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn explicit_child() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .event(event::mock().with_explicit_parent(Some("foo")))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ tracing::event!(parent: foo.id(), Level::TRACE, "bar");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn explicit_child_at_levels() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .event(event::mock().with_explicit_parent(Some("foo")))
+ .event(event::mock().with_explicit_parent(Some("foo")))
+ .event(event::mock().with_explicit_parent(Some("foo")))
+ .event(event::mock().with_explicit_parent(Some("foo")))
+ .event(event::mock().with_explicit_parent(Some("foo")))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ trace!(parent: foo.id(), "a");
+ debug!(parent: foo.id(), "b");
+ info!(parent: foo.id(), "c");
+ warn!(parent: foo.id(), "d");
+ error!(parent: foo.id(), "e");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn option_values() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("some_str")
+ .with_value(&"yes")
+ .and(field::mock("some_bool").with_value(&true))
+ .and(field::mock("some_u64").with_value(&42_u64))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let some_str = Some("yes");
+ let none_str: Option<&'static str> = None;
+ let some_bool = Some(true);
+ let none_bool: Option<bool> = None;
+ let some_u64 = Some(42_u64);
+ let none_u64: Option<u64> = None;
+ trace!(
+ some_str = some_str,
+ none_str = none_str,
+ some_bool = some_bool,
+ none_bool = none_bool,
+ some_u64 = some_u64,
+ none_u64 = none_u64
+ );
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn option_ref_values() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("some_str")
+ .with_value(&"yes")
+ .and(field::mock("some_bool").with_value(&true))
+ .and(field::mock("some_u64").with_value(&42_u64))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let some_str = &Some("yes");
+ let none_str: &Option<&'static str> = &None;
+ let some_bool = &Some(true);
+ let none_bool: &Option<bool> = &None;
+ let some_u64 = &Some(42_u64);
+ let none_u64: &Option<u64> = &None;
+ trace!(
+ some_str = some_str,
+ none_str = none_str,
+ some_bool = some_bool,
+ none_bool = none_bool,
+ some_u64 = some_u64,
+ none_u64 = none_u64
+ );
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn option_ref_mut_values() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(
+ event::mock().with_fields(
+ field::mock("some_str")
+ .with_value(&"yes")
+ .and(field::mock("some_bool").with_value(&true))
+ .and(field::mock("some_u64").with_value(&42_u64))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let some_str = &mut Some("yes");
+ let none_str: &mut Option<&'static str> = &mut None;
+ let some_bool = &mut Some(true);
+ let none_bool: &mut Option<bool> = &mut None;
+ let some_u64 = &mut Some(42_u64);
+ let none_u64: &mut Option<u64> = &mut None;
+ trace!(
+ some_str = some_str,
+ none_str = none_str,
+ some_bool = some_bool,
+ none_bool = none_bool,
+ some_u64 = some_u64,
+ none_u64 = none_u64
+ );
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn string_field() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(event::mock().with_fields(field::mock("my_string").with_value(&"hello").only()))
+ .event(
+ event::mock().with_fields(field::mock("my_string").with_value(&"hello world!").only()),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let mut my_string = String::from("hello");
+
+ tracing::event!(Level::INFO, my_string);
+
+ // the string is not moved by using it as a field!
+ my_string.push_str(" world!");
+
+ tracing::event!(Level::INFO, my_string);
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/filter_caching_is_lexically_scoped.rs b/third_party/rust/tracing/tests/filter_caching_is_lexically_scoped.rs
new file mode 100644
index 0000000000..e291103d75
--- /dev/null
+++ b/third_party/rust/tracing/tests/filter_caching_is_lexically_scoped.rs
@@ -0,0 +1,65 @@
+// Tests that depend on a count of the number of times their filter is evaluated
+// can't exist in the same file with other tests that add subscribers to the
+// registry. The registry was changed so that each time a new dispatcher is
+// added all filters are re-evaluated. The tests being run only in separate
+// threads with shared global state lets them interfere with each other
+
+#[cfg(not(feature = "std"))]
+extern crate std;
+
+use tracing::{span, Level};
+use tracing_mock::*;
+
+use std::sync::{
+ atomic::{AtomicUsize, Ordering},
+ Arc,
+};
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn filter_caching_is_lexically_scoped() {
+ pub fn my_great_function() -> bool {
+ span!(Level::TRACE, "emily").in_scope(|| true)
+ }
+
+ pub fn my_other_function() -> bool {
+ span!(Level::TRACE, "frank").in_scope(|| true)
+ }
+
+ let count = Arc::new(AtomicUsize::new(0));
+ let count2 = count.clone();
+
+ let subscriber = subscriber::mock()
+ .with_filter(move |meta| match meta.name() {
+ "emily" | "frank" => {
+ count2.fetch_add(1, Ordering::Relaxed);
+ true
+ }
+ _ => false,
+ })
+ .run();
+
+ // Since this test is in its own file anyway, we can do this. Thus, this
+ // test will work even with no-std.
+ tracing::subscriber::set_global_default(subscriber).unwrap();
+
+ // Call the function once. The filter should be re-evaluated.
+ assert!(my_great_function());
+ assert_eq!(count.load(Ordering::Relaxed), 1);
+
+ // Call the function again. The cached result should be used.
+ assert!(my_great_function());
+ assert_eq!(count.load(Ordering::Relaxed), 1);
+
+ assert!(my_other_function());
+ assert_eq!(count.load(Ordering::Relaxed), 2);
+
+ assert!(my_great_function());
+ assert_eq!(count.load(Ordering::Relaxed), 2);
+
+ assert!(my_other_function());
+ assert_eq!(count.load(Ordering::Relaxed), 2);
+
+ assert!(my_great_function());
+ assert_eq!(count.load(Ordering::Relaxed), 2);
+}
diff --git a/third_party/rust/tracing/tests/filters_are_not_reevaluated_for_the_same_span.rs b/third_party/rust/tracing/tests/filters_are_not_reevaluated_for_the_same_span.rs
new file mode 100644
index 0000000000..e9b2529b8f
--- /dev/null
+++ b/third_party/rust/tracing/tests/filters_are_not_reevaluated_for_the_same_span.rs
@@ -0,0 +1,70 @@
+// Tests that depend on a count of the number of times their filter is evaluated
+// cant exist in the same file with other tests that add subscribers to the
+// registry. The registry was changed so that each time a new dispatcher is
+// added all filters are re-evaluated. The tests being run only in separate
+// threads with shared global state lets them interfere with each other
+#[cfg(not(feature = "std"))]
+extern crate std;
+
+use tracing::{span, Level};
+use tracing_mock::*;
+
+use std::sync::{
+ atomic::{AtomicUsize, Ordering},
+ Arc,
+};
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn filters_are_not_reevaluated_for_the_same_span() {
+ // Asserts that the `span!` macro caches the result of calling
+ // `Subscriber::enabled` for each span.
+ let alice_count = Arc::new(AtomicUsize::new(0));
+ let bob_count = Arc::new(AtomicUsize::new(0));
+ let alice_count2 = alice_count.clone();
+ let bob_count2 = bob_count.clone();
+
+ let (subscriber, handle) = subscriber::mock()
+ .with_filter(move |meta| match meta.name() {
+ "alice" => {
+ alice_count2.fetch_add(1, Ordering::Relaxed);
+ false
+ }
+ "bob" => {
+ bob_count2.fetch_add(1, Ordering::Relaxed);
+ true
+ }
+ _ => false,
+ })
+ .run_with_handle();
+
+ // Since this test is in its own file anyway, we can do this. Thus, this
+ // test will work even with no-std.
+ tracing::subscriber::set_global_default(subscriber).unwrap();
+
+ // Enter "alice" and then "bob". The dispatcher expects to see "bob" but
+ // not "alice."
+ let alice = span!(Level::TRACE, "alice");
+ let bob = alice.in_scope(|| {
+ let bob = span!(Level::TRACE, "bob");
+ bob.in_scope(|| ());
+ bob
+ });
+
+ // The filter should have seen each span a single time.
+ assert_eq!(alice_count.load(Ordering::Relaxed), 1);
+ assert_eq!(bob_count.load(Ordering::Relaxed), 1);
+
+ alice.in_scope(|| bob.in_scope(|| {}));
+
+ // The subscriber should see "bob" again, but the filter should not have
+ // been called.
+ assert_eq!(alice_count.load(Ordering::Relaxed), 1);
+ assert_eq!(bob_count.load(Ordering::Relaxed), 1);
+
+ bob.in_scope(|| {});
+ assert_eq!(alice_count.load(Ordering::Relaxed), 1);
+ assert_eq!(bob_count.load(Ordering::Relaxed), 1);
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs b/third_party/rust/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs
new file mode 100644
index 0000000000..265d4a8865
--- /dev/null
+++ b/third_party/rust/tracing/tests/filters_are_reevaluated_for_different_call_sites.rs
@@ -0,0 +1,80 @@
+// Tests that depend on a count of the number of times their filter is evaluated
+// cant exist in the same file with other tests that add subscribers to the
+// registry. The registry was changed so that each time a new dispatcher is
+// added all filters are re-evaluated. The tests being run only in separate
+// threads with shared global state lets them interfere with each other
+#[cfg(not(feature = "std"))]
+extern crate std;
+
+use tracing::{span, Level};
+use tracing_mock::*;
+
+use std::sync::{
+ atomic::{AtomicUsize, Ordering},
+ Arc,
+};
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn filters_are_reevaluated_for_different_call_sites() {
+ // Asserts that the `span!` macro caches the result of calling
+ // `Subscriber::enabled` for each span.
+ let charlie_count = Arc::new(AtomicUsize::new(0));
+ let dave_count = Arc::new(AtomicUsize::new(0));
+ let charlie_count2 = charlie_count.clone();
+ let dave_count2 = dave_count.clone();
+
+ let subscriber = subscriber::mock()
+ .with_filter(move |meta| {
+ println!("Filter: {:?}", meta.name());
+ match meta.name() {
+ "charlie" => {
+ charlie_count2.fetch_add(1, Ordering::Relaxed);
+ false
+ }
+ "dave" => {
+ dave_count2.fetch_add(1, Ordering::Relaxed);
+ true
+ }
+ _ => false,
+ }
+ })
+ .run();
+
+ // Since this test is in its own file anyway, we can do this. Thus, this
+ // test will work even with no-std.
+ tracing::subscriber::set_global_default(subscriber).unwrap();
+
+ // Enter "charlie" and then "dave". The dispatcher expects to see "dave" but
+ // not "charlie."
+ let charlie = span!(Level::TRACE, "charlie");
+ let dave = charlie.in_scope(|| {
+ let dave = span!(Level::TRACE, "dave");
+ dave.in_scope(|| {});
+ dave
+ });
+
+ // The filter should have seen each span a single time.
+ assert_eq!(charlie_count.load(Ordering::Relaxed), 1);
+ assert_eq!(dave_count.load(Ordering::Relaxed), 1);
+
+ charlie.in_scope(|| dave.in_scope(|| {}));
+
+ // The subscriber should see "dave" again, but the filter should not have
+ // been called.
+ assert_eq!(charlie_count.load(Ordering::Relaxed), 1);
+ assert_eq!(dave_count.load(Ordering::Relaxed), 1);
+
+ // A different span with the same name has a different call site, so it
+ // should cause the filter to be reapplied.
+ let charlie2 = span!(Level::TRACE, "charlie");
+ charlie.in_scope(|| {});
+ assert_eq!(charlie_count.load(Ordering::Relaxed), 2);
+ assert_eq!(dave_count.load(Ordering::Relaxed), 1);
+
+ // But, the filter should not be re-evaluated for the new "charlie" span
+ // when it is re-entered.
+ charlie2.in_scope(|| span!(Level::TRACE, "dave").in_scope(|| {}));
+ assert_eq!(charlie_count.load(Ordering::Relaxed), 2);
+ assert_eq!(dave_count.load(Ordering::Relaxed), 2);
+}
diff --git a/third_party/rust/tracing/tests/filters_dont_leak.rs b/third_party/rust/tracing/tests/filters_dont_leak.rs
new file mode 100644
index 0000000000..2ef1c9c701
--- /dev/null
+++ b/third_party/rust/tracing/tests/filters_dont_leak.rs
@@ -0,0 +1,81 @@
+#![cfg(feature = "std")]
+
+use tracing_mock::*;
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn spans_dont_leak() {
+ fn do_span() {
+ let span = tracing::debug_span!("alice");
+ let _e = span.enter();
+ }
+
+ let (subscriber, handle) = subscriber::mock()
+ .named("spans/subscriber1")
+ .with_filter(|_| false)
+ .done()
+ .run_with_handle();
+
+ let _guard = tracing::subscriber::set_default(subscriber);
+
+ do_span();
+
+ let alice = span::mock().named("alice");
+ let (subscriber2, handle2) = subscriber::mock()
+ .named("spans/subscriber2")
+ .with_filter(|_| true)
+ .new_span(alice.clone())
+ .enter(alice.clone())
+ .exit(alice.clone())
+ .drop_span(alice)
+ .done()
+ .run_with_handle();
+
+ tracing::subscriber::with_default(subscriber2, || {
+ println!("--- subscriber 2 is default ---");
+ do_span()
+ });
+
+ println!("--- subscriber 1 is default ---");
+ do_span();
+
+ handle.assert_finished();
+ handle2.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn events_dont_leak() {
+ fn do_event() {
+ tracing::debug!("alice");
+ }
+
+ let (subscriber, handle) = subscriber::mock()
+ .named("events/subscriber1")
+ .with_filter(|_| false)
+ .done()
+ .run_with_handle();
+
+ let _guard = tracing::subscriber::set_default(subscriber);
+
+ do_event();
+
+ let (subscriber2, handle2) = subscriber::mock()
+ .named("events/subscriber2")
+ .with_filter(|_| true)
+ .event(event::mock())
+ .done()
+ .run_with_handle();
+
+ tracing::subscriber::with_default(subscriber2, || {
+ println!("--- subscriber 2 is default ---");
+ do_event()
+ });
+
+ println!("--- subscriber 1 is default ---");
+
+ do_event();
+
+ handle.assert_finished();
+ handle2.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/future_send.rs b/third_party/rust/tracing/tests/future_send.rs
new file mode 100644
index 0000000000..5e5f9f18bc
--- /dev/null
+++ b/third_party/rust/tracing/tests/future_send.rs
@@ -0,0 +1,22 @@
+// These tests reproduce the following issues:
+// - https://github.com/tokio-rs/tracing/issues/1487
+// - https://github.com/tokio-rs/tracing/issues/1793
+
+use core::future::{self, Future};
+#[test]
+fn async_fn_is_send() {
+ async fn some_async_fn() {
+ tracing::info!("{}", future::ready("test").await);
+ }
+
+ assert_send(some_async_fn())
+}
+
+#[test]
+fn async_block_is_send() {
+ assert_send(async {
+ tracing::info!("{}", future::ready("test").await);
+ })
+}
+
+fn assert_send<F: Future + Send>(_f: F) {}
diff --git a/third_party/rust/tracing/tests/macro_imports.rs b/third_party/rust/tracing/tests/macro_imports.rs
new file mode 100644
index 0000000000..2d0a9d6528
--- /dev/null
+++ b/third_party/rust/tracing/tests/macro_imports.rs
@@ -0,0 +1,23 @@
+use tracing::Level;
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn prefixed_span_macros() {
+ tracing::span!(Level::DEBUG, "foo");
+ tracing::trace_span!("foo");
+ tracing::debug_span!("foo");
+ tracing::info_span!("foo");
+ tracing::warn_span!("foo");
+ tracing::error_span!("foo");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn prefixed_event_macros() {
+ tracing::event!(Level::DEBUG, "foo");
+ tracing::trace!("foo");
+ tracing::debug!("foo");
+ tracing::info!("foo");
+ tracing::warn!("foo");
+ tracing::error!("foo");
+}
diff --git a/third_party/rust/tracing/tests/macros.rs b/third_party/rust/tracing/tests/macros.rs
new file mode 100644
index 0000000000..a9679a3e94
--- /dev/null
+++ b/third_party/rust/tracing/tests/macros.rs
@@ -0,0 +1,963 @@
+#![deny(warnings)]
+use tracing::{
+ callsite, debug, debug_span, enabled, error, error_span, event, event_enabled, info, info_span,
+ span, span_enabled, trace, trace_span, warn, warn_span, Level,
+};
+
+// Tests that macros work across various invocation syntax.
+//
+// These are quite repetitive, and _could_ be generated by a macro. However,
+// they're compile-time tests, so I want to get line numbers etc out of
+// failures, and producing them with a macro would muddy the waters a bit.
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span() {
+ span!(target: "foo_events", Level::DEBUG, "foo", bar.baz = ?2, quux = %3, quuux = 4);
+ span!(target: "foo_events", Level::DEBUG, "foo", bar.baz = 2, quux = 3);
+ span!(target: "foo_events", Level::DEBUG, "foo", bar.baz = 2, quux = 4,);
+ span!(target: "foo_events", Level::DEBUG, "foo");
+ span!(target: "foo_events", Level::DEBUG, "bar",);
+ span!(Level::DEBUG, "foo", bar.baz = 2, quux = 3);
+ span!(Level::DEBUG, "foo", bar.baz = 2, quux = 4,);
+ span!(Level::DEBUG, "foo", bar.baz = 2, quux = 3);
+ span!(Level::DEBUG, "foo", bar.baz = 2, quux = 4,);
+ span!(Level::DEBUG, "foo", bar.baz = ?2);
+ span!(Level::DEBUG, "foo", bar.baz = %2);
+ span!(Level::DEBUG, "foo");
+ span!(Level::DEBUG, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn trace_span() {
+ trace_span!(target: "foo_events", "foo", bar.baz = ?2, quux = %3, quuux = 4);
+ trace_span!(target: "foo_events", "foo", bar.baz = 2, quux = 3);
+ trace_span!(target: "foo_events", "foo", bar.baz = 2, quux = 4,);
+ trace_span!(target: "foo_events", "foo");
+ trace_span!(target: "foo_events", "bar",);
+ trace_span!("foo", bar.baz = 2, quux = 3);
+ trace_span!("foo", bar.baz = 2, quux = 4,);
+ trace_span!("foo", bar.baz = ?2);
+ trace_span!("foo", bar.baz = %2);
+ trace_span!("bar");
+ trace_span!("bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug_span() {
+ debug_span!(target: "foo_events", "foo", bar.baz = ?2, quux = %3, quuux = 4);
+ debug_span!(target: "foo_events", "foo", bar.baz = 2, quux = 3);
+ debug_span!(target: "foo_events", "foo", bar.baz = 2, quux = 4,);
+ debug_span!(target: "foo_events", "foo");
+ debug_span!(target: "foo_events", "bar",);
+ debug_span!("foo", bar.baz = 2, quux = 3);
+ debug_span!("foo", bar.baz = 2, quux = 4,);
+ debug_span!("foo", bar.baz = ?2);
+ debug_span!("foo", bar.baz = %2);
+ debug_span!("bar");
+ debug_span!("bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn info_span() {
+ info_span!(target: "foo_events", "foo", bar.baz = ?2, quux = %3, quuux = 4);
+ info_span!(target: "foo_events", "foo", bar.baz = 2, quux = 3);
+ info_span!(target: "foo_events", "foo", bar.baz = 2, quux = 4,);
+ info_span!(target: "foo_events", "foo");
+ info_span!(target: "foo_events", "bar",);
+ info_span!("foo", bar.baz = 2, quux = 3);
+ info_span!("foo", bar.baz = 2, quux = 4,);
+ info_span!("foo", bar.baz = ?2);
+ info_span!("foo", bar.baz = %2);
+ info_span!("bar");
+ info_span!("bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn warn_span() {
+ warn_span!(target: "foo_events", "foo", bar.baz = ?2, quux = %3, quuux = 4);
+ warn_span!(target: "foo_events", "foo", bar.baz = 2, quux = 3);
+ warn_span!(target: "foo_events", "foo", bar.baz = 2, quux = 4,);
+ warn_span!(target: "foo_events", "foo");
+ warn_span!(target: "foo_events", "bar",);
+ warn_span!("foo", bar.baz = 2, quux = 3);
+ warn_span!("foo", bar.baz = 2, quux = 4,);
+ warn_span!("foo", bar.baz = ?2);
+ warn_span!("foo", bar.baz = %2);
+ warn_span!("bar");
+ warn_span!("bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn error_span() {
+ error_span!(target: "foo_events", "foo", bar.baz = ?2, quux = %3, quuux = 4);
+ error_span!(target: "foo_events", "foo", bar.baz = 2, quux = 3);
+ error_span!(target: "foo_events", "foo", bar.baz = 2, quux = 4,);
+ error_span!(target: "foo_events", "foo");
+ error_span!(target: "foo_events", "bar",);
+ error_span!("foo", bar.baz = 2, quux = 3);
+ error_span!("foo", bar.baz = 2, quux = 4,);
+ error_span!("foo", bar.baz = ?2);
+ error_span!("foo", bar.baz = %2);
+ error_span!("bar");
+ error_span!("bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span_root() {
+ span!(target: "foo_events", parent: None, Level::TRACE, "foo", bar.baz = 2, quux = 3);
+ span!(target: "foo_events", parent: None, Level::TRACE, "foo", bar.baz = 2, quux = 3);
+ span!(target: "foo_events", parent: None, Level::TRACE, "foo", bar.baz = 2, quux = 4,);
+ span!(target: "foo_events", parent: None, Level::TRACE, "foo");
+ span!(target: "foo_events", parent: None, Level::TRACE, "bar",);
+ span!(parent: None, Level::DEBUG, "foo", bar.baz = 2, quux = 3);
+ span!(parent: None, Level::DEBUG, "foo", bar.baz = 2, quux = 4,);
+ span!(parent: None, Level::DEBUG, "foo");
+ span!(parent: None, Level::DEBUG, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn trace_span_root() {
+ trace_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
+ trace_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
+ trace_span!(target: "foo_events", parent: None, "foo");
+ trace_span!(target: "foo_events", parent: None, "bar",);
+ trace_span!(parent: None, "foo", bar.baz = 2, quux = 3);
+ trace_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
+ trace_span!(parent: None, "foo");
+ trace_span!(parent: None, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug_span_root() {
+ debug_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
+ debug_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
+ debug_span!(target: "foo_events", parent: None, "foo");
+ debug_span!(target: "foo_events", parent: None, "bar",);
+ debug_span!(parent: None, "foo", bar.baz = 2, quux = 3);
+ debug_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
+ debug_span!(parent: None, "foo");
+ debug_span!(parent: None, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn info_span_root() {
+ info_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
+ info_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
+ info_span!(target: "foo_events", parent: None, "foo");
+ info_span!(target: "foo_events", parent: None, "bar",);
+ info_span!(parent: None, "foo", bar.baz = 2, quux = 3);
+ info_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
+ info_span!(parent: None, "foo");
+ info_span!(parent: None, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn warn_span_root() {
+ warn_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
+ warn_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
+ warn_span!(target: "foo_events", parent: None, "foo");
+ warn_span!(target: "foo_events", parent: None, "bar",);
+ warn_span!(parent: None, "foo", bar.baz = 2, quux = 3);
+ warn_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
+ warn_span!(parent: None, "foo");
+ warn_span!(parent: None, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn error_span_root() {
+ error_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 3);
+ error_span!(target: "foo_events", parent: None, "foo", bar.baz = 2, quux = 4,);
+ error_span!(target: "foo_events", parent: None, "foo");
+ error_span!(target: "foo_events", parent: None, "bar",);
+ error_span!(parent: None, "foo", bar.baz = 2, quux = 3);
+ error_span!(parent: None, "foo", bar.baz = 2, quux = 4,);
+ error_span!(parent: None, "foo");
+ error_span!(parent: None, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ span!(target: "foo_events", parent: &p, Level::TRACE, "foo", bar.baz = 2, quux = 3);
+ span!(target: "foo_events", parent: &p, Level::TRACE, "foo", bar.baz = 2, quux = 4,);
+ span!(target: "foo_events", parent: &p, Level::TRACE, "foo");
+ span!(target: "foo_events", parent: &p, Level::TRACE, "bar",);
+ span!(parent: &p, Level::DEBUG, "foo", bar.baz = 2, quux = 3);
+ span!(parent: &p, Level::DEBUG, "foo", bar.baz = 2, quux = 4,);
+ span!(parent: &p, Level::DEBUG, "foo");
+ span!(parent: &p, Level::DEBUG, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn trace_span_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ trace_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 3);
+ trace_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 4,);
+ trace_span!(target: "foo_events", parent: &p, "foo");
+ trace_span!(target: "foo_events", parent: &p, "bar",);
+
+ trace_span!(parent: &p, "foo", bar.baz = 2, quux = 3);
+ trace_span!(parent: &p, "foo", bar.baz = 2, quux = 4,);
+
+ trace_span!(parent: &p, "foo");
+ trace_span!(parent: &p, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug_span_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ debug_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 3);
+ debug_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 4,);
+ debug_span!(target: "foo_events", parent: &p, "foo");
+ debug_span!(target: "foo_events", parent: &p, "bar",);
+
+ debug_span!(parent: &p, "foo", bar.baz = 2, quux = 3);
+ debug_span!(parent: &p, "foo", bar.baz = 2, quux = 4,);
+
+ debug_span!(parent: &p, "foo");
+ debug_span!(parent: &p, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn info_span_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ info_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 3);
+ info_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 4,);
+ info_span!(target: "foo_events", parent: &p, "foo");
+ info_span!(target: "foo_events", parent: &p, "bar",);
+
+ info_span!(parent: &p, "foo", bar.baz = 2, quux = 3);
+ info_span!(parent: &p, "foo", bar.baz = 2, quux = 4,);
+
+ info_span!(parent: &p, "foo");
+ info_span!(parent: &p, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn warn_span_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ warn_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 3);
+ warn_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 4,);
+ warn_span!(target: "foo_events", parent: &p, "foo");
+ warn_span!(target: "foo_events", parent: &p, "bar",);
+
+ warn_span!(parent: &p, "foo", bar.baz = 2, quux = 3);
+ warn_span!(parent: &p, "foo", bar.baz = 2, quux = 4,);
+
+ warn_span!(parent: &p, "foo");
+ warn_span!(parent: &p, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn error_span_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ error_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 3);
+ error_span!(target: "foo_events", parent: &p, "foo", bar.baz = 2, quux = 4,);
+ error_span!(target: "foo_events", parent: &p, "foo");
+ error_span!(target: "foo_events", parent: &p, "bar",);
+
+ error_span!(parent: &p, "foo", bar.baz = 2, quux = 3);
+ error_span!(parent: &p, "foo", bar.baz = 2, quux = 4,);
+
+ error_span!(parent: &p, "foo");
+ error_span!(parent: &p, "bar",);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span_with_non_rust_symbol() {
+ span!(Level::TRACE, "non-rust", "guid:x-request-id" = ?"abcdef", "more {}", 42);
+ span!(Level::TRACE, "non-rust", "guid:x-request-id" = %"abcdef", "more {}", 51);
+ span!(
+ Level::TRACE,
+ "non-rust",
+ "guid:x-request-id" = "abcdef",
+ "more {}",
+ 60
+ );
+ span!(Level::TRACE, "non-rust", "guid:x-request-id" = ?"abcdef");
+ span!(Level::TRACE, "non-rust", "guid:x-request-id" = %"abcdef");
+ span!(Level::TRACE, "non-rust", "guid:x-request-id" = "abcdef");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event() {
+ event!(Level::DEBUG, foo = ?3, bar.baz = %2, quux = false);
+ event!(Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+ event!(Level::DEBUG, foo = 3, bar.baz = 3,);
+ event!(Level::DEBUG, "foo");
+ event!(Level::DEBUG, "foo: {}", 3);
+ event!(Level::INFO, foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
+ event!(
+ Level::INFO,
+ foo = 3,
+ bar.baz = 2,
+ quux = false,
+ "hello world {:?}",
+ 42
+ );
+ event!(Level::INFO, foo = 3, bar.baz = 3, "hello world {:?}", 42,);
+ event!(Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+ event!(Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ event!(Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ event!(Level::DEBUG, { foo = ?2, bar.baz = %78 }, "quux");
+ event!(target: "foo_events", Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+ event!(target: "foo_events", Level::DEBUG, foo = 3, bar.baz = 3,);
+ event!(target: "foo_events", Level::DEBUG, "foo");
+ event!(target: "foo_events", Level::DEBUG, "foo: {}", 3);
+ event!(target: "foo_events", Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+ event!(target: "foo_events", Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ event!(target: "foo_events", Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ event!(target: "foo_events", Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
+ let foo = 1;
+ event!(Level::DEBUG, ?foo);
+ event!(Level::DEBUG, %foo);
+ event!(Level::DEBUG, foo);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn enabled() {
+ enabled!(Level::DEBUG, foo, bar.baz, quux,);
+ enabled!(Level::DEBUG, message);
+ enabled!(Level::INFO, foo, bar.baz, quux, message,);
+ enabled!(Level::INFO, foo, bar., message,);
+ enabled!(Level::DEBUG, foo);
+
+ enabled!(Level::DEBUG);
+ enabled!(target: "rando", Level::DEBUG);
+ enabled!(target: "rando", Level::DEBUG, field);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span_enabled() {
+ span_enabled!(Level::DEBUG, foo, bar.baz, quux,);
+ span_enabled!(Level::DEBUG, message);
+ span_enabled!(Level::INFO, foo, bar.baz, quux, message,);
+ span_enabled!(Level::INFO, foo, bar., message,);
+ span_enabled!(Level::DEBUG, foo);
+
+ span_enabled!(Level::DEBUG);
+ span_enabled!(target: "rando", Level::DEBUG);
+ span_enabled!(target: "rando", Level::DEBUG, field);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event_enabled() {
+ event_enabled!(Level::DEBUG, foo, bar.baz, quux,);
+ event_enabled!(Level::DEBUG, message);
+ event_enabled!(Level::INFO, foo, bar.baz, quux, message,);
+ event_enabled!(Level::INFO, foo, bar., message,);
+ event_enabled!(Level::DEBUG, foo);
+
+ event_enabled!(Level::DEBUG);
+ event_enabled!(target: "rando", Level::DEBUG);
+ event_enabled!(target: "rando", Level::DEBUG, field);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn locals_with_message() {
+ let data = (42, "forty-two");
+ let private_data = "private";
+ let error = "a bad error";
+ event!(Level::ERROR, %error, "Received error");
+ event!(
+ target: "app_events",
+ Level::WARN,
+ private_data,
+ ?data,
+ "App warning: {}",
+ error
+ );
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn locals_no_message() {
+ let data = (42, "forty-two");
+ let private_data = "private";
+ let error = "a bad error";
+ event!(
+ target: "app_events",
+ Level::WARN,
+ private_data,
+ ?data,
+ );
+ event!(
+ target: "app_events",
+ Level::WARN,
+ private_data,
+ ?data,
+ error,
+ );
+ event!(
+ target: "app_events",
+ Level::WARN,
+ private_data,
+ ?data,
+ error
+ );
+ event!(Level::WARN, private_data, ?data, error,);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn trace() {
+ trace!(foo = ?3, bar.baz = %2, quux = false);
+ trace!(foo = 3, bar.baz = 2, quux = false);
+ trace!(foo = 3, bar.baz = 3,);
+ trace!("foo");
+ trace!("foo: {}", 3);
+ trace!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
+ trace!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
+ trace!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
+ trace!({ foo = 3, bar.baz = 80 }, "quux");
+ trace!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ trace!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ trace!({ foo = 2, bar.baz = 78 }, "quux");
+ trace!({ foo = ?2, bar.baz = %78 }, "quux");
+ trace!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
+ trace!(target: "foo_events", foo = 3, bar.baz = 3,);
+ trace!(target: "foo_events", "foo");
+ trace!(target: "foo_events", "foo: {}", 3);
+ trace!(target: "foo_events", { foo = 3, bar.baz = 80 }, "quux");
+ trace!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ trace!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ trace!(target: "foo_events", { foo = 2, bar.baz = 78, }, "quux");
+ let foo = 1;
+ trace!(?foo);
+ trace!(%foo);
+ trace!(foo);
+ trace!(target: "foo_events", ?foo);
+ trace!(target: "foo_events", %foo);
+ trace!(target: "foo_events", foo);
+ trace!(target: "foo_events", ?foo, true, "message");
+ trace!(target: "foo_events", %foo, true, "message");
+ trace!(target: "foo_events", foo, true, "message");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug() {
+ debug!(foo = ?3, bar.baz = %2, quux = false);
+ debug!(foo = 3, bar.baz = 2, quux = false);
+ debug!(foo = 3, bar.baz = 3,);
+ debug!("foo");
+ debug!("foo: {}", 3);
+ debug!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
+ debug!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
+ debug!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
+ debug!({ foo = 3, bar.baz = 80 }, "quux");
+ debug!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ debug!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ debug!({ foo = 2, bar.baz = 78 }, "quux");
+ debug!({ foo = ?2, bar.baz = %78 }, "quux");
+ debug!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
+ debug!(target: "foo_events", foo = 3, bar.baz = 3,);
+ debug!(target: "foo_events", "foo");
+ debug!(target: "foo_events", "foo: {}", 3);
+ debug!(target: "foo_events", { foo = 3, bar.baz = 80 }, "quux");
+ debug!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ debug!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ debug!(target: "foo_events", { foo = 2, bar.baz = 78, }, "quux");
+ let foo = 1;
+ debug!(?foo);
+ debug!(%foo);
+ debug!(foo);
+ debug!(target: "foo_events", ?foo);
+ debug!(target: "foo_events", %foo);
+ debug!(target: "foo_events", foo);
+ debug!(target: "foo_events", ?foo, true, "message");
+ debug!(target: "foo_events", %foo, true, "message");
+ debug!(target: "foo_events", foo, true, "message");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn info() {
+ info!(foo = ?3, bar.baz = %2, quux = false);
+ info!(foo = 3, bar.baz = 2, quux = false);
+ info!(foo = 3, bar.baz = 3,);
+ info!("foo");
+ info!("foo: {}", 3);
+ info!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
+ info!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
+ info!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
+ info!({ foo = 3, bar.baz = 80 }, "quux");
+ info!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ info!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ info!({ foo = 2, bar.baz = 78 }, "quux");
+ info!({ foo = ?2, bar.baz = %78 }, "quux");
+ info!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
+ info!(target: "foo_events", foo = 3, bar.baz = 3,);
+ info!(target: "foo_events", "foo");
+ info!(target: "foo_events", "foo: {}", 3);
+ info!(target: "foo_events", { foo = 3, bar.baz = 80 }, "quux");
+ info!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ info!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ info!(target: "foo_events", { foo = 2, bar.baz = 78, }, "quux");
+ let foo = 1;
+ info!(?foo);
+ info!(%foo);
+ info!(foo);
+ info!(target: "foo_events", ?foo);
+ info!(target: "foo_events", %foo);
+ info!(target: "foo_events", foo);
+ info!(target: "foo_events", ?foo, true, "message");
+ info!(target: "foo_events", %foo, true, "message");
+ info!(target: "foo_events", foo, true, "message");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn warn() {
+ warn!(foo = ?3, bar.baz = %2, quux = false);
+ warn!(foo = 3, bar.baz = 2, quux = false);
+ warn!(foo = 3, bar.baz = 3,);
+ warn!("foo");
+ warn!("foo: {}", 3);
+ warn!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
+ warn!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
+ warn!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
+ warn!({ foo = 3, bar.baz = 80 }, "quux");
+ warn!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ warn!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ warn!({ foo = 2, bar.baz = 78 }, "quux");
+ warn!({ foo = ?2, bar.baz = %78 }, "quux");
+ warn!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
+ warn!(target: "foo_events", foo = 3, bar.baz = 3,);
+ warn!(target: "foo_events", "foo");
+ warn!(target: "foo_events", "foo: {}", 3);
+ warn!(target: "foo_events", { foo = 3, bar.baz = 80 }, "quux");
+ warn!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ warn!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ warn!(target: "foo_events", { foo = 2, bar.baz = 78, }, "quux");
+ let foo = 1;
+ warn!(?foo);
+ warn!(%foo);
+ warn!(foo);
+ warn!(target: "foo_events", ?foo);
+ warn!(target: "foo_events", %foo);
+ warn!(target: "foo_events", foo);
+ warn!(target: "foo_events", ?foo, true, "message");
+ warn!(target: "foo_events", %foo, true, "message");
+ warn!(target: "foo_events", foo, true, "message");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn error() {
+ error!(foo = ?3, bar.baz = %2, quux = false);
+ error!(foo = 3, bar.baz = 2, quux = false);
+ error!(foo = 3, bar.baz = 3,);
+ error!("foo");
+ error!("foo: {}", 3);
+ error!(foo = ?3, bar.baz = %2, quux = false, "hello world {:?}", 42);
+ error!(foo = 3, bar.baz = 2, quux = false, "hello world {:?}", 42);
+ error!(foo = 3, bar.baz = 3, "hello world {:?}", 42,);
+ error!({ foo = 3, bar.baz = 80 }, "quux");
+ error!({ foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ error!({ foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ error!({ foo = 2, bar.baz = 78, }, "quux");
+ error!({ foo = ?2, bar.baz = %78 }, "quux");
+ error!(target: "foo_events", foo = 3, bar.baz = 2, quux = false);
+ error!(target: "foo_events", foo = 3, bar.baz = 3,);
+ error!(target: "foo_events", "foo");
+ error!(target: "foo_events", "foo: {}", 3);
+ error!(target: "foo_events", { foo = 3, bar.baz = 80 }, "quux");
+ error!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ error!(target: "foo_events", { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ error!(target: "foo_events", { foo = 2, bar.baz = 78, }, "quux");
+ let foo = 1;
+ error!(?foo);
+ error!(%foo);
+ error!(foo);
+ error!(target: "foo_events", ?foo);
+ error!(target: "foo_events", %foo);
+ error!(target: "foo_events", foo);
+ error!(target: "foo_events", ?foo, true, "message");
+ error!(target: "foo_events", %foo, true, "message");
+ error!(target: "foo_events", foo, true, "message");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event_root() {
+ event!(parent: None, Level::DEBUG, foo = ?3, bar.baz = %2, quux = false);
+ event!(
+ parent: None,
+ Level::DEBUG,
+ foo = 3,
+ bar.baz = 2,
+ quux = false
+ );
+ event!(parent: None, Level::DEBUG, foo = 3, bar.baz = 3,);
+ event!(parent: None, Level::DEBUG, "foo");
+ event!(parent: None, Level::DEBUG, "foo: {}", 3);
+ event!(parent: None, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+ event!(parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ event!(parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ event!(parent: None, Level::DEBUG, { foo = ?2, bar.baz = %78 }, "quux");
+ event!(target: "foo_events", parent: None, Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+ event!(target: "foo_events", parent: None, Level::DEBUG, foo = 3, bar.baz = 3,);
+ event!(target: "foo_events", parent: None, Level::DEBUG, "foo");
+ event!(target: "foo_events", parent: None, Level::DEBUG, "foo: {}", 3);
+ event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+ event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ event!(target: "foo_events", parent: None, Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn trace_root() {
+ trace!(parent: None, foo = ?3, bar.baz = %2, quux = false);
+ trace!(parent: None, foo = 3, bar.baz = 2, quux = false);
+ trace!(parent: None, foo = 3, bar.baz = 3,);
+ trace!(parent: None, "foo");
+ trace!(parent: None, "foo: {}", 3);
+ trace!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ trace!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ trace!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ trace!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
+ trace!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
+ trace!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
+ trace!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
+ trace!(target: "foo_events", parent: None, "foo");
+ trace!(target: "foo_events", parent: None, "foo: {}", 3);
+ trace!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ trace!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ trace!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ trace!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug_root() {
+ debug!(parent: None, foo = ?3, bar.baz = %2, quux = false);
+ debug!(parent: None, foo = 3, bar.baz = 2, quux = false);
+ debug!(parent: None, foo = 3, bar.baz = 3,);
+ debug!(parent: None, "foo");
+ debug!(parent: None, "foo: {}", 3);
+ debug!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ debug!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ debug!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ debug!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
+ debug!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
+ debug!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
+ debug!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
+ debug!(target: "foo_events", parent: None, "foo");
+ debug!(target: "foo_events", parent: None, "foo: {}", 3);
+ debug!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ debug!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ debug!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ debug!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn info_root() {
+ info!(parent: None, foo = ?3, bar.baz = %2, quux = false);
+ info!(parent: None, foo = 3, bar.baz = 2, quux = false);
+ info!(parent: None, foo = 3, bar.baz = 3,);
+ info!(parent: None, "foo");
+ info!(parent: None, "foo: {}", 3);
+ info!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ info!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ info!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ info!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
+ info!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
+ info!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
+ info!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
+ info!(target: "foo_events", parent: None, "foo");
+ info!(target: "foo_events", parent: None, "foo: {}", 3);
+ info!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ info!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ info!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ info!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn warn_root() {
+ warn!(parent: None, foo = ?3, bar.baz = %2, quux = false);
+ warn!(parent: None, foo = 3, bar.baz = 2, quux = false);
+ warn!(parent: None, foo = 3, bar.baz = 3,);
+ warn!(parent: None, "foo");
+ warn!(parent: None, "foo: {}", 3);
+ warn!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ warn!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ warn!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ warn!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
+ warn!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
+ warn!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
+ warn!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
+ warn!(target: "foo_events", parent: None, "foo");
+ warn!(target: "foo_events", parent: None, "foo: {}", 3);
+ warn!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ warn!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ warn!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ warn!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn error_root() {
+ error!(parent: None, foo = ?3, bar.baz = %2, quux = false);
+ error!(parent: None, foo = 3, bar.baz = 2, quux = false);
+ error!(parent: None, foo = 3, bar.baz = 3,);
+ error!(parent: None, "foo");
+ error!(parent: None, "foo: {}", 3);
+ error!(parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ error!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ error!(parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ error!(parent: None, { foo = 2, bar.baz = 78 }, "quux");
+ error!(parent: None, { foo = ?2, bar.baz = %78 }, "quux");
+ error!(target: "foo_events", parent: None, foo = 3, bar.baz = 2, quux = false);
+ error!(target: "foo_events", parent: None, foo = 3, bar.baz = 3,);
+ error!(target: "foo_events", parent: None, "foo");
+ error!(target: "foo_events", parent: None, "foo: {}", 3);
+ error!(target: "foo_events", parent: None, { foo = 3, bar.baz = 80 }, "quux");
+ error!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ error!(target: "foo_events", parent: None, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ error!(target: "foo_events", parent: None, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ event!(parent: &p, Level::DEBUG, foo = ?3, bar.baz = %2, quux = false);
+ event!(parent: &p, Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+ event!(parent: &p, Level::DEBUG, foo = 3, bar.baz = 3,);
+ event!(parent: &p, Level::DEBUG, "foo");
+ event!(parent: &p, Level::DEBUG, "foo: {}", 3);
+ event!(parent: &p, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+ event!(parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ event!(parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ event!(parent: &p, Level::DEBUG, { foo = ?2, bar.baz = %78 }, "quux");
+ event!(target: "foo_events", parent: &p, Level::DEBUG, foo = 3, bar.baz = 2, quux = false);
+ event!(target: "foo_events", parent: &p, Level::DEBUG, foo = 3, bar.baz = 3,);
+ event!(target: "foo_events", parent: &p, Level::DEBUG, "foo");
+ event!(target: "foo_events", parent: &p, Level::DEBUG, "foo: {}", 3);
+ event!(target: "foo_events", parent: &p, Level::DEBUG, { foo = 3, bar.baz = 80 }, "quux");
+ event!(target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ event!(target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ event!(target: "foo_events", parent: &p, Level::DEBUG, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn trace_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ trace!(parent: &p, foo = ?3, bar.baz = %2, quux = false);
+ trace!(parent: &p, foo = 3, bar.baz = 2, quux = false);
+ trace!(parent: &p, foo = 3, bar.baz = 3,);
+ trace!(parent: &p, "foo");
+ trace!(parent: &p, "foo: {}", 3);
+ trace!(parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ trace!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ trace!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ trace!(parent: &p, { foo = 2, bar.baz = 78 }, "quux");
+ trace!(parent: &p, { foo = ?2, bar.baz = %78 }, "quux");
+ trace!(target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+ trace!(target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+ trace!(target: "foo_events", parent: &p, "foo");
+ trace!(target: "foo_events", parent: &p, "foo: {}", 3);
+ trace!(target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ trace!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ trace!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ trace!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ debug!(parent: &p, foo = ?3, bar.baz = %2, quux = false);
+ debug!(parent: &p, foo = 3, bar.baz = 2, quux = false);
+ debug!(parent: &p, foo = 3, bar.baz = 3,);
+ debug!(parent: &p, "foo");
+ debug!(parent: &p, "foo: {}", 3);
+ debug!(parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ debug!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ debug!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ debug!(parent: &p, { foo = 2, bar.baz = 78 }, "quux");
+ debug!(parent: &p, { foo = ?2, bar.baz = %78 }, "quux");
+ debug!(target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+ debug!(target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+ debug!(target: "foo_events", parent: &p, "foo");
+ debug!(target: "foo_events", parent: &p, "foo: {}", 3);
+ debug!(target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ debug!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ debug!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ debug!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn info_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ info!(parent: &p, foo = ?3, bar.baz = %2, quux = false);
+ info!(parent: &p, foo = 3, bar.baz = 2, quux = false);
+ info!(parent: &p, foo = 3, bar.baz = 3,);
+ info!(parent: &p, "foo");
+ info!(parent: &p, "foo: {}", 3);
+ info!(parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ info!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ info!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ info!(parent: &p, { foo = 2, bar.baz = 78 }, "quux");
+ info!(parent: &p, { foo = ?2, bar.baz = %78 }, "quux");
+ info!(target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+ info!(target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+ info!(target: "foo_events", parent: &p, "foo");
+ info!(target: "foo_events", parent: &p, "foo: {}", 3);
+ info!(target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ info!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ info!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ info!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn warn_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ warn!(parent: &p, foo = ?3, bar.baz = %2, quux = false);
+ warn!(parent: &p, foo = 3, bar.baz = 2, quux = false);
+ warn!(parent: &p, foo = 3, bar.baz = 3,);
+ warn!(parent: &p, "foo");
+ warn!(parent: &p, "foo: {}", 3);
+ warn!(parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ warn!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ warn!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ warn!(parent: &p, { foo = 2, bar.baz = 78 }, "quux");
+ warn!(parent: &p, { foo = ?2, bar.baz = %78 }, "quux");
+ warn!(target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+ warn!(target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+ warn!(target: "foo_events", parent: &p, "foo");
+ warn!(target: "foo_events", parent: &p, "foo: {}", 3);
+ warn!(target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ warn!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ warn!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ warn!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn error_with_parent() {
+ let p = span!(Level::TRACE, "im_a_parent!");
+ error!(parent: &p, foo = ?3, bar.baz = %2, quux = false);
+ error!(parent: &p, foo = 3, bar.baz = 2, quux = false);
+ error!(parent: &p, foo = 3, bar.baz = 3,);
+ error!(parent: &p, "foo");
+ error!(parent: &p, "foo: {}", 3);
+ error!(parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ error!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ error!(parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ error!(parent: &p, { foo = 2, bar.baz = 78 }, "quux");
+ error!(parent: &p, { foo = ?2, bar.baz = %78 }, "quux");
+ error!(target: "foo_events", parent: &p, foo = 3, bar.baz = 2, quux = false);
+ error!(target: "foo_events", parent: &p, foo = 3, bar.baz = 3,);
+ error!(target: "foo_events", parent: &p, "foo");
+ error!(target: "foo_events", parent: &p, "foo: {}", 3);
+ error!(target: "foo_events", parent: &p, { foo = 3, bar.baz = 80 }, "quux");
+ error!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}", true);
+ error!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 79 }, "quux {:?}, {quux}", true, quux = false);
+ error!(target: "foo_events", parent: &p, { foo = 2, bar.baz = 78, }, "quux");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn field_shorthand_only() {
+ #[derive(Debug)]
+ struct Position {
+ x: f32,
+ y: f32,
+ }
+ let pos = Position {
+ x: 3.234,
+ y: -1.223,
+ };
+
+ trace!(?pos.x, ?pos.y);
+ debug!(?pos.x, ?pos.y);
+ info!(?pos.x, ?pos.y);
+ warn!(?pos.x, ?pos.y);
+ error!(?pos.x, ?pos.y);
+ event!(Level::TRACE, ?pos.x, ?pos.y);
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn borrow_val_events() {
+ // Reproduces https://github.com/tokio-rs/tracing/issues/954
+ let mut foo = (String::new(), String::new());
+ let zero = &mut foo.0;
+ trace!(one = ?foo.1);
+ debug!(one = ?foo.1);
+ info!(one = ?foo.1);
+ warn!(one = ?foo.1);
+ error!(one = ?foo.1);
+ zero.push_str("hello world");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn borrow_val_spans() {
+ // Reproduces https://github.com/tokio-rs/tracing/issues/954
+ let mut foo = (String::new(), String::new());
+ let zero = &mut foo.0;
+ let _span = trace_span!("span", one = ?foo.1);
+ let _span = debug_span!("span", one = ?foo.1);
+ let _span = info_span!("span", one = ?foo.1);
+ let _span = warn_span!("span", one = ?foo.1);
+ let _span = error_span!("span", one = ?foo.1);
+ zero.push_str("hello world");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn callsite_macro_api() {
+ // This test should catch any inadvertent breaking changes
+ // caused by changes to the macro.
+ let _callsite = callsite! {
+ name: "test callsite",
+ kind: tracing::metadata::Kind::EVENT,
+ target: "test target",
+ level: tracing::Level::TRACE,
+ fields: foo, bar,
+ };
+ let _callsite = callsite! {
+ name: "test callsite",
+ kind: tracing::metadata::Kind::SPAN,
+ level: tracing::Level::TRACE,
+ fields: foo,
+ };
+ let _callsite = callsite! {
+ name: "test callsite",
+ kind: tracing::metadata::Kind::SPAN,
+ fields: foo,
+ };
+}
diff --git a/third_party/rust/tracing/tests/macros_incompatible_concat.rs b/third_party/rust/tracing/tests/macros_incompatible_concat.rs
new file mode 100644
index 0000000000..bda6b964fa
--- /dev/null
+++ b/third_party/rust/tracing/tests/macros_incompatible_concat.rs
@@ -0,0 +1,24 @@
+use tracing::{enabled, event, span, Level};
+
+#[macro_export]
+macro_rules! concat {
+ () => {};
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span() {
+ span!(Level::DEBUG, "foo");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event() {
+ event!(Level::DEBUG, "foo");
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn enabled() {
+ enabled!(Level::DEBUG);
+}
diff --git a/third_party/rust/tracing/tests/macros_redefined_core.rs b/third_party/rust/tracing/tests/macros_redefined_core.rs
new file mode 100644
index 0000000000..d830dcdb02
--- /dev/null
+++ b/third_party/rust/tracing/tests/macros_redefined_core.rs
@@ -0,0 +1,18 @@
+extern crate self as core;
+
+use tracing::{enabled, event, span, Level};
+
+#[test]
+fn span() {
+ span!(Level::DEBUG, "foo");
+}
+
+#[test]
+fn event() {
+ event!(Level::DEBUG, "foo");
+}
+
+#[test]
+fn enabled() {
+ enabled!(Level::DEBUG);
+}
diff --git a/third_party/rust/tracing/tests/max_level_hint.rs b/third_party/rust/tracing/tests/max_level_hint.rs
new file mode 100644
index 0000000000..63d3af6357
--- /dev/null
+++ b/third_party/rust/tracing/tests/max_level_hint.rs
@@ -0,0 +1,37 @@
+use tracing::Level;
+use tracing_mock::*;
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn max_level_hints() {
+ // This test asserts that when a subscriber provides us with the global
+ // maximum level that it will enable (by implementing the
+ // `Subscriber::max_level_hint` method), we will never call
+ // `Subscriber::enabled` for events above that maximum level.
+ //
+ // In this case, we test that by making the `enabled` method assert that no
+ // `Metadata` for spans or events at the `TRACE` or `DEBUG` levels.
+ let (subscriber, handle) = subscriber::mock()
+ .with_max_level_hint(Level::INFO)
+ .with_filter(|meta| {
+ assert!(
+ dbg!(meta).level() <= &Level::INFO,
+ "a TRACE or DEBUG event was dynamically filtered: "
+ );
+ true
+ })
+ .event(event::mock().at_level(Level::INFO))
+ .event(event::mock().at_level(Level::WARN))
+ .event(event::mock().at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+
+ tracing::subscriber::set_global_default(subscriber).unwrap();
+
+ tracing::info!("doing a thing that you might care about");
+ tracing::debug!("charging turboencabulator with interocitor");
+ tracing::warn!("extremely serious warning, pay attention");
+ tracing::trace!("interocitor charge level is 10%");
+ tracing::error!("everything is on fire");
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/multiple_max_level_hints.rs b/third_party/rust/tracing/tests/multiple_max_level_hints.rs
new file mode 100644
index 0000000000..dd50a193b5
--- /dev/null
+++ b/third_party/rust/tracing/tests/multiple_max_level_hints.rs
@@ -0,0 +1,69 @@
+#![cfg(feature = "std")]
+
+use tracing::Level;
+use tracing_mock::*;
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn multiple_max_level_hints() {
+ // This test ensures that when multiple subscribers are active, their max
+ // level hints are handled correctly. The global max level should be the
+ // maximum of the level filters returned by the two `Subscriber`'s
+ // `max_level_hint` method.
+ //
+ // In this test, we create a subscriber whose max level is `INFO`, and
+ // another whose max level is `DEBUG`. We then add an assertion to both of
+ // those subscribers' `enabled` method that no metadata for `TRACE` spans or
+ // events are filtered, since they are disabled by the global max filter.
+
+ fn do_events() {
+ tracing::info!("doing a thing that you might care about");
+ tracing::debug!("charging turboencabulator with interocitor");
+ tracing::warn!("extremely serious warning, pay attention");
+ tracing::trace!("interocitor charge level is 10%");
+ tracing::error!("everything is on fire");
+ }
+
+ let (subscriber1, handle1) = subscriber::mock()
+ .named("subscriber1")
+ .with_max_level_hint(Level::INFO)
+ .with_filter(|meta| {
+ let level = dbg!(meta.level());
+ assert!(
+ level <= &Level::DEBUG,
+ "a TRACE event was dynamically filtered by subscriber1"
+ );
+ level <= &Level::INFO
+ })
+ .event(event::mock().at_level(Level::INFO))
+ .event(event::mock().at_level(Level::WARN))
+ .event(event::mock().at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+ let (subscriber2, handle2) = subscriber::mock()
+ .named("subscriber2")
+ .with_max_level_hint(Level::DEBUG)
+ .with_filter(|meta| {
+ let level = dbg!(meta.level());
+ assert!(
+ level <= &Level::DEBUG,
+ "a TRACE event was dynamically filtered by subscriber2"
+ );
+ level <= &Level::DEBUG
+ })
+ .event(event::mock().at_level(Level::INFO))
+ .event(event::mock().at_level(Level::DEBUG))
+ .event(event::mock().at_level(Level::WARN))
+ .event(event::mock().at_level(Level::ERROR))
+ .done()
+ .run_with_handle();
+
+ let dispatch1 = tracing::Dispatch::new(subscriber1);
+
+ tracing::dispatcher::with_default(&dispatch1, do_events);
+ handle1.assert_finished();
+
+ let dispatch2 = tracing::Dispatch::new(subscriber2);
+ tracing::dispatcher::with_default(&dispatch2, do_events);
+ handle2.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/no_subscriber.rs b/third_party/rust/tracing/tests/no_subscriber.rs
new file mode 100644
index 0000000000..5f927c1dee
--- /dev/null
+++ b/third_party/rust/tracing/tests/no_subscriber.rs
@@ -0,0 +1,15 @@
+#![cfg(feature = "std")]
+
+use tracing::subscriber::{self, NoSubscriber};
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn no_subscriber_disables_global() {
+ // Reproduces https://github.com/tokio-rs/tracing/issues/1999
+ let (subscriber, handle) = tracing_mock::subscriber::mock().done().run_with_handle();
+ subscriber::set_global_default(subscriber).expect("setting global default must succeed");
+ subscriber::with_default(NoSubscriber::default(), || {
+ tracing::info!("this should not be recorded");
+ });
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/register_callsite_deadlock.rs b/third_party/rust/tracing/tests/register_callsite_deadlock.rs
new file mode 100644
index 0000000000..e4c116c75f
--- /dev/null
+++ b/third_party/rust/tracing/tests/register_callsite_deadlock.rs
@@ -0,0 +1,47 @@
+use std::{sync::mpsc, thread, time::Duration};
+use tracing::{
+ metadata::Metadata,
+ span,
+ subscriber::{self, Interest, Subscriber},
+ Event,
+};
+
+#[test]
+fn register_callsite_doesnt_deadlock() {
+ pub struct EvilSubscriber;
+
+ impl Subscriber for EvilSubscriber {
+ fn register_callsite(&self, meta: &'static Metadata<'static>) -> Interest {
+ tracing::info!(?meta, "registered a callsite");
+ Interest::always()
+ }
+
+ fn enabled(&self, _: &Metadata<'_>) -> bool {
+ true
+ }
+ fn new_span(&self, _: &span::Attributes<'_>) -> span::Id {
+ span::Id::from_u64(1)
+ }
+ fn record(&self, _: &span::Id, _: &span::Record<'_>) {}
+ fn record_follows_from(&self, _: &span::Id, _: &span::Id) {}
+ fn event(&self, _: &Event<'_>) {}
+ fn enter(&self, _: &span::Id) {}
+ fn exit(&self, _: &span::Id) {}
+ }
+
+ subscriber::set_global_default(EvilSubscriber).unwrap();
+
+ // spawn a thread, and assert it doesn't hang...
+ let (tx, didnt_hang) = mpsc::channel();
+ let th = thread::spawn(move || {
+ tracing::info!("hello world!");
+ tx.send(()).unwrap();
+ });
+
+ didnt_hang
+ // Note: 60 seconds is *way* more than enough, but let's be generous in
+ // case of e.g. slow CI machines.
+ .recv_timeout(Duration::from_secs(60))
+ .expect("the thread must not have hung!");
+ th.join().expect("thread should join successfully");
+}
diff --git a/third_party/rust/tracing/tests/scoped_clobbers_default.rs b/third_party/rust/tracing/tests/scoped_clobbers_default.rs
new file mode 100644
index 0000000000..362d34a82c
--- /dev/null
+++ b/third_party/rust/tracing/tests/scoped_clobbers_default.rs
@@ -0,0 +1,35 @@
+#![cfg(feature = "std")]
+use tracing_mock::*;
+
+#[test]
+fn scoped_clobbers_global() {
+ // Reproduces https://github.com/tokio-rs/tracing/issues/2050
+
+ let (scoped, scoped_handle) = subscriber::mock()
+ .event(event::msg("before global"))
+ .event(event::msg("before drop"))
+ .done()
+ .run_with_handle();
+
+ let (global, global_handle) = subscriber::mock()
+ .event(event::msg("after drop"))
+ .done()
+ .run_with_handle();
+
+ // Set a scoped default subscriber, returning a guard.
+ let guard = tracing::subscriber::set_default(scoped);
+ tracing::info!("before global");
+
+ // Now, set the global default.
+ tracing::subscriber::set_global_default(global)
+ .expect("global default should not already be set");
+ // This event should still be collected by the scoped default.
+ tracing::info!("before drop");
+
+ // Drop the guard. Now, the global default subscriber should be used.
+ drop(guard);
+ tracing::info!("after drop");
+
+ scoped_handle.assert_finished();
+ global_handle.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/span.rs b/third_party/rust/tracing/tests/span.rs
new file mode 100644
index 0000000000..4ed6500235
--- /dev/null
+++ b/third_party/rust/tracing/tests/span.rs
@@ -0,0 +1,825 @@
+// These tests require the thread-local scoped dispatcher, which only works when
+// we have a standard library. The behaviour being tested should be the same
+// with the standard lib disabled.
+#![cfg(feature = "std")]
+
+use std::thread;
+
+use tracing::{
+ field::{debug, display},
+ subscriber::with_default,
+ Level, Span,
+};
+use tracing_mock::*;
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn handles_to_the_same_span_are_equal() {
+ // Create a mock subscriber that will return `true` on calls to
+ // `Subscriber::enabled`, so that the spans will be constructed. We
+ // won't enter any spans in this test, so the subscriber won't actually
+ // expect to see any spans.
+ with_default(subscriber::mock().run(), || {
+ let foo1 = tracing::span!(Level::TRACE, "foo");
+ let foo2 = foo1.clone();
+ // Two handles that point to the same span are equal.
+ assert_eq!(foo1, foo2);
+ });
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn handles_to_different_spans_are_not_equal() {
+ with_default(subscriber::mock().run(), || {
+ // Even though these spans have the same name and fields, they will have
+ // differing metadata, since they were created on different lines.
+ let foo1 = tracing::span!(Level::TRACE, "foo", bar = 1u64, baz = false);
+ let foo2 = tracing::span!(Level::TRACE, "foo", bar = 1u64, baz = false);
+
+ assert_ne!(foo1, foo2);
+ });
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn handles_to_different_spans_with_the_same_metadata_are_not_equal() {
+ // Every time time this function is called, it will return a _new
+ // instance_ of a span with the same metadata, name, and fields.
+ fn make_span() -> Span {
+ tracing::span!(Level::TRACE, "foo", bar = 1u64, baz = false)
+ }
+
+ with_default(subscriber::mock().run(), || {
+ let foo1 = make_span();
+ let foo2 = make_span();
+
+ assert_ne!(foo1, foo2);
+ // assert_ne!(foo1.data(), foo2.data());
+ });
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn spans_always_go_to_the_subscriber_that_tagged_them() {
+ let subscriber1 = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run();
+ let subscriber2 = subscriber::mock().run();
+
+ let foo = with_default(subscriber1, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ foo.in_scope(|| {});
+ foo
+ });
+ // Even though we enter subscriber 2's context, the subscriber that
+ // tagged the span should see the enter/exit.
+ with_default(subscriber2, move || foo.in_scope(|| {}));
+}
+
+// This gets exempt from testing in wasm because of: `thread::spawn` which is
+// not yet possible to do in WASM. There is work going on see:
+// <https://rustwasm.github.io/2018/10/24/multithreading-rust-and-wasm.html>
+//
+// But for now since it's not possible we don't need to test for it :)
+#[test]
+fn spans_always_go_to_the_subscriber_that_tagged_them_even_across_threads() {
+ let subscriber1 = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run();
+ let foo = with_default(subscriber1, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ foo.in_scope(|| {});
+ foo
+ });
+
+ // Even though we enter subscriber 2's context, the subscriber that
+ // tagged the span should see the enter/exit.
+ thread::spawn(move || {
+ with_default(subscriber::mock().run(), || {
+ foo.in_scope(|| {});
+ })
+ })
+ .join()
+ .unwrap();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn dropping_a_span_calls_drop_span() {
+ let (subscriber, handle) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo");
+ span.in_scope(|| {});
+ drop(span);
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span_closes_after_event() {
+ let (subscriber, handle) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .event(event::mock())
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "foo").in_scope(|| {
+ tracing::event!(Level::DEBUG, {}, "my tracing::event!");
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn new_span_after_event() {
+ let (subscriber, handle) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .event(event::mock())
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .enter(span::mock().named("bar"))
+ .exit(span::mock().named("bar"))
+ .drop_span(span::mock().named("bar"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "foo").in_scope(|| {
+ tracing::event!(Level::DEBUG, {}, "my tracing::event!");
+ });
+ tracing::span!(Level::TRACE, "bar").in_scope(|| {});
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event_outside_of_span() {
+ let (subscriber, handle) = subscriber::mock()
+ .event(event::mock())
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::debug!("my tracing::event!");
+ tracing::span!(Level::TRACE, "foo").in_scope(|| {});
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn cloning_a_span_calls_clone_span() {
+ let (subscriber, handle) = subscriber::mock()
+ .clone_span(span::mock().named("foo"))
+ .run_with_handle();
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo");
+ // Allow the "redundant" `.clone` since it is used to call into the `.clone_span` hook.
+ #[allow(clippy::redundant_clone)]
+ let _span2 = span.clone();
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn drop_span_when_exiting_dispatchers_context() {
+ let (subscriber, handle) = subscriber::mock()
+ .clone_span(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .run_with_handle();
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo");
+ let _span2 = span.clone();
+ drop(span);
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn clone_and_drop_span_always_go_to_the_subscriber_that_tagged_the_span() {
+ let (subscriber1, handle1) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .clone_span(span::mock().named("foo"))
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .run_with_handle();
+ let subscriber2 = subscriber::mock().done().run();
+
+ let foo = with_default(subscriber1, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ foo.in_scope(|| {});
+ foo
+ });
+ // Even though we enter subscriber 2's context, the subscriber that
+ // tagged the span should see the enter/exit.
+ with_default(subscriber2, move || {
+ let foo2 = foo.clone();
+ foo.in_scope(|| {});
+ drop(foo);
+ drop(foo2);
+ });
+
+ handle1.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn span_closes_when_exited() {
+ let (subscriber, handle) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+
+ foo.in_scope(|| {});
+
+ drop(foo);
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn enter() {
+ let (subscriber, handle) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .event(event::mock())
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ let _enter = foo.enter();
+ tracing::debug!("dropping guard...");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn entered() {
+ let (subscriber, handle) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .event(event::mock())
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let _span = tracing::span!(Level::TRACE, "foo").entered();
+ tracing::debug!("dropping guard...");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn entered_api() {
+ let (subscriber, handle) = subscriber::mock()
+ .enter(span::mock().named("foo"))
+ .event(event::mock())
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo").entered();
+ let _derefs_to_span = span.id();
+ tracing::debug!("exiting span...");
+ let _: Span = span.exit();
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn moved_field() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("bar")
+ .with_value(&display("hello from my span"))
+ .only(),
+ ),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ let from = "my span";
+ let span = tracing::span!(
+ Level::TRACE,
+ "foo",
+ bar = display(format!("hello from {}", from))
+ );
+ span.in_scope(|| {});
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn dotted_field_name() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock()
+ .named("foo")
+ .with_field(field::mock("fields.bar").with_value(&true).only()),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "foo", fields.bar = true);
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn borrowed_field() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("bar")
+ .with_value(&display("hello from my span"))
+ .only(),
+ ),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let from = "my span";
+ let mut message = format!("hello from {}", from);
+ let span = tracing::span!(Level::TRACE, "foo", bar = display(&message));
+ span.in_scope(|| {
+ message.insert_str(10, " inside");
+ });
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+// If emitting log instrumentation, this gets moved anyway, breaking the test.
+#[cfg(not(feature = "log"))]
+fn move_field_out_of_struct() {
+ use tracing::field::debug;
+
+ #[derive(Debug)]
+ struct Position {
+ x: f32,
+ y: f32,
+ }
+
+ let pos = Position {
+ x: 3.234,
+ y: -1.223,
+ };
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("x")
+ .with_value(&debug(3.234))
+ .and(field::mock("y").with_value(&debug(-1.223)))
+ .only(),
+ ),
+ )
+ .new_span(
+ span::mock()
+ .named("bar")
+ .with_field(field::mock("position").with_value(&debug(&pos)).only()),
+ )
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let pos = Position {
+ x: 3.234,
+ y: -1.223,
+ };
+ let foo = tracing::span!(Level::TRACE, "foo", x = debug(pos.x), y = debug(pos.y));
+ let bar = tracing::span!(Level::TRACE, "bar", position = debug(pos));
+ foo.in_scope(|| {});
+ bar.in_scope(|| {});
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn float_values() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("x")
+ .with_value(&3.234)
+ .and(field::mock("y").with_value(&-1.223))
+ .only(),
+ ),
+ )
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo", x = 3.234, y = -1.223);
+ foo.in_scope(|| {});
+ });
+
+ handle.assert_finished();
+}
+
+// TODO(#1138): determine a new syntax for uninitialized span fields, and
+// re-enable these.
+/*
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn add_field_after_new_span() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock()
+ .named("foo")
+ .with_field(field::mock("bar").with_value(&5)
+ .and(field::mock("baz").with_value).only()),
+ )
+ .record(
+ span::mock().named("foo"),
+ field::mock("baz").with_value(&true).only(),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo", bar = 5, baz = false);
+ span.record("baz", &true);
+ span.in_scope(|| {})
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn add_fields_only_after_new_span() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .record(
+ span::mock().named("foo"),
+ field::mock("bar").with_value(&5).only(),
+ )
+ .record(
+ span::mock().named("foo"),
+ field::mock("baz").with_value(&true).only(),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo", bar = _, baz = _);
+ span.record("bar", &5);
+ span.record("baz", &true);
+ span.in_scope(|| {})
+ });
+
+ handle.assert_finished();
+}
+*/
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn record_new_value_for_field() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("bar")
+ .with_value(&5)
+ .and(field::mock("baz").with_value(&false))
+ .only(),
+ ),
+ )
+ .record(
+ span::mock().named("foo"),
+ field::mock("baz").with_value(&true).only(),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo", bar = 5, baz = false);
+ span.record("baz", &true);
+ span.in_scope(|| {})
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn record_new_values_for_fields() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("bar")
+ .with_value(&4)
+ .and(field::mock("baz").with_value(&false))
+ .only(),
+ ),
+ )
+ .record(
+ span::mock().named("foo"),
+ field::mock("bar").with_value(&5).only(),
+ )
+ .record(
+ span::mock().named("foo"),
+ field::mock("baz").with_value(&true).only(),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let span = tracing::span!(Level::TRACE, "foo", bar = 4, baz = false);
+ span.record("bar", &5);
+ span.record("baz", &true);
+ span.in_scope(|| {})
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn new_span_with_target_and_log_level() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock()
+ .named("foo")
+ .with_target("app_span")
+ .at_level(Level::DEBUG),
+ )
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::span!(target: "app_span", Level::DEBUG, "foo");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn explicit_root_span_is_root() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo").with_explicit_parent(None))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::span!(parent: None, Level::TRACE, "foo");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn explicit_root_span_is_root_regardless_of_ctx() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .enter(span::mock().named("foo"))
+ .new_span(span::mock().named("bar").with_explicit_parent(None))
+ .exit(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "foo").in_scope(|| {
+ tracing::span!(parent: None, Level::TRACE, "bar");
+ })
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn explicit_child() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .new_span(span::mock().named("bar").with_explicit_parent(Some("foo")))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ tracing::span!(parent: foo.id(), Level::TRACE, "bar");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn explicit_child_at_levels() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .new_span(span::mock().named("a").with_explicit_parent(Some("foo")))
+ .new_span(span::mock().named("b").with_explicit_parent(Some("foo")))
+ .new_span(span::mock().named("c").with_explicit_parent(Some("foo")))
+ .new_span(span::mock().named("d").with_explicit_parent(Some("foo")))
+ .new_span(span::mock().named("e").with_explicit_parent(Some("foo")))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ tracing::trace_span!(parent: foo.id(), "a");
+ tracing::debug_span!(parent: foo.id(), "b");
+ tracing::info_span!(parent: foo.id(), "c");
+ tracing::warn_span!(parent: foo.id(), "d");
+ tracing::error_span!(parent: foo.id(), "e");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn explicit_child_regardless_of_ctx() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .new_span(span::mock().named("bar"))
+ .enter(span::mock().named("bar"))
+ .new_span(span::mock().named("baz").with_explicit_parent(Some("foo")))
+ .exit(span::mock().named("bar"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ let foo = tracing::span!(Level::TRACE, "foo");
+ tracing::span!(Level::TRACE, "bar")
+ .in_scope(|| tracing::span!(parent: foo.id(), Level::TRACE, "baz"))
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn contextual_root() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo").with_contextual_parent(None))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "foo");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn contextual_child() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(span::mock().named("foo"))
+ .enter(span::mock().named("foo"))
+ .new_span(
+ span::mock()
+ .named("bar")
+ .with_contextual_parent(Some("foo")),
+ )
+ .exit(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "foo").in_scope(|| {
+ tracing::span!(Level::TRACE, "bar");
+ })
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn display_shorthand() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("my_span").with_field(
+ field::mock("my_field")
+ .with_value(&display("hello world"))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "my_span", my_field = %"hello world");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn debug_shorthand() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("my_span").with_field(
+ field::mock("my_field")
+ .with_value(&debug("hello world"))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "my_span", my_field = ?"hello world");
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn both_shorthands() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("my_span").with_field(
+ field::mock("display_field")
+ .with_value(&display("hello world"))
+ .and(field::mock("debug_field").with_value(&debug("hello world")))
+ .only(),
+ ),
+ )
+ .done()
+ .run_with_handle();
+ with_default(subscriber, || {
+ tracing::span!(Level::TRACE, "my_span", display_field = %"hello world", debug_field = ?"hello world");
+ });
+
+ handle.assert_finished();
+}
diff --git a/third_party/rust/tracing/tests/subscriber.rs b/third_party/rust/tracing/tests/subscriber.rs
new file mode 100644
index 0000000000..15557c107f
--- /dev/null
+++ b/third_party/rust/tracing/tests/subscriber.rs
@@ -0,0 +1,130 @@
+// These tests require the thread-local scoped dispatcher, which only works when
+// we have a standard library. The behaviour being tested should be the same
+// with the standard lib disabled.
+//
+// The alternative would be for each of these tests to be defined in a separate
+// file, which is :(
+#![cfg(feature = "std")]
+use tracing::{
+ field::display,
+ span::{Attributes, Id, Record},
+ subscriber::{with_default, Interest, Subscriber},
+ Event, Level, Metadata,
+};
+
+use tracing_mock::*;
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn event_macros_dont_infinite_loop() {
+ // This test ensures that an event macro within a subscriber
+ // won't cause an infinite loop of events.
+ struct TestSubscriber;
+ impl Subscriber for TestSubscriber {
+ fn register_callsite(&self, _: &Metadata<'_>) -> Interest {
+ // Always return sometimes so that `enabled` will be called
+ // (which can loop).
+ Interest::sometimes()
+ }
+
+ fn enabled(&self, meta: &Metadata<'_>) -> bool {
+ assert!(meta.fields().iter().any(|f| f.name() == "foo"));
+ tracing::event!(Level::TRACE, bar = false);
+ true
+ }
+
+ fn new_span(&self, _: &Attributes<'_>) -> Id {
+ Id::from_u64(0xAAAA)
+ }
+
+ fn record(&self, _: &Id, _: &Record<'_>) {}
+
+ fn record_follows_from(&self, _: &Id, _: &Id) {}
+
+ fn event(&self, event: &Event<'_>) {
+ assert!(event.metadata().fields().iter().any(|f| f.name() == "foo"));
+ tracing::event!(Level::TRACE, baz = false);
+ }
+
+ fn enter(&self, _: &Id) {}
+
+ fn exit(&self, _: &Id) {}
+ }
+
+ with_default(TestSubscriber, || {
+ tracing::event!(Level::TRACE, foo = false);
+ })
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn boxed_subscriber() {
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("bar")
+ .with_value(&display("hello from my span"))
+ .only(),
+ ),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .done()
+ .run_with_handle();
+ let subscriber: Box<dyn Subscriber + Send + Sync + 'static> = Box::new(subscriber);
+
+ with_default(subscriber, || {
+ let from = "my span";
+ let span = tracing::span!(
+ Level::TRACE,
+ "foo",
+ bar = format_args!("hello from {}", from)
+ );
+ span.in_scope(|| {});
+ });
+
+ handle.assert_finished();
+}
+
+#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
+#[test]
+fn arced_subscriber() {
+ use std::sync::Arc;
+
+ let (subscriber, handle) = subscriber::mock()
+ .new_span(
+ span::mock().named("foo").with_field(
+ field::mock("bar")
+ .with_value(&display("hello from my span"))
+ .only(),
+ ),
+ )
+ .enter(span::mock().named("foo"))
+ .exit(span::mock().named("foo"))
+ .drop_span(span::mock().named("foo"))
+ .event(
+ event::mock()
+ .with_fields(field::mock("message").with_value(&display("hello from my event"))),
+ )
+ .done()
+ .run_with_handle();
+ let subscriber: Arc<dyn Subscriber + Send + Sync + 'static> = Arc::new(subscriber);
+
+ // Test using a clone of the `Arc`ed subscriber
+ with_default(subscriber.clone(), || {
+ let from = "my span";
+ let span = tracing::span!(
+ Level::TRACE,
+ "foo",
+ bar = format_args!("hello from {}", from)
+ );
+ span.in_scope(|| {});
+ });
+
+ with_default(subscriber, || {
+ tracing::info!("hello from my event");
+ });
+
+ handle.assert_finished();
+}