aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFedor Tsarev <ftsarev@google.com>2023-03-27 07:07:02 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2023-03-27 07:07:02 +0000
commitaf68fcf57e73943ec9ef2c832681f20bc08cfeb2 (patch)
tree5fc512f186c4de22ed6d8172488edcd3ad988202
parent235dea6c72589e45f08bef8325fa490b3312de49 (diff)
parentbaab3d8cbdcc5894eb7d5dff17fe5ed528c4ebd7 (diff)
downloadtracing-core-af68fcf57e73943ec9ef2c832681f20bc08cfeb2.tar.gz
Import crate tracing-core am: baab3d8cbd
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/tracing-core/+/2507476 Change-Id: I7baf0428f4a38447af3f10d1f609f4fd8d34210f Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r--CHANGELOG.md495
-rw-r--r--Cargo.toml66
-rw-r--r--Cargo.toml.orig48
-rw-r--r--LICENSE25
-rw-r--r--METADATA19
-rw-r--r--MODULE_LICENSE_MIT0
-rw-r--r--OWNERS1
-rw-r--r--README.md121
-rw-r--r--src/callsite.rs621
-rw-r--r--src/dispatcher.rs1008
-rw-r--r--src/event.rs128
-rw-r--r--src/field.rs1263
-rw-r--r--src/lazy.rs76
-rw-r--r--src/lib.rs295
-rw-r--r--src/metadata.rs1114
-rw-r--r--src/parent.rs11
-rw-r--r--src/span.rs341
-rw-r--r--src/spin/LICENSE21
-rw-r--r--src/spin/mod.rs7
-rw-r--r--src/spin/mutex.rs118
-rw-r--r--src/spin/once.rs158
-rw-r--r--src/stdlib.rs78
-rw-r--r--src/subscriber.rs870
-rw-r--r--tests/common/mod.rs30
-rw-r--r--tests/dispatch.rs56
-rw-r--r--tests/global_dispatch.rs34
-rw-r--r--tests/macros.rs48
27 files changed, 7052 insertions, 0 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..cf0d8e3
--- /dev/null
+++ b/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/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..8060061
--- /dev/null
+++ b/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/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..aacd334
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,48 @@
+[package]
+name = "tracing-core"
+# When releasing to crates.io:
+# - Remove path dependencies
+# - Update html_root_url.
+# - Update doc url
+# - Cargo.toml
+# - README.md
+# - Update CHANGELOG.md.
+# - Create "v0.1.x" git tag.
+version = "0.1.30"
+authors = ["Tokio Contributors <team@tokio.rs>"]
+license = "MIT"
+readme = "README.md"
+repository = "https://github.com/tokio-rs/tracing"
+homepage = "https://tokio.rs"
+description = """
+Core primitives for application-level tracing.
+"""
+categories = [
+ "development-tools::debugging",
+ "development-tools::profiling",
+ "asynchronous",
+]
+keywords = ["logging", "tracing", "profiling"]
+edition = "2018"
+rust-version = "1.49.0"
+
+[features]
+default = ["std", "valuable/std"]
+std = ["once_cell"]
+
+[badges]
+maintenance = { status = "actively-developed" }
+
+[dependencies]
+once_cell = { version = "1.13.0", optional = true }
+
+[target.'cfg(tracing_unstable)'.dependencies]
+valuable = { version = "0.1.0", optional = true, default-features = false }
+
+[package.metadata.docs.rs]
+all-features = true
+# enable unstable features in the documentation
+rustdoc-args = ["--cfg", "docsrs", "--cfg", "tracing_unstable"]
+# it's necessary to _also_ pass `--cfg tracing_unstable` to rustc, or else
+# dependencies will not be enabled, and the docs build will fail.
+rustc-args = ["--cfg", "tracing_unstable"]
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..cdb28b4
--- /dev/null
+++ b/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/METADATA b/METADATA
new file mode 100644
index 0000000..374df14
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "tracing-core"
+description: "Core primitives for application-level tracing."
+third_party {
+ url {
+ type: HOMEPAGE
+ value: "https://crates.io/crates/tracing-core"
+ }
+ url {
+ type: ARCHIVE
+ value: "https://static.crates.io/crates/tracing-core/tracing-core-0.1.30.crate"
+ }
+ version: "0.1.30"
+ license_type: NOTICE
+ last_upgrade_date {
+ year: 2023
+ month: 3
+ day: 3
+ }
+}
diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_MIT
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..45dc4dd
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:master:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f06c760
--- /dev/null
+++ b/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/src/callsite.rs b/src/callsite.rs
new file mode 100644
index 0000000..f887132
--- /dev/null
+++ b/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/src/dispatcher.rs b/src/dispatcher.rs
new file mode 100644
index 0000000..36b3cfd
--- /dev/null
+++ b/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/src/event.rs b/src/event.rs
new file mode 100644
index 0000000..6e25437
--- /dev/null
+++ b/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/src/field.rs b/src/field.rs
new file mode 100644
index 0000000..e103c75
--- /dev/null
+++ b/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/src/lazy.rs b/src/lazy.rs
new file mode 100644
index 0000000..4f004e6
--- /dev/null
+++ b/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/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..c1f87b2
--- /dev/null
+++ b/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/src/metadata.rs b/src/metadata.rs
new file mode 100644
index 0000000..a154419
--- /dev/null
+++ b/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/src/parent.rs b/src/parent.rs
new file mode 100644
index 0000000..cb34b37
--- /dev/null
+++ b/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/src/span.rs b/src/span.rs
new file mode 100644
index 0000000..44738b2
--- /dev/null
+++ b/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/src/spin/LICENSE b/src/spin/LICENSE
new file mode 100644
index 0000000..84d5f4d
--- /dev/null
+++ b/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/src/spin/mod.rs b/src/spin/mod.rs
new file mode 100644
index 0000000..148b192
--- /dev/null
+++ b/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/src/spin/mutex.rs b/src/spin/mutex.rs
new file mode 100644
index 0000000..c261a61
--- /dev/null
+++ b/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/src/spin/once.rs b/src/spin/once.rs
new file mode 100644
index 0000000..27c99e5
--- /dev/null
+++ b/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/src/stdlib.rs b/src/stdlib.rs
new file mode 100644
index 0000000..7415495
--- /dev/null
+++ b/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/src/subscriber.rs b/src/subscriber.rs
new file mode 100644
index 0000000..e8f4441
--- /dev/null
+++ b/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/tests/common/mod.rs b/tests/common/mod.rs
new file mode 100644
index 0000000..3420f0b
--- /dev/null
+++ b/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/tests/dispatch.rs b/tests/dispatch.rs
new file mode 100644
index 0000000..3820692
--- /dev/null
+++ b/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/tests/global_dispatch.rs b/tests/global_dispatch.rs
new file mode 100644
index 0000000..d430ac6
--- /dev/null
+++ b/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/tests/macros.rs b/tests/macros.rs
new file mode 100644
index 0000000..ee9007e
--- /dev/null
+++ b/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
+ };
+}