tracing-core-0.1.32/.cargo_vcs_info.json0000644000000001520000000000100134720ustar { "git": { "sha1": "c4b2a56937dd40aaa2e2991636eca6748353201f" }, "path_in_vcs": "tracing-core" }tracing-core-0.1.32/CHANGELOG.md000064400000000000000000000407071046102023000141050ustar 00000000000000# 0.1.32 (October 13, 2023) ### Documented - Fix typo in `field` docs ([#2611]) - Remove duplicate wording ([#2674]) ### Changed - Allow `ValueSet`s of any length ([#2508]) [#2611]: https://github.com/tokio-rs/tracing/pull/2611 [#2674]: https://github.com/tokio-rs/tracing/pull/2674 [#2508]: https://github.com/tokio-rs/tracing/pull/2508 # 0.1.31 (May 11, 2023) This release of `tracing-core` fixes a bug that caused threads which call `dispatcher::get_default` _before_ a global default subscriber is set to never see the global default once it is set. In addition, it includes improvements for instrumentation performance in some cases, especially when using a global default dispatcher. ### Fixed - Fixed incorrect thread-local caching of `Dispatch::none` if `dispatcher::get_default` is called before `dispatcher::set_global_default` ([#2593]) ### Changed - Cloning a `Dispatch` that points at a global default subscriber no longer requires an `Arc` reference count increment, improving performance substantially ([#2593]) - `dispatcher::get_default` no longer attempts to access a thread local if the scoped dispatcher is not in use, improving performance when the default dispatcher is global ([#2593]) - Added `#[inline]` annotations called by the `event!` and `span!` macros to reduce the size of macro-generated code and improve recording performance ([#2555]) Thanks to new contributor @ldm0 for contributing to this release! [#2593]: https://github.com/tokio-rs/tracing/pull/2593 [#2555]: https://github.com/tokio-rs/tracing/pull/2555 # 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` and `Arc` ([#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` 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 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 where T: Value` as typed `tracing` field values. ### Added - **field**: `Value` impl for `Option 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` ([#1358]) - `Subscriber` impl for `Arc` ([#1374]) - Symmetric `From` impls for existing `Into` impls on `Current` and `Option` ([#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` to `LevelFilter`. This resolves a previously unreported regression where `Option` 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>`, `Into>`, and `Into>>` 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 tracing-core-0.1.32/Cargo.toml0000644000000026600000000000100114760ustar # 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.56.0" name = "tracing-core" version = "0.1.32" authors = ["Tokio Contributors "] 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 rustc-args = [ "--cfg", "tracing_unstable", ] rustdoc-args = [ "--cfg", "docsrs", "--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" tracing-core-0.1.32/Cargo.toml.orig000064400000000000000000000024671046102023000151640ustar 00000000000000[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.32" authors = ["Tokio Contributors "] 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.56.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"] tracing-core-0.1.32/LICENSE000064400000000000000000000020461046102023000132730ustar 00000000000000Copyright (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. tracing-core-0.1.32/README.md000064400000000000000000000116451046102023000135520ustar 00000000000000![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.31 [docs-badge]: https://docs.rs/tracing-core/badge.svg [docs-url]: https://docs.rs/tracing-core/0.1.31 [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.56+][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.31", default-features = false } ``` **Note**:`tracing-core`'s `no_std` support requires `liballoc`. [`tracing`]: ../tracing [`span::Id`]: https://docs.rs/tracing-core/0.1.31/tracing_core/span/struct.Id.html [`Event`]: https://docs.rs/tracing-core/0.1.31/tracing_core/event/struct.Event.html [`Subscriber`]: https://docs.rs/tracing-core/0.1.31/tracing_core/subscriber/trait.Subscriber.html [`Metadata`]: https://docs.rs/tracing-core/0.1.31/tracing_core/metadata/struct.Metadata.html [`Callsite`]: https://docs.rs/tracing-core/0.1.31/tracing_core/callsite/trait.Callsite.html [`Field`]: https://docs.rs/tracing-core/0.1.31/tracing_core/field/struct.Field.html [`FieldSet`]: https://docs.rs/tracing-core/0.1.31/tracing_core/field/struct.FieldSet.html [`Value`]: https://docs.rs/tracing-core/0.1.31/tracing_core/field/trait.Value.html [`ValueSet`]: https://docs.rs/tracing-core/0.1.31/tracing_core/field/struct.ValueSet.html [`Dispatch`]: https://docs.rs/tracing-core/0.1.31/tracing_core/dispatcher/struct.Dispatch.html ## Supported Rust Versions Tracing is built against the latest stable release. The minimum supported version is 1.56. 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.69, the minimum supported version will not be increased past 1.69, 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. tracing-core-0.1.32/src/callsite.rs000064400000000000000000000551351046102023000152320ustar 00000000000000//! 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. //! //! # 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. /// ///
///
    ///
    /// **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).
    ///
    /// 
/// /// [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 where Self: 'static, { private::Private(TypeId::of::()) } } /// 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, } /// 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::() { 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>> = Lazy::new(Default::default); struct Callsites { list_head: AtomicPtr, 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(&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(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>> = Lazy::new(Default::default); pub(super) enum Rebuilder<'a> { JustOne, Read(RwLockReadGuard<'a, Vec>), Write(RwLockWriteGuard<'a, Vec>), } 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) } } } } tracing-core-0.1.32/src/dispatcher.rs000064400000000000000000001066071046102023000155610ustar 00000000000000//! 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 //! ``` //! //!
//!     Note:the thread-local scoped dispatcher
//!     (with_default) requires the
//!     Rust standard library. no_std users should use
//!     set_global_default
//!     instead.
//! 
//! //! ## 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, Ref, RefCell}, 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: Kind>, } /// `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`. 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: Kind>, } #[derive(Clone)] enum Kind { Global(&'static (dyn Subscriber + 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); #[cfg(feature = "std")] static SCOPED_COUNT: AtomicUsize = AtomicUsize::new(0); const UNINITIALIZED: usize = 0; const INITIALIZING: usize = 1; const INITIALIZED: usize = 2; static mut GLOBAL_DISPATCH: Dispatch = Dispatch { subscriber: Kind::Global(&NO_SUBSCRIBER), }; static NONE: Dispatch = Dispatch { subscriber: Kind::Global(&NO_SUBSCRIBER), }; static NO_SUBSCRIBER: NoSubscriber = NoSubscriber::new(); /// The dispatch state of a thread. #[cfg(feature = "std")] struct State { /// This thread's current default dispatcher. default: RefCell>, /// 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, } /// 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); /// Sets this dispatch as the default for the duration of a closure. /// /// The default dispatcher is used when creating a new [span] or /// [`Event`]. /// ///
///     Note: This function required the Rust standard library.
///     no_std users should use 
///     set_global_default instead.
/// 
/// /// [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(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 /// ///
///     Note: This function required the Rust standard library.
///     no_std users should use 
///     set_global_default instead.
/// 
/// /// [`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. /// ///
///     Warning: In general, libraries should not call
///     set_global_default()! Doing so will cause conflicts when
///     executables that depend on the library try to set the default later.
/// 
/// /// [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() { let subscriber = { let subscriber = match dispatcher.subscriber { Kind::Global(s) => s, Kind::Scoped(s) => unsafe { // safety: this leaks the subscriber onto the heap. the // reference count will always be at least 1, because the // global default will never be dropped. &*Arc::into_raw(s) }, }; Kind::Global(subscriber) }; unsafe { GLOBAL_DISPATCH = Dispatch { subscriber }; } 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(mut f: F) -> T where F: FnMut(&Dispatch) -> T, { if SCOPED_COUNT.load(Ordering::Acquire) == 0 { // fast path if no scoped dispatcher has been set; just use the global // default. return f(get_global()); } CURRENT_STATE .try_with(|state| { if let Some(entered) = state.enter() { return f(&entered.current()); } f(&NONE) }) .unwrap_or_else(|_| f(&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(f: impl FnOnce(&Dispatch) -> T) -> Option { if SCOPED_COUNT.load(Ordering::Acquire) == 0 { // fast path if no scoped dispatcher has been set; just use the global // default. return Some(f(get_global())); } 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(f: impl FnOnce(&Dispatch) -> T) -> Option { Some(f(get_global())) } /// Executes a closure with a reference to the current [dispatcher]. /// /// [dispatcher]: super::dispatcher::Dispatch #[cfg(not(feature = "std"))] pub fn get_default(mut f: F) -> T where F: FnMut(&Dispatch) -> T, { f(&get_global()) } #[inline] fn get_global() -> &'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`. &GLOBAL_DISPATCH } } #[cfg(feature = "std")] pub(crate) struct Registrar(Kind>); impl Dispatch { /// Returns a new `Dispatch` that discards events and spans. #[inline] pub fn none() -> Self { Dispatch { subscriber: Kind::Global(&NO_SUBSCRIBER), } } /// Returns a `Dispatch` that forwards to the given [`Subscriber`]. /// /// [`Subscriber`]: super::subscriber::Subscriber pub fn new(subscriber: S) -> Self where S: Subscriber + Send + Sync + 'static, { let me = Dispatch { subscriber: Kind::Scoped(Arc::new(subscriber)), }; callsite::register_dispatch(&me); me } #[cfg(feature = "std")] pub(crate) fn registrar(&self) -> Registrar { Registrar(self.subscriber.downgrade()) } /// 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: self.subscriber.downgrade(), } } #[inline(always)] pub(crate) fn subscriber(&self) -> &(dyn Subscriber + Send + Sync) { match self.subscriber { Kind::Global(s) => s, Kind::Scoped(ref s) => s.as_ref(), } } /// Registers a new callsite with this subscriber, returning whether or not /// the subscriber 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 { 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<'_>) { let subscriber = self.subscriber(); if subscriber.event_enabled(event) { 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. /// ///
    ///     Deprecated: The 
    ///     try_close method is functionally identical, but returns
    ///     true if the span is now closed. It should be used
    ///     instead of this method.
    /// 
/// /// [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(&self) -> bool { ::is::(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(&self) -> Option<&T> { ::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 { match self.subscriber { Kind::Scoped(ref s) => f .debug_tuple("Dispatch::Scoped") .field(&format_args!("{:p}", s)) .finish(), Kind::Global(s) => f .debug_tuple("Dispatch::Global") .field(&format_args!("{:p}", s)) .finish(), } } } impl From 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 { self.subscriber .upgrade() .map(|subscriber| Dispatch { subscriber }) } } impl fmt::Debug for WeakDispatch { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.subscriber { Kind::Scoped(ref s) => f .debug_tuple("WeakDispatch::Scoped") .field(&format_args!("{:p}", s)) .finish(), Kind::Global(s) => f .debug_tuple("WeakDispatch::Global") .field(&format_args!("{:p}", s)) .finish(), } } } #[cfg(feature = "std")] impl Registrar { pub(crate) fn upgrade(&self) -> Option { self.0.upgrade().map(|subscriber| Dispatch { subscriber }) } } // ===== impl State ===== impl Kind> { fn downgrade(&self) -> Kind> { match self { Kind::Global(s) => Kind::Global(*s), Kind::Scoped(ref s) => Kind::Scoped(Arc::downgrade(s)), } } } impl Kind> { fn upgrade(&self) -> Option>> { match self { Kind::Global(s) => Some(Kind::Global(*s)), Kind::Scoped(ref s) => Some(Kind::Scoped(s.upgrade()?)), } } } // ===== 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); SCOPED_COUNT.fetch_add(1, Ordering::Release); DefaultGuard(prior) } #[inline] fn enter(&self) -> Option> { if self.can_enter.replace(false) { Some(Entered(self)) } else { None } } } // ===== impl Entered ===== #[cfg(feature = "std")] impl<'a> Entered<'a> { #[inline] fn current(&self) -> Ref<'a, Dispatch> { let default = self.0.default.borrow(); Ref::map(default, |default| match default { Some(default) => default, None => get_global(), }) } } #[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())); SCOPED_COUNT.fetch_sub(1, Ordering::Release); 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::()); } #[test] fn dispatch_downcasts() { let dispatcher = Dispatch::new(NoSubscriber::default()); assert!(dispatcher.downcast_ref::().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::()); } #[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::()); drop(guard); let default_dispatcher = Dispatch::default(); assert!(default_dispatcher.is::()); } } tracing-core-0.1.32/src/event.rs000064400000000000000000000104621046102023000145450ustar 00000000000000//! 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>, 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>, 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, } } } tracing-core-0.1.32/src/field.rs000064400000000000000000001162271046102023000145150ustar 00000000000000//! `Span` and `Event` key-value data. //! //! Spans and events may be annotated with key-value data, 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 event 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`. //! //!
//!     Note: valuable support is an
//!     unstable feature. See
//!     the documentation on unstable features for details on how to enable it.
//! 
//! //! 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, 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`. /// ///
///
/// Note: The record_error trait method is only
/// available when the Rust standard library is present, as it requires the
/// std::error::Error trait.
/// 
/// /// [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`. /// ///
///
    /// Note: This is only enabled when the Rust standard library is
    /// present.
    /// 
///
#[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); /// A `Value` which serializes as a string using `fmt::Debug`. #[derive(Clone)] pub struct DebugValue(T); /// Wraps a type implementing `fmt::Display` as a `Value` that can be /// recorded using its `Display` implementation. pub fn display(t: T) -> DisplayValue 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) -> DebugValue 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) -> 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 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) { // `op` is always a function; the closure is used because // sometimes there isn't a real function corresponding to that // operation. the clippy warning is not that useful here. #[allow(clippy::redundant_closure_call)] 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) { // `op` is always a function; the closure is used because // sometimes there isn't a real function corresponding to that // operation. the clippy warning is not that useful here. #[allow(clippy::redundant_closure_call)] 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 crate::sealed::Sealed for Wrapping {} impl crate::field::Value for Wrapping { 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 crate::sealed::Sealed for crate::stdlib::boxed::Box where T: Value {} impl Value for crate::stdlib::boxed::Box 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 crate::sealed::Sealed for DisplayValue {} impl Value for DisplayValue where T: fmt::Display, { fn record(&self, key: &Field, visitor: &mut dyn Visit) { visitor.record_debug(key, self) } } impl fmt::Debug for DisplayValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Display::fmt(self, f) } } impl fmt::Display for DisplayValue { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } // ===== impl DebugValue ===== impl crate::sealed::Sealed for DebugValue {} impl Value for DebugValue where T: fmt::Debug, { fn record(&self, key: &Field, visitor: &mut dyn Visit) { visitor.record_debug(key, &self.0) } } impl fmt::Debug for DebugValue { 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 crate::sealed::Sealed for Option {} impl Value for Option { 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 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(&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 #[inline] 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(&self, name: &Q) -> Option where Q: Borrow, { 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`. /// ///
///
    /// Note: If field shares a name with a field
    /// in this FieldSet, but was created by a FieldSet
    /// with a different callsite, this FieldSet does not
    /// contain it. This is so that if two separate span callsites define a field
    /// named "foo", the Field corresponding to "foo" for each
    /// of those callsites are not equivalent.
    /// 
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`. #[inline] 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. #[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; #[inline] fn next(&mut self) -> Option { 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::*; /// Restrictions on `ValueSet` lengths were removed in #2508 but this type remains for backwards compatibility. pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {} impl<'a, const N: usize> ValidLen<'a> for [(&'a Field, Option<&'a (dyn Value + 'a)>); N] {} } #[cfg(test)] mod test { use super::*; use crate::metadata::{Kind, Level, Metadata}; use crate::stdlib::{borrow::ToOwned, string::String}; // Make sure TEST_CALLSITE_* have non-zero size, so they can't be located at the same address. struct TestCallsite1(u8); static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1(0); 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(u8); static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2(0); 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 = 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)); } } tracing-core-0.1.32/src/lazy.rs000064400000000000000000000047311046102023000144050ustar 00000000000000#[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> { cell: Once, init: Cell>, } impl fmt::Debug for Lazy { 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` so it is fine to not impl // `Sync` for `F`. We do create a `&mut Option` in `force`, but this is // properly synchronized, so it only happens once so it also does not // contribute to this impl. unsafe impl Sync for Lazy where Once: Sync {} // auto-derived `Send` impl is OK. impl Lazy { /// Creates a new lazy value with the given initializing function. pub(crate) const fn new(init: F) -> Lazy { Lazy { cell: Once::new(), init: Cell::new(Some(init)), } } } impl T> Lazy { /// 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 { this.cell.call_once(|| match this.init.take() { Some(f) => f(), None => panic!("Lazy instance has previously been poisoned"), }) } } impl T> Deref for Lazy { type Target = T; fn deref(&self) -> &T { Lazy::force(self) } } impl Default for Lazy { /// Creates a new lazy value using `Default` as the initializing function. fn default() -> Lazy { Lazy::new(T::default) } } } tracing-core-0.1.32/src/lib.rs000064400000000000000000000214161046102023000141730ustar 00000000000000//! 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.56+][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.56. 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.69, the minimum supported version will not be //! increased past 1.66, 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_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, 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, ::core::option::Option::Some(file!()), ::core::option::Option::Some(line!()), ::core::option::Option::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 {} } tracing-core-0.1.32/src/metadata.rs000064400000000000000000001151401046102023000152030ustar 00000000000000//! 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, /// 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 { /// 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); /// 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, 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. #[inline] 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 { 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 { s.parse::() .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 for LevelFilter { #[inline] fn from(level: Level) -> Self { Self::from_level(level) } } impl From> for LevelFilter { #[inline] fn from(level: Option) -> Self { Self(level) } } impl From for Option { #[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 { 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 { from.parse::() .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`, 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` 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`) 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 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 { 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 for Level { #[inline(always)] fn partial_cmp(&self, other: &LevelFilter) -> Option { 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) -> usize { match x { Some(Level(f)) => *f as usize, None => LevelFilter::OFF_USIZE, } } impl PartialEq 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 { 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 for LevelFilter { #[inline(always)] fn partial_cmp(&self, other: &Level) -> Option { 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::().unwrap(), Level::ERROR); assert_eq!("4".parse::().unwrap(), Level::DEBUG); assert!("0".parse::().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::(), mem::size_of::(), "`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::(filter) }; assert_eq!(expected, repr, "repr changed for {:?}", filter) } } } tracing-core-0.1.32/src/parent.rs000064400000000000000000000004071046102023000147130ustar 00000000000000use 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), } tracing-core-0.1.32/src/span.rs000064400000000000000000000244021046102023000143640ustar 00000000000000//! 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`. /// ///
    ///     Note: Span IDs must be greater than zero.
    /// 
/// /// # 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 { 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 { fn from(cur: &'a Current) -> Self { cur.id().cloned() } } impl From for Option { 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() } } tracing-core-0.1.32/src/spin/LICENSE000064400000000000000000000020751046102023000150350ustar 00000000000000The 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. tracing-core-0.1.32/src/spin/mod.rs000064400000000000000000000001741046102023000151530ustar 00000000000000//! Synchronization primitives based on spinning pub(crate) use mutex::*; pub(crate) use once::Once; mod mutex; mod once; tracing-core-0.1.32/src/spin/mutex.rs000064400000000000000000000064171046102023000155440ustar 00000000000000use 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 { lock: AtomicBool, data: UnsafeCell, } /// 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 Sync for Mutex {} unsafe impl Send for Mutex {} impl Mutex { /// Creates a new spinlock wrapping the supplied data. pub(crate) const fn new(user_data: T) -> Mutex { Mutex { lock: AtomicBool::new(false), data: UnsafeCell::new(user_data), } } } impl Mutex { 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> { 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 fmt::Debug for Mutex { 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 {{ }}"), } } } impl Default for Mutex { fn default() -> Mutex { 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); } } tracing-core-0.1.32/src/spin/once.rs000064400000000000000000000117711046102023000153250ustar 00000000000000use 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 { state: AtomicUsize, data: UnsafeCell>, // TODO remove option and use mem::uninitialized } impl fmt::Debug for Once { 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 {{ }}"), } } } // Same unsafe impls as `std::sync::RwLock`, because this also allows for // concurrent reads. unsafe impl Sync for Once {} unsafe impl Send for Once {} // 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 Once { /// 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 { 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); } } } tracing-core-0.1.32/src/stdlib.rs000064400000000000000000000046701046102023000147110ustar 00000000000000//! 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 { inner: crate::spin::Mutex, } impl Mutex { // pub(crate) fn new(data: T) -> Self { // Self { // inner: crate::spin::Mutex::new(data), // } // } pub(crate) fn lock(&self) -> Result, ()> { Ok(self.inner.lock()) } } } } tracing-core-0.1.32/src/subscriber.rs000064400000000000000000001053731046102023000155750ustar 00000000000000//! 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 { 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::() { 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(&self) -> bool { self.downcast_ref::().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(&self) -> Option<&T> { unsafe { let raw = self.downcast_raw(TypeId::of::())?; 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(&self) -> bool { self.downcast_ref::().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(&self) -> Option<&T> { unsafe { let raw = self.downcast_raw(TypeId::of::())?; 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(&self) -> bool { self.downcast_ref::().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(&self) -> Option<&T> { unsafe { let raw = self.downcast_raw(TypeId::of::())?; 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(&self) -> bool { self.downcast_ref::().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(&self) -> Option<&T> { unsafe { let raw = self.downcast_raw(TypeId::of::())?; 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 NoSubscriber { /// Returns a new `NoSubscriber`. #[must_use] pub const fn new() -> Self { Self(()) } } impl Subscriber for Box 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 { 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::() { return Some(self as *const Self as *const _); } self.as_ref().downcast_raw(id) } } impl Subscriber for Arc 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 { 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::() { return Some(self as *const Self as *const _); } self.as_ref().downcast_raw(id) } } tracing-core-0.1.32/tests/common/mod.rs000064400000000000000000000017761046102023000160560ustar 00000000000000use 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) {} } tracing-core-0.1.32/tests/dispatch.rs000064400000000000000000000026341046102023000156000ustar 00000000000000#![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::(), "global dispatch get failed" ) }); let guard = set_default(&Dispatch::new(TestSubscriberB)); get_default(|current| assert!(current.is::(), "set_default get failed")); // Drop the guard, setting the dispatch back to the global dispatch drop(guard); get_default(|current| { assert!( current.is::(), "global dispatch get failed" ) }); } #[test] fn nested_set_default() { let _guard = set_default(&Dispatch::new(TestSubscriberA)); get_default(|current| { assert!( current.is::(), "set_default for outer subscriber failed" ) }); let inner_guard = set_default(&Dispatch::new(TestSubscriberB)); get_default(|current| { assert!( current.is::(), "set_default inner subscriber failed" ) }); drop(inner_guard); get_default(|current| { assert!( current.is::(), "set_default outer subscriber failed" ) }); } tracing-core-0.1.32/tests/global_dispatch.rs000064400000000000000000000015761046102023000171240ustar 00000000000000mod 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::(), "global dispatch get failed" ) }); #[cfg(feature = "std")] with_default(&Dispatch::new(TestSubscriberB), || { get_default(|current| { assert!( current.is::(), "thread-local override of global dispatch failed" ) }); }); get_default(|current| { assert!( current.is::(), "reset to global override failed" ) }); set_global_default(Dispatch::new(TestSubscriberA)) .expect_err("double global dispatch set succeeded"); } tracing-core-0.1.32/tests/local_dispatch_before_init.rs000064400000000000000000000024741046102023000213210ustar 00000000000000mod common; use common::*; use tracing_core::{ dispatcher::{self, Dispatch}, subscriber::NoSubscriber, }; /// This test reproduces the following issues: /// - https://github.com/tokio-rs/tracing/issues/2587 /// - https://github.com/tokio-rs/tracing/issues/2411 /// - https://github.com/tokio-rs/tracing/issues/2436 #[test] fn local_dispatch_before_init() { dispatcher::get_default(|current| assert!(dbg!(current).is::())); // Temporarily override the default dispatcher with a scoped dispatcher. // Using a scoped dispatcher makes the thread local state attempt to cache // the scoped default. #[cfg(feature = "std")] { dispatcher::with_default(&Dispatch::new(TestSubscriberB), || { dispatcher::get_default(|current| { assert!( dbg!(current).is::(), "overriden subscriber not set", ); }) }) } dispatcher::get_default(|current| assert!(current.is::())); dispatcher::set_global_default(Dispatch::new(TestSubscriberA)) .expect("set global dispatch failed"); dispatcher::get_default(|current| { assert!( dbg!(current).is::(), "default subscriber not set" ); }); } tracing-core-0.1.32/tests/macros.rs000064400000000000000000000022641046102023000152640ustar 00000000000000use 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 }; }