diff --git a/tracing-opentelemetry/Cargo.toml b/tracing-opentelemetry/Cargo.toml index f37a779bf5..f7d2934e98 100644 --- a/tracing-opentelemetry/Cargo.toml +++ b/tracing-opentelemetry/Cargo.toml @@ -25,7 +25,7 @@ default = ["tracing-log"] opentelemetry = { version = "0.16", default-features = false, features = ["trace"] } tracing = { path = "../tracing", version = "0.2", default-features = false, features = ["std"] } tracing-core = { path = "../tracing-core", version = "0.2" } -tracing-subscriber = { path = "../tracing-subscriber", version = "0.3", default-features = false, features = ["registry"] } +tracing-subscriber = { path = "../tracing-subscriber", version = "0.3", default-features = false, features = ["registry", "std"] } tracing-log = { path = "../tracing-log", version = "0.2", default-features = false, optional = true } [dev-dependencies] diff --git a/tracing-subscriber/Cargo.toml b/tracing-subscriber/Cargo.toml index ed469813a3..ce3a8657f8 100644 --- a/tracing-subscriber/Cargo.toml +++ b/tracing-subscriber/Cargo.toml @@ -23,7 +23,9 @@ keywords = ["logging", "tracing", "metrics", "subscriber"] [features] -default = ["smallvec", "fmt", "ansi", "tracing-log"] +default = ["smallvec", "fmt", "ansi", "tracing-log", "std"] +alloc = [] +std = ["alloc", "tracing-core/std"] env-filter = ["matchers", "regex", "lazy_static", "tracing"] fmt = ["registry"] ansi = ["fmt", "ansi_term"] @@ -37,7 +39,7 @@ local-time = ["time/local-offset"] tracing-core = { path = "../tracing-core", version = "0.2" } # only required by the `env-filter` feature -tracing = { optional = true, path = "../tracing", version = "0.2", default-features = false, features = ["std"] } +tracing = { optional = true, path = "../tracing", version = "0.2", default-features = false } matchers = { optional = true, version = "0.1.0" } regex = { optional = true, version = "1", default-features = false, features = ["std"] } smallvec = { optional = true, version = "1" } diff --git a/tracing-subscriber/src/field/debug.rs b/tracing-subscriber/src/field/debug.rs index 10b9eb274c..cc67d29fe7 100644 --- a/tracing-subscriber/src/field/debug.rs +++ b/tracing-subscriber/src/field/debug.rs @@ -1,8 +1,8 @@ //! `MakeVisitor` wrappers for working with `fmt::Debug` fields. -use super::{MakeVisitor, VisitFmt, VisitOutput, VisitWrite}; +use super::{MakeVisitor, VisitFmt, VisitOutput}; use tracing_core::field::{Field, Visit}; -use std::{fmt, io}; +use core::fmt; /// A visitor wrapper that ensures any `fmt::Debug` fields are formatted using /// the alternate (`:#`) formatter. @@ -84,13 +84,19 @@ where } } -impl VisitWrite for Alt -where - V: VisitWrite, -{ - #[inline] - fn writer(&mut self) -> &mut dyn io::Write { - self.0.writer() +feature! { + #![feature = "std"] + use super::VisitWrite; + use std::io; + + impl VisitWrite for Alt + where + V: VisitWrite, + { + #[inline] + fn writer(&mut self) -> &mut dyn io::Write { + self.0.writer() + } } } diff --git a/tracing-subscriber/src/field/delimited.rs b/tracing-subscriber/src/field/delimited.rs index dff611ce8c..98634cea9b 100644 --- a/tracing-subscriber/src/field/delimited.rs +++ b/tracing-subscriber/src/field/delimited.rs @@ -1,7 +1,7 @@ //! A `MakeVisitor` wrapper that separates formatted fields with a delimiter. use super::{MakeVisitor, VisitFmt, VisitOutput}; -use std::fmt; +use core::fmt; use tracing_core::field::{Field, Visit}; /// A `MakeVisitor` wrapper that wraps a visitor that writes formatted output so @@ -133,6 +133,7 @@ where } #[cfg(test)] +#[cfg(all(test, feature = "alloc"))] mod test { use super::*; use crate::field::test_util::*; diff --git a/tracing-subscriber/src/field/display.rs b/tracing-subscriber/src/field/display.rs index 63245fdc02..78a039ce17 100644 --- a/tracing-subscriber/src/field/display.rs +++ b/tracing-subscriber/src/field/display.rs @@ -1,8 +1,8 @@ //! `MakeVisitor` wrappers for working with `fmt::Display` fields. -use super::{MakeVisitor, VisitFmt, VisitOutput, VisitWrite}; +use super::{MakeVisitor, VisitFmt, VisitOutput}; use tracing_core::field::{Field, Visit}; -use std::{fmt, io}; +use core::fmt; /// A visitor wrapper that ensures any strings named "message" are formatted /// using `fmt::Display` @@ -90,13 +90,19 @@ where } } -impl VisitWrite for Messages -where - V: VisitWrite, -{ - #[inline] - fn writer(&mut self) -> &mut dyn io::Write { - self.0.writer() +feature! { + #![feature = "std"] + use super::VisitWrite; + use std::io; + + impl VisitWrite for Messages + where + V: VisitWrite, + { + #[inline] + fn writer(&mut self) -> &mut dyn io::Write { + self.0.writer() + } } } diff --git a/tracing-subscriber/src/field/mod.rs b/tracing-subscriber/src/field/mod.rs index 7f9d7a10d4..ca4ad5771a 100644 --- a/tracing-subscriber/src/field/mod.rs +++ b/tracing-subscriber/src/field/mod.rs @@ -2,7 +2,7 @@ //! //! [fields]: tracing_core::field //! [field visitors]: tracing_core::field::Visit -use std::{fmt, io}; +use core::{fmt, marker::PhantomData}; pub use tracing_core::field::Visit; use tracing_core::{ span::{Attributes, Record}, @@ -108,11 +108,16 @@ where } } -/// Extension trait implemented by visitors to indicate that they write to an -/// `io::Write` instance, and allow access to that writer. -pub trait VisitWrite: VisitOutput> { - /// Returns the writer that this visitor writes to. - fn writer(&mut self) -> &mut dyn io::Write; +feature! { + #![feature = "std"] + use std::io; + + /// Extension trait implemented by visitors to indicate that they write to an + /// `io::Write` instance, and allow access to that writer. + pub trait VisitWrite: VisitOutput> { + /// Returns the writer that this visitor writes to. + fn writer(&mut self) -> &mut dyn io::Write; + } } /// Extension trait implemented by visitors to indicate that they write to a @@ -223,7 +228,7 @@ where #[derive(Debug)] #[doc(hidden)] pub struct MakeExtMarker { - _p: std::marker::PhantomData, + _p: PhantomData, } #[derive(Debug)] @@ -232,10 +237,11 @@ pub struct RecordFieldsMarker { _p: (), } -#[cfg(test)] +#[cfg(all(test, feature = "alloc"))] #[macro_use] pub(in crate::field) mod test_util { use super::*; + pub(in crate::field) use alloc::string::String; use tracing_core::{ callsite::Callsite, field::{Field, Value}, diff --git a/tracing-subscriber/src/filter/env/mod.rs b/tracing-subscriber/src/filter/env/mod.rs index 0ac337ea42..721cf38d66 100644 --- a/tracing-subscriber/src/filter/env/mod.rs +++ b/tracing-subscriber/src/filter/env/mod.rs @@ -97,8 +97,7 @@ use tracing_core::{ /// [`Event`]: tracing_core::Event /// [`level`]: tracing_core::Level /// [`Metadata`]: tracing_core::Metadata -#[cfg(feature = "env-filter")] -#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))] #[derive(Debug)] pub struct EnvFilter { statics: directive::Statics, @@ -121,7 +120,7 @@ type FilterVec = Vec; /// Indicates that an error occurred while parsing a `EnvFilter` from an /// environment variable. -#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] +#[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))] #[derive(Debug)] pub struct FromEnvError { kind: ErrorKind, diff --git a/tracing-subscriber/src/filter/mod.rs b/tracing-subscriber/src/filter/mod.rs index 41c49a6c7e..9d63ff3f4d 100644 --- a/tracing-subscriber/src/filter/mod.rs +++ b/tracing-subscriber/src/filter/mod.rs @@ -2,12 +2,12 @@ //! subscriber. //! //! [`Subscriber`]: crate::fmt::Subscriber -#[cfg(feature = "env-filter")] -mod env; mod level; pub use self::level::{LevelFilter, ParseError as LevelParseError}; -#[cfg(feature = "env-filter")] -#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] -pub use self::env::*; +feature! { + #![all(feature = "env-filter", feature = "std")] + mod env; + pub use self::env::*; +} diff --git a/tracing-subscriber/src/fmt/fmt_subscriber.rs b/tracing-subscriber/src/fmt/fmt_subscriber.rs index 257c5c43f5..23209b949f 100644 --- a/tracing-subscriber/src/fmt/fmt_subscriber.rs +++ b/tracing-subscriber/src/fmt/fmt_subscriber.rs @@ -61,6 +61,7 @@ use tracing_core::{ /// /// [`Subscriber`]: subscribe::Subscribe #[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub struct Subscriber io::Stdout> { make_writer: W, fmt_fields: N, diff --git a/tracing-subscriber/src/fmt/mod.rs b/tracing-subscriber/src/fmt/mod.rs index 5d1a11e523..4b64d7ed6a 100644 --- a/tracing-subscriber/src/fmt/mod.rs +++ b/tracing-subscriber/src/fmt/mod.rs @@ -288,8 +288,11 @@ use std::{any::TypeId, error::Error, io, ptr::NonNull}; use tracing_core::{collect::Interest, span, Event, Metadata}; mod fmt_subscriber; +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub mod format; +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub mod time; +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub mod writer; pub use fmt_subscriber::{FmtContext, FormattedFields, Subscriber}; @@ -311,6 +314,7 @@ pub use self::{ /// /// This consists of an inner `Formatter` wrapped in a subscriber that performs filtering. #[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub struct Collector< N = format::DefaultFields, E = format::Format, @@ -322,11 +326,13 @@ pub struct Collector< /// A collector that logs formatted representations of `tracing` events. /// This type only logs formatted events; it does not perform any filtering. +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub type Formatter io::Stdout> = subscribe::Layered, Registry>; /// Configures and constructs `Collector`s. #[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub struct CollectorBuilder< N = format::DefaultFields, E = format::Format, @@ -400,6 +406,7 @@ pub struct CollectorBuilder< /// [`init`]: CollectorBuilder::init() /// [`try_init`]: CollectorBuilder::try_init() /// [`finish`]: CollectorBuilder::finish() +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub fn fmt() -> CollectorBuilder { CollectorBuilder::default() } @@ -411,6 +418,7 @@ pub fn fmt() -> CollectorBuilder { /// /// [formatting subscriber]: Subscriber /// [composed]: super::subscribe +#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))] pub fn subscriber() -> Subscriber { Subscriber::default() } diff --git a/tracing-subscriber/src/fmt/writer.rs b/tracing-subscriber/src/fmt/writer.rs index e0fbbafefb..a34903a7ed 100644 --- a/tracing-subscriber/src/fmt/writer.rs +++ b/tracing-subscriber/src/fmt/writer.rs @@ -3,7 +3,7 @@ //! [`io::Write`]: std::io::Write use std::{ - fmt::{self, Debug}, + fmt, io::{self, Write}, sync::{Mutex, MutexGuard}, }; @@ -642,6 +642,7 @@ pub struct Tee { /// `tracing-subscriber`'s `FormatEvent`/`FormatTime` traits expect a /// `fmt::Write` implementation, while `serde_json::Serializer` and `time`'s /// `format_into` methods expect an `io::Write`. +#[cfg(any(feature = "json", feature = "time"))] pub(in crate::fmt) struct WriteAdaptor<'a> { fmt_write: &'a mut dyn fmt::Write, } @@ -710,8 +711,8 @@ impl BoxMakeWriter { } } -impl Debug for BoxMakeWriter { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for BoxMakeWriter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_tuple("BoxMakeWriter") .field(&format_args!("<{}>", self.name)) .finish() @@ -1097,12 +1098,13 @@ where // === impl WriteAdaptor === +#[cfg(any(feature = "json", feature = "time"))] impl<'a> WriteAdaptor<'a> { pub(in crate::fmt) fn new(fmt_write: &'a mut dyn fmt::Write) -> Self { Self { fmt_write } } } - +#[cfg(any(feature = "json", feature = "time"))] impl<'a> io::Write for WriteAdaptor<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { let s = @@ -1120,6 +1122,7 @@ impl<'a> io::Write for WriteAdaptor<'a> { } } +#[cfg(any(feature = "json", feature = "time"))] impl<'a> fmt::Debug for WriteAdaptor<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("WriteAdaptor { .. }") diff --git a/tracing-subscriber/src/lib.rs b/tracing-subscriber/src/lib.rs index a9ac89d3bd..7d92256af0 100644 --- a/tracing-subscriber/src/lib.rs +++ b/tracing-subscriber/src/lib.rs @@ -22,6 +22,9 @@ //! //! ## Feature Flags //! +//! - `std`: Enables APIs that depend on the on the Rust standard library +//! (enabled by default). +//! - `alloc`: Depend on [`liballoc`] (enabled by "std"). //! - `env-filter`: Enables the [`EnvFilter`] type, which implements filtering //! similar to the [`env_logger` crate]. //! - `fmt`: Enables the [`fmt`] module, which provides a subscriber @@ -46,6 +49,34 @@ //! - [`parking_lot`]: Use the `parking_lot` crate's `RwLock` implementation //! rather than the Rust standard library's implementation. //! +//! ### `no_std` Support +//! +//! In embedded systems and other bare-metal applications, `tracing` can be +//! used without requiring the Rust standard library, although some features are +//! disabled. Although most of the APIs provided by `tracing-subscriber`, such +//! as [`fmt`] and [`EnvFilter`], require the standard library, some +//! functionality, such as the [`Subscriber`] trait, can still be used in +//! `no_std` environments. +//! +//! The dependency on the standard library is controlled by two crate feature +//! flags, "std", which enables the dependency on [`libstd`], and "alloc", which +//! enables the dependency on [`liballoc`] (and is enabled by the "std" +//! feature). These features are enabled by default, but `no_std` users can +//! disable them using: +//! +//! ```toml +//! # Cargo.toml +//! tracing-subscriber = { version = "0.3", default-features = false } +//! ``` +//! +//! Additional APIs are available when [`liballoc`] is available. To enable +//! `liballoc` but not `std`, use: +//! +//! ```toml +//! # Cargo.toml +//! tracing-subscriber = { version = "0.3", default-features = false, features = ["alloc"] } +//! ``` +//! //! ## Supported Rust Versions //! //! Tracing is built against the latest stable release. The minimum supported @@ -69,6 +100,7 @@ //! [`env_logger` crate]: https://crates.io/crates/env_logger //! [`parking_lot`]: https://crates.io/crates/parking_lot //! [`time` crate]: https://crates.io/crates/time +//! [`liballoc`]: https://doc.rust-lang.org/alloc/index.html #![doc(html_root_url = "https://docs.rs/tracing-subscriber/0.2.12")] #![doc( html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png", @@ -103,43 +135,51 @@ // future, reducing diff noise. Allow this even though clippy considers it // "needless". #![allow(clippy::needless_update)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "alloc")] +extern crate alloc; #[macro_use] mod macros; pub mod field; pub mod filter; -#[cfg(feature = "fmt")] -#[cfg_attr(docsrs, doc(cfg(feature = "fmt")))] -pub mod fmt; pub mod prelude; pub mod registry; -pub mod reload; + pub mod subscribe; -pub(crate) mod sync; pub mod util; -#[cfg(feature = "env-filter")] -#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))] -pub use filter::EnvFilter; - -pub use subscribe::Subscribe; +feature! { + #![feature = "std"] + pub mod reload; + pub(crate) mod sync; +} -cfg_feature!("fmt", { +feature! { + #![all(feature = "fmt", feature = "std")] + pub mod fmt; pub use fmt::fmt; pub use fmt::Subscriber as FmtSubscriber; -}); +} + +feature! { + #![all(feature = "env-filter", feature = "std")] + pub use filter::EnvFilter; +} -cfg_feature!("registry", { +pub use subscribe::Subscribe; + +feature! { + #![all(feature = "registry", feature = "std")] pub use registry::Registry; /// pub fn registry() -> Registry { Registry::default() } -}); - -use std::default::Default; +} mod sealed { pub trait Sealed {} diff --git a/tracing-subscriber/src/macros.rs b/tracing-subscriber/src/macros.rs index adda4cc81c..81351132f5 100644 --- a/tracing-subscriber/src/macros.rs +++ b/tracing-subscriber/src/macros.rs @@ -1,3 +1,4 @@ +#[cfg(feature = "std")] macro_rules! try_lock { ($lock:expr) => { try_lock!($lock, else return) @@ -13,11 +14,14 @@ macro_rules! try_lock { }; } -macro_rules! cfg_feature { - ($name:literal, { $($item:item)* }) => { +macro_rules! feature { + ( + #![$meta:meta] + $($item:item)* + ) => { $( - #[cfg(feature = $name)] - #[cfg_attr(docsrs, doc(cfg(feature = $name)))] + #[cfg($meta)] + #[cfg_attr(docsrs, doc(cfg($meta)))] $item )* } diff --git a/tracing-subscriber/src/prelude.rs b/tracing-subscriber/src/prelude.rs index 72570350e8..a6d6e0f7d3 100644 --- a/tracing-subscriber/src/prelude.rs +++ b/tracing-subscriber/src/prelude.rs @@ -7,6 +7,7 @@ pub use crate::field::{MakeExt as _, RecordFields as _}; pub use crate::subscribe::{CollectExt as _, Subscribe as _}; pub use crate::util::SubscriberInitExt as _; -#[cfg(feature = "fmt")] -#[cfg_attr(docsrs, doc(cfg(feature = "fmt")))] -pub use crate::fmt::writer::MakeWriterExt as _; +feature! { + #![all(feature = "fmt", feature = "std")] + pub use crate::fmt::writer::MakeWriterExt as _; +} diff --git a/tracing-subscriber/src/registry/extensions.rs b/tracing-subscriber/src/registry/extensions.rs index 09ef985e0f..8b087b7d09 100644 --- a/tracing-subscriber/src/registry/extensions.rs +++ b/tracing-subscriber/src/registry/extensions.rs @@ -35,6 +35,7 @@ impl Hasher for IdHasher { /// An immutable, read-only reference to a Span's extensions. #[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub struct Extensions<'a> { inner: RwLockReadGuard<'a, ExtensionsInner>, } @@ -52,6 +53,7 @@ impl<'a> Extensions<'a> { /// An mutable reference to a Span's extensions. #[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub struct ExtensionsMut<'a> { inner: RwLockWriteGuard<'a, ExtensionsInner>, } diff --git a/tracing-subscriber/src/registry/mod.rs b/tracing-subscriber/src/registry/mod.rs index 73786a1318..334cd0b792 100644 --- a/tracing-subscriber/src/registry/mod.rs +++ b/tracing-subscriber/src/registry/mod.rs @@ -58,22 +58,27 @@ //! [`Collect`]: tracing_core::collect::Collect //! [ctx]: crate::subscribe::Context //! [lookup]: crate::subscribe::Context::span() -use std::fmt::Debug; +use core::fmt::Debug; use tracing_core::{field::FieldSet, span::Id, Metadata}; -/// A module containing a type map of span extensions. -mod extensions; +feature! { + #![feature = "std"] + /// A module containing a type map of span extensions. + mod extensions; + pub use extensions::{Extensions, ExtensionsMut}; + +} + +feature! { + #![all(feature = "registry", feature = "std")] -cfg_feature!("registry", { mod sharded; mod stack; pub use sharded::Data; pub use sharded::Registry; -}); - -pub use extensions::{Extensions, ExtensionsMut}; +} /// Provides access to stored span data. /// @@ -140,12 +145,16 @@ pub trait SpanData<'a> { /// /// The extensions may be used by `Subscriber`s to store additional data /// describing the span. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] fn extensions(&self) -> Extensions<'_>; /// Returns a mutable reference to this span's `Extensions`. /// /// The extensions may be used by `Subscriber`s to store additional data /// describing the span. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] fn extensions_mut(&self) -> ExtensionsMut<'_>; } @@ -172,87 +181,91 @@ pub struct Scope<'a, R> { next: Option, } -impl<'a, R> Scope<'a, R> -where - R: LookupSpan<'a>, -{ - /// Flips the order of the iterator, so that it is ordered from root to leaf. - /// - /// The iterator will first return the root span, then that span's immediate child, - /// and so on until it finally returns the span that [`SpanRef::scope`] was called on. - /// - /// If any items were consumed from the [`Scope`] before calling this method then they - /// will *not* be returned from the [`ScopeFromRoot`]. +feature! { + #![feature = "std"] + + /// An iterator over the parents of a span, ordered from root to leaf. /// - /// **Note**: this will allocate if there are many spans remaining, or if the - /// "smallvec" feature flag is not enabled. - #[allow(clippy::wrong_self_convention)] - pub fn from_root(self) -> ScopeFromRoot<'a, R> { + /// This is returned by the [`Scope::from_root`] method. + pub struct ScopeFromRoot<'a, R> + where + R: LookupSpan<'a>, + { #[cfg(feature = "smallvec")] - type Buf = smallvec::SmallVec; + spans: std::iter::Rev>>, #[cfg(not(feature = "smallvec"))] - type Buf = Vec; - ScopeFromRoot { - spans: self.collect::>().into_iter().rev(), - } + spans: std::iter::Rev>>, } -} -impl<'a, R> Iterator for Scope<'a, R> -where - R: LookupSpan<'a>, -{ - type Item = SpanRef<'a, R>; + #[cfg(feature = "smallvec")] + type SpanRefVecArray<'span, L> = [SpanRef<'span, L>; 16]; - fn next(&mut self) -> Option { - let curr = self.registry.span(self.next.as_ref()?)?; - self.next = curr.parent_id().cloned(); - Some(curr) + impl<'a, R> Scope<'a, R> + where + R: LookupSpan<'a>, + { + /// Flips the order of the iterator, so that it is ordered from root to leaf. + /// + /// The iterator will first return the root span, then that span's immediate child, + /// and so on until it finally returns the span that [`SpanRef::scope`] was called on. + /// + /// If any items were consumed from the [`Scope`] before calling this method then they + /// will *not* be returned from the [`ScopeFromRoot`]. + /// + /// **Note**: this will allocate if there are many spans remaining, or if the + /// "smallvec" feature flag is not enabled. + #[allow(clippy::wrong_self_convention)] + pub fn from_root(self) -> ScopeFromRoot<'a, R> { + #[cfg(feature = "smallvec")] + type Buf = smallvec::SmallVec; + #[cfg(not(feature = "smallvec"))] + type Buf = Vec; + ScopeFromRoot { + spans: self.collect::>().into_iter().rev(), + } + } } -} -/// An iterator over the parents of a span, ordered from root to leaf. -/// -/// This is returned by the [`Scope::from_root`] method. -pub struct ScopeFromRoot<'a, R> -where - R: LookupSpan<'a>, -{ - #[cfg(feature = "smallvec")] - spans: std::iter::Rev>>, - #[cfg(not(feature = "smallvec"))] - spans: std::iter::Rev>>, -} + impl<'a, R> Iterator for ScopeFromRoot<'a, R> + where + R: LookupSpan<'a>, + { + type Item = SpanRef<'a, R>; -impl<'a, R> Iterator for ScopeFromRoot<'a, R> -where - R: LookupSpan<'a>, -{ - type Item = SpanRef<'a, R>; + #[inline] + fn next(&mut self) -> Option { + self.spans.next() + } - #[inline] - fn next(&mut self) -> Option { - self.spans.next() + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.spans.size_hint() + } } - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.spans.size_hint() + impl<'a, R> Debug for ScopeFromRoot<'a, R> + where + R: LookupSpan<'a>, + { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.pad("ScopeFromRoot { .. }") + } } } -impl<'a, R> Debug for ScopeFromRoot<'a, R> +impl<'a, R> Iterator for Scope<'a, R> where R: LookupSpan<'a>, { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.pad("ScopeFromRoot { .. }") + type Item = SpanRef<'a, R>; + + fn next(&mut self) -> Option { + let curr = self.registry.span(self.next.as_ref()?)?; + self.next = curr.parent_id().cloned(); + Some(curr) } } -#[cfg(feature = "smallvec")] -type SpanRefVecArray<'span, L> = [SpanRef<'span, L>; 16]; - impl<'a, R> SpanRef<'a, R> where R: LookupSpan<'a>, @@ -374,6 +387,8 @@ where /// /// The extensions may be used by `Subscriber`s to store additional data /// describing the span. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn extensions(&self) -> Extensions<'_> { self.data.extensions() } @@ -382,12 +397,14 @@ where /// /// The extensions may be used by `Subscriber`s to store additional data /// describing the span. + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn extensions_mut(&self) -> ExtensionsMut<'_> { self.data.extensions_mut() } } -#[cfg(all(test, feature = "registry"))] +#[cfg(all(test, feature = "registry", feature = "std"))] mod tests { use crate::{ prelude::*, diff --git a/tracing-subscriber/src/registry/sharded.rs b/tracing-subscriber/src/registry/sharded.rs index ca680de25b..c594d3f25c 100644 --- a/tracing-subscriber/src/registry/sharded.rs +++ b/tracing-subscriber/src/registry/sharded.rs @@ -19,94 +19,93 @@ use tracing_core::{ Collect, Event, Interest, Metadata, }; -cfg_feature!("registry", { - /// A shared, reusable store for spans. - /// - /// A `Registry` is a [`Collect`] around which multiple subscribers - /// implementing various behaviors may be [added]. Unlike other types - /// implementing `Collect`, `Registry` does not actually record traces itself: - /// instead, it collects and stores span data that is exposed to any [subscriber]s - /// wrapping it through implementations of the [`LookupSpan`] trait. - /// The `Registry` is responsible for storing span metadata, recording - /// relationships between spans, and tracking which spans are active and which - /// are closed. In addition, it provides a mechanism for [subscriber]s to store - /// user-defined per-span data, called [extensions], in the registry. This - /// allows `Subscriber`-specific data to benefit from the `Registry`'s - /// high-performance concurrent storage. - /// - /// This registry is implemented using a [lock-free sharded slab][slab], and is - /// highly optimized for concurrent access. - /// - /// # Span ID Generation - /// - /// Span IDs are not globally unique, but the registry ensures that - /// no two currently active spans have the same ID within a process. - /// - /// One of the primary responsibilities of the registry is to generate [span - /// IDs]. Therefore, it's important for other code that interacts with the - /// registry, such as [subscriber]s, to understand the guarantees of the - /// span IDs that are generated. - /// - /// The registry's span IDs are guaranteed to be unique **at a given point - /// in time**. This means that an active span will never be assigned the - /// same ID as another **currently active** span. However, the registry - /// **will** eventually reuse the IDs of [closed] spans, although an ID - /// will never be reassigned immediately after a span has closed. - /// - /// Spans are not [considered closed] by the `Registry` until *every* - /// [`Span`] reference with that ID has been dropped. - /// - /// Thus: span IDs generated by the registry should be considered unique - /// only at a given point in time, and only relative to other spans - /// generated by the same process. Two spans with the same ID will not exist - /// in the same process concurrently. However, if historical span data is - /// being stored, the same ID may occur for multiple spans times in that - /// data. If spans must be uniquely identified in historical data, the user - /// code storing this data must assign its own unique identifiers to those - /// spans. A counter is generally sufficient for this. - /// - /// Similarly, span IDs generated by the registry are not unique outside of - /// a given process. Distributed tracing systems may require identifiers - /// that are unique across multiple processes on multiple machines (for - /// example, [OpenTelemetry's `SpanId`s and `TraceId`s][ot]). `tracing` span - /// IDs generated by the registry should **not** be used for this purpose. - /// Instead, code which integrates with a distributed tracing system should - /// generate and propagate its own IDs according to the rules specified by - /// the distributed tracing system. These IDs can be associated with - /// `tracing` spans using [fields] and/or [stored span data]. - /// - /// [span IDs]: https://docs.rs/tracing-core/latest/tracing_core/span/struct.Id.html - /// [slab]: https://docs.rs/crate/sharded-slab/ - /// [subscriber]: crate::Subscribe - /// [added]: crate::subscribe::Subscribe#composing-subscribers - /// [extensions]: super::Extensions - /// [closed]: https://docs.rs/tracing/latest/tracing/span/index.html#closing-spans - /// [considered closed]: https://docs.rs/tracing-core/latest/tracing_core/subscriber/trait.Subscriber.html#method.try_close - /// [`Span`]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html - /// [ot]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#spancontext - /// [fields]: https://docs.rs/tracing-core/latest/tracing-core/field/index.html - /// [stored span data]: crate::registry::SpanData::extensions_mut - #[derive(Debug)] - pub struct Registry { - spans: Pool, - current_spans: ThreadLocal>, - } - - /// Span data stored in a [`Registry`]. - /// - /// The registry stores well-known data defined by tracing: span relationships, - /// metadata and reference counts. Additional user-defined data provided by - /// [`Subscriber`s], such as formatted fields, metrics, or distributed traces should - /// be stored in the [extensions] typemap. - /// - /// [`Subscriber`s]: crate::Subscribe - /// [extensions]: Extensions - #[derive(Debug)] - pub struct Data<'a> { - /// Immutable reference to the pooled `DataInner` entry. - inner: Ref<'a, DataInner>, - } -}); +/// A shared, reusable store for spans. +/// +/// A `Registry` is a [`Collect`] around which multiple subscribers +/// implementing various behaviors may be [added]. Unlike other types +/// implementing `Collect`, `Registry` does not actually record traces itself: +/// instead, it collects and stores span data that is exposed to any [subscriber]s +/// wrapping it through implementations of the [`LookupSpan`] trait. +/// The `Registry` is responsible for storing span metadata, recording +/// relationships between spans, and tracking which spans are active and which +/// are closed. In addition, it provides a mechanism for [subscriber]s to store +/// user-defined per-span data, called [extensions], in the registry. This +/// allows `Subscriber`-specific data to benefit from the `Registry`'s +/// high-performance concurrent storage. +/// +/// This registry is implemented using a [lock-free sharded slab][slab], and is +/// highly optimized for concurrent access. +/// +/// # Span ID Generation +/// +/// Span IDs are not globally unique, but the registry ensures that +/// no two currently active spans have the same ID within a process. +/// +/// One of the primary responsibilities of the registry is to generate [span +/// IDs]. Therefore, it's important for other code that interacts with the +/// registry, such as [subscriber]s, to understand the guarantees of the +/// span IDs that are generated. +/// +/// The registry's span IDs are guaranteed to be unique **at a given point +/// in time**. This means that an active span will never be assigned the +/// same ID as another **currently active** span. However, the registry +/// **will** eventually reuse the IDs of [closed] spans, although an ID +/// will never be reassigned immediately after a span has closed. +/// +/// Spans are not [considered closed] by the `Registry` until *every* +/// [`Span`] reference with that ID has been dropped. +/// +/// Thus: span IDs generated by the registry should be considered unique +/// only at a given point in time, and only relative to other spans +/// generated by the same process. Two spans with the same ID will not exist +/// in the same process concurrently. However, if historical span data is +/// being stored, the same ID may occur for multiple spans times in that +/// data. If spans must be uniquely identified in historical data, the user +/// code storing this data must assign its own unique identifiers to those +/// spans. A counter is generally sufficient for this. +/// +/// Similarly, span IDs generated by the registry are not unique outside of +/// a given process. Distributed tracing systems may require identifiers +/// that are unique across multiple processes on multiple machines (for +/// example, [OpenTelemetry's `SpanId`s and `TraceId`s][ot]). `tracing` span +/// IDs generated by the registry should **not** be used for this purpose. +/// Instead, code which integrates with a distributed tracing system should +/// generate and propagate its own IDs according to the rules specified by +/// the distributed tracing system. These IDs can be associated with +/// `tracing` spans using [fields] and/or [stored span data]. +/// +/// [span IDs]: https://docs.rs/tracing-core/latest/tracing_core/span/struct.Id.html +/// [slab]: https://docs.rs/crate/sharded-slab/ +/// [subscriber]: crate::Subscribe +/// [added]: crate::subscribe::Subscribe#composing-subscribers +/// [extensions]: super::Extensions +/// [closed]: https://docs.rs/tracing/latest/tracing/span/index.html#closing-spans +/// [considered closed]: https://docs.rs/tracing-core/latest/tracing_core/subscriber/trait.Subscriber.html#method.try_close +/// [`Span`]: https://docs.rs/tracing/latest/tracing/span/struct.Span.html +/// [ot]: https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#spancontext +/// [fields]: https://docs.rs/tracing-core/latest/tracing-core/field/index.html +/// [stored span data]: crate::registry::SpanData::extensions_mut +#[derive(Debug)] +#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))] +pub struct Registry { + spans: Pool, + current_spans: ThreadLocal>, +} + +/// Span data stored in a [`Registry`]. +/// +/// The registry stores well-known data defined by tracing: span relationships, +/// metadata and reference counts. Additional user-defined data provided by +/// [`Subscriber`s], such as formatted fields, metrics, or distributed traces should +/// be stored in the [extensions] typemap. +/// +/// [`Subscriber`s]: crate::Subscribe +/// [extensions]: Extensions +#[derive(Debug)] +pub struct Data<'a> { + /// Immutable reference to the pooled `DataInner` entry. + inner: Ref<'a, DataInner>, +} /// Stored data associated with a span. /// diff --git a/tracing-subscriber/src/subscribe.rs b/tracing-subscriber/src/subscribe.rs index 6c9673dad4..d0f5fef0a7 100644 --- a/tracing-subscriber/src/subscribe.rs +++ b/tracing-subscriber/src/subscribe.rs @@ -7,9 +7,16 @@ use tracing_core::{ span, Event, LevelFilter, }; -#[cfg(feature = "registry")] -use crate::registry::{self, LookupSpan, Registry, SpanRef}; -use std::{any::TypeId, marker::PhantomData, ops::Deref, ptr::NonNull}; +#[cfg(all(feature = "std", feature = "registry"))] +use crate::registry::Registry; +use crate::registry::{self, LookupSpan, SpanRef}; +use core::{any::TypeId, cmp, marker::PhantomData, ptr::NonNull}; + +feature! { + #![feature = "alloc"] + use alloc::boxed::Box; + use core::ops::Deref; +} /// A composable handler for `tracing` events. /// @@ -601,7 +608,7 @@ where } fn max_level_hint(&self) -> Option { - std::cmp::max( + cmp::max( self.subscriber.max_level_hint(), self.inner.max_level_hint(), ) @@ -652,16 +659,16 @@ where } fn try_close(&self, id: span::Id) -> bool { - #[cfg(feature = "registry")] + #[cfg(all(feature = "registry", feature = "std"))] let subscriber = &self.inner as &dyn Collect; - #[cfg(feature = "registry")] + #[cfg(all(feature = "registry", feature = "std"))] let mut guard = subscriber .downcast_ref::() .map(|registry| registry.start_close(id.clone())); if self.inner.try_close(id.clone()) { // If we have a registry's close guard, indicate that the span is // closing. - #[cfg(feature = "registry")] + #[cfg(all(feature = "registry", feature = "std"))] { if let Some(g) = guard.as_mut() { g.is_closing() @@ -884,88 +891,90 @@ where } } -macro_rules! subscriber_impl_body { - () => { - #[inline] - fn new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, C>) { - self.deref().new_span(attrs, id, ctx) - } +feature! { + #![any(feature = "std", feature = "alloc")] - #[inline] - fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { - self.deref().register_callsite(metadata) - } + macro_rules! subscriber_impl_body { + () => { + #[inline] + fn new_span(&self, attrs: &span::Attributes<'_>, id: &span::Id, ctx: Context<'_, C>) { + self.deref().new_span(attrs, id, ctx) + } - #[inline] - fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, C>) -> bool { - self.deref().enabled(metadata, ctx) - } + #[inline] + fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest { + self.deref().register_callsite(metadata) + } - #[inline] - fn max_level_hint(&self) -> Option { - self.deref().max_level_hint() - } + #[inline] + fn enabled(&self, metadata: &Metadata<'_>, ctx: Context<'_, C>) -> bool { + self.deref().enabled(metadata, ctx) + } - #[inline] - fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, C>) { - self.deref().on_record(span, values, ctx) - } + #[inline] + fn max_level_hint(&self) -> Option { + self.deref().max_level_hint() + } - #[inline] - fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: Context<'_, C>) { - self.deref().on_follows_from(span, follows, ctx) - } + #[inline] + fn on_record(&self, span: &span::Id, values: &span::Record<'_>, ctx: Context<'_, C>) { + self.deref().on_record(span, values, ctx) + } - #[inline] - fn on_event(&self, event: &Event<'_>, ctx: Context<'_, C>) { - self.deref().on_event(event, ctx) - } + #[inline] + fn on_follows_from(&self, span: &span::Id, follows: &span::Id, ctx: Context<'_, C>) { + self.deref().on_follows_from(span, follows, ctx) + } - #[inline] - fn on_enter(&self, id: &span::Id, ctx: Context<'_, C>) { - self.deref().on_enter(id, ctx) - } + #[inline] + fn on_event(&self, event: &Event<'_>, ctx: Context<'_, C>) { + self.deref().on_event(event, ctx) + } - #[inline] - fn on_exit(&self, id: &span::Id, ctx: Context<'_, C>) { - self.deref().on_exit(id, ctx) - } + #[inline] + fn on_enter(&self, id: &span::Id, ctx: Context<'_, C>) { + self.deref().on_enter(id, ctx) + } - #[inline] - fn on_close(&self, id: span::Id, ctx: Context<'_, C>) { - self.deref().on_close(id, ctx) - } + #[inline] + fn on_exit(&self, id: &span::Id, ctx: Context<'_, C>) { + self.deref().on_exit(id, ctx) + } - #[inline] - fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: Context<'_, C>) { - self.deref().on_id_change(old, new, ctx) - } + #[inline] + fn on_close(&self, id: span::Id, ctx: Context<'_, C>) { + self.deref().on_close(id, ctx) + } - #[doc(hidden)] - #[inline] - unsafe fn downcast_raw(&self, id: TypeId) -> std::option::Option> { - self.deref().downcast_raw(id) - } - }; -} + #[inline] + fn on_id_change(&self, old: &span::Id, new: &span::Id, ctx: Context<'_, C>) { + self.deref().on_id_change(old, new, ctx) + } -impl Subscribe for Box -where - S: Subscribe, - C: Collect, -{ - subscriber_impl_body! {} -} + #[doc(hidden)] + #[inline] + unsafe fn downcast_raw(&self, id: TypeId) -> Option> { + self.deref().downcast_raw(id) + } + }; + } -impl Subscribe for Box + Send + Sync> -where - C: Collect, -{ - subscriber_impl_body! {} + impl Subscribe for Box + where + S: Subscribe, + C: Collect, + { + subscriber_impl_body! {} + } + + impl Subscribe for Box + Send + Sync> + where + C: Collect, + { + subscriber_impl_body! {} + } } -#[cfg(feature = "registry")] -#[cfg_attr(docsrs, doc(cfg(feature = "registry")))] impl<'a, S, C> LookupSpan<'a> for Layered where C: Collect + LookupSpan<'a>, @@ -1111,8 +1120,6 @@ where /// declaration for details. /// #[inline] - #[cfg(feature = "registry")] - #[cfg_attr(docsrs, doc(cfg(feature = "registry")))] pub fn event_span(&self, event: &Event<'_>) -> Option> where C: for<'lookup> LookupSpan<'lookup>, @@ -1131,8 +1138,6 @@ where /// If this returns `None`, then no span exists for that ID (either it has /// closed or the ID is invalid). #[inline] - #[cfg(feature = "registry")] - #[cfg_attr(docsrs, doc(cfg(feature = "registry")))] pub fn metadata(&self, id: &span::Id) -> Option<&'static Metadata<'static>> where C: for<'lookup> LookupSpan<'lookup>, @@ -1156,8 +1161,6 @@ where /// /// [stored data]: super::registry::SpanRef #[inline] - #[cfg(feature = "registry")] - #[cfg_attr(docsrs, doc(cfg(feature = "registry")))] pub fn span(&self, id: &span::Id) -> Option> where C: for<'lookup> LookupSpan<'lookup>, @@ -1175,8 +1178,6 @@ where /// /// #[inline] - #[cfg(feature = "registry")] - #[cfg_attr(docsrs, doc(cfg(feature = "registry")))] pub fn exists(&self, id: &span::Id) -> bool where C: for<'lookup> LookupSpan<'lookup>, @@ -1199,8 +1200,6 @@ where /// /// [stored data]: super::registry::SpanRef #[inline] - #[cfg(feature = "registry")] - #[cfg_attr(docsrs, doc(cfg(feature = "registry")))] pub fn lookup_current(&self) -> Option> where C: for<'lookup> LookupSpan<'lookup>, @@ -1241,8 +1240,6 @@ where /// /// /// [stored data]: ../registry/struct.SpanRef.html - #[cfg(feature = "registry")] - #[cfg_attr(docsrs, doc(cfg(feature = "registry")))] pub fn span_scope(&self, id: &span::Id) -> Option> where C: for<'lookup> registry::LookupSpan<'lookup>, @@ -1271,8 +1268,6 @@ where /// /// /// [stored data]: ../registry/struct.SpanRef.html - #[cfg(feature = "registry")] - #[cfg_attr(docsrs, doc(cfg(feature = "registry")))] pub fn event_scope(&self, event: &Event<'_>) -> Option> where C: for<'lookup> registry::LookupSpan<'lookup>, @@ -1308,7 +1303,6 @@ impl Identity { #[cfg(test)] pub(crate) mod tests { - use super::*; pub(crate) struct NopCollector; @@ -1346,15 +1340,16 @@ pub(crate) mod tests { /// A subscriber that holds a string. /// /// Used to test that pointers returned by downcasting are actually valid. - struct StringSubscriber(String); + struct StringSubscriber(&'static str); impl Subscribe for StringSubscriber {} - struct StringSubscriber2(String); + + struct StringSubscriber2(&'static str); impl Subscribe for StringSubscriber2 {} - struct StringSubscriber3(String); + struct StringSubscriber3(&'static str); impl Subscribe for StringSubscriber3 {} - pub(crate) struct StringCollector(String); + pub(crate) struct StringCollector(&'static str); impl Collect for StringCollector { fn register_callsite(&self, _: &'static Metadata<'static>) -> Interest { @@ -1409,31 +1404,31 @@ pub(crate) mod tests { let s = NopSubscriber .and_then(NopSubscriber) .and_then(NopSubscriber) - .with_collector(StringCollector("collector".into())); + .with_collector(StringCollector("collector")); let collector = ::downcast_ref::(&s).expect("collector should downcast"); - assert_eq!(&collector.0, "collector"); + assert_eq!(collector.0, "collector"); } #[test] fn downcasts_to_subscriber() { - let s = StringSubscriber("subscriber_1".into()) - .and_then(StringSubscriber2("subscriber_2".into())) - .and_then(StringSubscriber3("subscriber_3".into())) + let s = StringSubscriber("subscriber_1") + .and_then(StringSubscriber2("subscriber_2")) + .and_then(StringSubscriber3("subscriber_3")) .with_collector(NopCollector); let subscriber = ::downcast_ref::(&s) .expect("subscriber 2 should downcast"); - assert_eq!(&subscriber.0, "subscriber_1"); + assert_eq!(subscriber.0, "subscriber_1"); let subscriber = ::downcast_ref::(&s) .expect("subscriber 2 should downcast"); - assert_eq!(&subscriber.0, "subscriber_2"); + assert_eq!(subscriber.0, "subscriber_2"); let subscriber = ::downcast_ref::(&s) .expect("subscriber 3 should downcast"); - assert_eq!(&subscriber.0, "subscriber_3"); + assert_eq!(subscriber.0, "subscriber_3"); } #[test] - #[cfg(feature = "registry")] + #[cfg(all(feature = "registry", feature = "std"))] fn context_event_span() { use std::sync::{Arc, Mutex}; let last_event_span = Arc::new(Mutex::new(None)); diff --git a/tracing-subscriber/src/util.rs b/tracing-subscriber/src/util.rs index 42a9fcfd98..f17a7c5b39 100644 --- a/tracing-subscriber/src/util.rs +++ b/tracing-subscriber/src/util.rs @@ -1,6 +1,8 @@ //! Extension traits and other utilities to make working with subscribers more //! ergonomic. -use std::{error::Error, fmt}; +use core::fmt; +#[cfg(feature = "std")] +use std::error::Error; use tracing_core::dispatch::{self, Dispatch}; #[cfg(feature = "tracing-log")] use tracing_log::AsLog; @@ -31,6 +33,8 @@ where /// /// [default subscriber]: tracing::dispatch#setting-the-default-collector /// [`log`]: https://crates.io/log + #[cfg(feature = "std")] + #[cfg_attr(docsrs, doc(cfg(feature = "std")))] fn set_default(self) -> dispatch::DefaultGuard { #[cfg(feature = "tracing-log")] let _ = tracing_log::LogTracer::init(); @@ -92,29 +96,56 @@ impl SubscriberInitExt for T where T: Into {} /// Error returned by [`try_init`](SubscriberInitExt::try_init) if a global default subscriber could not be initialized. pub struct TryInitError { + #[cfg(feature = "std")] inner: Box, + + #[cfg(not(feature = "std"))] + _p: (), } // ==== impl TryInitError ==== impl TryInitError { + #[cfg(feature = "std")] fn new(e: impl Into>) -> Self { Self { inner: e.into() } } + + #[cfg(not(feature = "std"))] + fn new(_: T) -> Self { + Self { _p: () } + } } impl fmt::Debug for TryInitError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Debug::fmt(&self.inner, f) + #[cfg(feature = "std")] + { + fmt::Debug::fmt(&self.inner, f) + } + + #[cfg(not(feature = "std"))] + { + f.write_str("TryInitError(())") + } } } impl fmt::Display for TryInitError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(&self.inner, f) + #[cfg(feature = "std")] + { + fmt::Display::fmt(&self.inner, f) + } + + #[cfg(not(feature = "std"))] + { + f.write_str("failed to set global default subscriber") + } } } +#[cfg(feature = "std")] impl Error for TryInitError { fn source(&self) -> Option<&(dyn Error + 'static)> { self.inner.source() diff --git a/tracing-subscriber/tests/utils.rs b/tracing-subscriber/tests/utils.rs index c3deeb2852..3e3506cb02 100644 --- a/tracing-subscriber/tests/utils.rs +++ b/tracing-subscriber/tests/utils.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "std")] mod support; use self::support::*; use tracing_subscriber::prelude::*;