Skip to content

Commit 226f605

Browse files
authored
subscriber: add minimal #![no_std] support (#1648)
Depends on #1649 ## Motivation Presently, the `tracing-subscriber` crate requires the Rust standard library and doesn't build with `#![no_std]` targets. For the most part, this is fine, as much of `tracing-subscriber` inherently depends on `std` APIs. However, `tracing-subscriber` also contains some key abstractions that are necessary for interoperability: the `Subscriber` and `LookupSpan` traits. Since these traits are in `tracing-subscriber`, `no-std` users cannot currently access them. Some of the other utilities in this crate, such as the field visitor combinators, may also be useful for `#![no_std]` projects. ## Solution This branch adds "std" and "alloc" feature flags to `tracing-subscriber`, for conditionally enabling `libstd` and `liballoc`, respectively. The `registry`, `fmt`, `EnvFilter`, and `reload` APIs all require libstd, and cannot be implemented without it, but the core `Subscribe` and `LookupSpan` traits are now available with `#![no_std]`. Fixes #999 Signed-off-by: Eliza Weisman <eliza@buoyant.io>
1 parent ae37598 commit 226f605

File tree

20 files changed

+448
-326
lines changed

20 files changed

+448
-326
lines changed

tracing-opentelemetry/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ default = ["tracing-log"]
2525
opentelemetry = { version = "0.16", default-features = false, features = ["trace"] }
2626
tracing = { path = "../tracing", version = "0.2", default-features = false, features = ["std"] }
2727
tracing-core = { path = "../tracing-core", version = "0.2" }
28-
tracing-subscriber = { path = "../tracing-subscriber", version = "0.3", default-features = false, features = ["registry"] }
28+
tracing-subscriber = { path = "../tracing-subscriber", version = "0.3", default-features = false, features = ["registry", "std"] }
2929
tracing-log = { path = "../tracing-log", version = "0.2", default-features = false, optional = true }
3030

3131
[dev-dependencies]

tracing-subscriber/Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ keywords = ["logging", "tracing", "metrics", "subscriber"]
2323

2424
[features]
2525

26-
default = ["smallvec", "fmt", "ansi", "tracing-log"]
26+
default = ["smallvec", "fmt", "ansi", "tracing-log", "std"]
27+
alloc = []
28+
std = ["alloc", "tracing-core/std"]
2729
env-filter = ["matchers", "regex", "lazy_static", "tracing"]
2830
fmt = ["registry"]
2931
ansi = ["fmt", "ansi_term"]
@@ -37,7 +39,7 @@ local-time = ["time/local-offset"]
3739
tracing-core = { path = "../tracing-core", version = "0.2" }
3840

3941
# only required by the `env-filter` feature
40-
tracing = { optional = true, path = "../tracing", version = "0.2", default-features = false, features = ["std"] }
42+
tracing = { optional = true, path = "../tracing", version = "0.2", default-features = false }
4143
matchers = { optional = true, version = "0.1.0" }
4244
regex = { optional = true, version = "1", default-features = false, features = ["std"] }
4345
smallvec = { optional = true, version = "1" }

tracing-subscriber/src/field/debug.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! `MakeVisitor` wrappers for working with `fmt::Debug` fields.
2-
use super::{MakeVisitor, VisitFmt, VisitOutput, VisitWrite};
2+
use super::{MakeVisitor, VisitFmt, VisitOutput};
33
use tracing_core::field::{Field, Visit};
44

5-
use std::{fmt, io};
5+
use core::fmt;
66

77
/// A visitor wrapper that ensures any `fmt::Debug` fields are formatted using
88
/// the alternate (`:#`) formatter.
@@ -84,13 +84,19 @@ where
8484
}
8585
}
8686

87-
impl<V> VisitWrite for Alt<V>
88-
where
89-
V: VisitWrite,
90-
{
91-
#[inline]
92-
fn writer(&mut self) -> &mut dyn io::Write {
93-
self.0.writer()
87+
feature! {
88+
#![feature = "std"]
89+
use super::VisitWrite;
90+
use std::io;
91+
92+
impl<V> VisitWrite for Alt<V>
93+
where
94+
V: VisitWrite,
95+
{
96+
#[inline]
97+
fn writer(&mut self) -> &mut dyn io::Write {
98+
self.0.writer()
99+
}
94100
}
95101
}
96102

tracing-subscriber/src/field/delimited.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! A `MakeVisitor` wrapper that separates formatted fields with a delimiter.
22
use super::{MakeVisitor, VisitFmt, VisitOutput};
33

4-
use std::fmt;
4+
use core::fmt;
55
use tracing_core::field::{Field, Visit};
66

77
/// A `MakeVisitor` wrapper that wraps a visitor that writes formatted output so
@@ -133,6 +133,7 @@ where
133133
}
134134

135135
#[cfg(test)]
136+
#[cfg(all(test, feature = "alloc"))]
136137
mod test {
137138
use super::*;
138139
use crate::field::test_util::*;

tracing-subscriber/src/field/display.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! `MakeVisitor` wrappers for working with `fmt::Display` fields.
2-
use super::{MakeVisitor, VisitFmt, VisitOutput, VisitWrite};
2+
use super::{MakeVisitor, VisitFmt, VisitOutput};
33
use tracing_core::field::{Field, Visit};
44

5-
use std::{fmt, io};
5+
use core::fmt;
66

77
/// A visitor wrapper that ensures any strings named "message" are formatted
88
/// using `fmt::Display`
@@ -90,13 +90,19 @@ where
9090
}
9191
}
9292

93-
impl<V> VisitWrite for Messages<V>
94-
where
95-
V: VisitWrite,
96-
{
97-
#[inline]
98-
fn writer(&mut self) -> &mut dyn io::Write {
99-
self.0.writer()
93+
feature! {
94+
#![feature = "std"]
95+
use super::VisitWrite;
96+
use std::io;
97+
98+
impl<V> VisitWrite for Messages<V>
99+
where
100+
V: VisitWrite,
101+
{
102+
#[inline]
103+
fn writer(&mut self) -> &mut dyn io::Write {
104+
self.0.writer()
105+
}
100106
}
101107
}
102108

tracing-subscriber/src/field/mod.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//!
33
//! [fields]: tracing_core::field
44
//! [field visitors]: tracing_core::field::Visit
5-
use std::{fmt, io};
5+
use core::{fmt, marker::PhantomData};
66
pub use tracing_core::field::Visit;
77
use tracing_core::{
88
span::{Attributes, Record},
@@ -108,11 +108,16 @@ where
108108
}
109109
}
110110

111-
/// Extension trait implemented by visitors to indicate that they write to an
112-
/// `io::Write` instance, and allow access to that writer.
113-
pub trait VisitWrite: VisitOutput<Result<(), io::Error>> {
114-
/// Returns the writer that this visitor writes to.
115-
fn writer(&mut self) -> &mut dyn io::Write;
111+
feature! {
112+
#![feature = "std"]
113+
use std::io;
114+
115+
/// Extension trait implemented by visitors to indicate that they write to an
116+
/// `io::Write` instance, and allow access to that writer.
117+
pub trait VisitWrite: VisitOutput<Result<(), io::Error>> {
118+
/// Returns the writer that this visitor writes to.
119+
fn writer(&mut self) -> &mut dyn io::Write;
120+
}
116121
}
117122

118123
/// Extension trait implemented by visitors to indicate that they write to a
@@ -223,7 +228,7 @@ where
223228
#[derive(Debug)]
224229
#[doc(hidden)]
225230
pub struct MakeExtMarker<T> {
226-
_p: std::marker::PhantomData<T>,
231+
_p: PhantomData<T>,
227232
}
228233

229234
#[derive(Debug)]
@@ -232,10 +237,11 @@ pub struct RecordFieldsMarker {
232237
_p: (),
233238
}
234239

235-
#[cfg(test)]
240+
#[cfg(all(test, feature = "alloc"))]
236241
#[macro_use]
237242
pub(in crate::field) mod test_util {
238243
use super::*;
244+
pub(in crate::field) use alloc::string::String;
239245
use tracing_core::{
240246
callsite::Callsite,
241247
field::{Field, Value},

tracing-subscriber/src/filter/env/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ use tracing_core::{
9797
/// [`Event`]: tracing_core::Event
9898
/// [`level`]: tracing_core::Level
9999
/// [`Metadata`]: tracing_core::Metadata
100-
#[cfg(feature = "env-filter")]
101-
#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
100+
#[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))]
102101
#[derive(Debug)]
103102
pub struct EnvFilter {
104103
statics: directive::Statics,
@@ -121,7 +120,7 @@ type FilterVec<T> = Vec<T>;
121120

122121
/// Indicates that an error occurred while parsing a `EnvFilter` from an
123122
/// environment variable.
124-
#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
123+
#[cfg_attr(docsrs, doc(cfg(all(feature = "env-filter", feature = "std"))))]
125124
#[derive(Debug)]
126125
pub struct FromEnvError {
127126
kind: ErrorKind,

tracing-subscriber/src/filter/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
//! subscriber.
33
//!
44
//! [`Subscriber`]: crate::fmt::Subscriber
5-
#[cfg(feature = "env-filter")]
6-
mod env;
75
mod level;
86

97
pub use self::level::{LevelFilter, ParseError as LevelParseError};
108

11-
#[cfg(feature = "env-filter")]
12-
#[cfg_attr(docsrs, doc(cfg(feature = "env-filter")))]
13-
pub use self::env::*;
9+
feature! {
10+
#![all(feature = "env-filter", feature = "std")]
11+
mod env;
12+
pub use self::env::*;
13+
}

tracing-subscriber/src/fmt/fmt_subscriber.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ use tracing_core::{
6161
///
6262
/// [`Subscriber`]: subscribe::Subscribe
6363
#[derive(Debug)]
64+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
6465
pub struct Subscriber<C, N = format::DefaultFields, E = format::Format, W = fn() -> io::Stdout> {
6566
make_writer: W,
6667
fmt_fields: N,

tracing-subscriber/src/fmt/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,11 @@ use std::{any::TypeId, error::Error, io, ptr::NonNull};
288288
use tracing_core::{collect::Interest, span, Event, Metadata};
289289

290290
mod fmt_subscriber;
291+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
291292
pub mod format;
293+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
292294
pub mod time;
295+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
293296
pub mod writer;
294297
pub use fmt_subscriber::{FmtContext, FormattedFields, Subscriber};
295298

@@ -311,6 +314,7 @@ pub use self::{
311314
///
312315
/// This consists of an inner `Formatter` wrapped in a subscriber that performs filtering.
313316
#[derive(Debug)]
317+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
314318
pub struct Collector<
315319
N = format::DefaultFields,
316320
E = format::Format,
@@ -322,11 +326,13 @@ pub struct Collector<
322326

323327
/// A collector that logs formatted representations of `tracing` events.
324328
/// This type only logs formatted events; it does not perform any filtering.
329+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
325330
pub type Formatter<N = format::DefaultFields, E = format::Format, W = fn() -> io::Stdout> =
326331
subscribe::Layered<fmt_subscriber::Subscriber<Registry, N, E, W>, Registry>;
327332

328333
/// Configures and constructs `Collector`s.
329334
#[derive(Debug)]
335+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
330336
pub struct CollectorBuilder<
331337
N = format::DefaultFields,
332338
E = format::Format,
@@ -400,6 +406,7 @@ pub struct CollectorBuilder<
400406
/// [`init`]: CollectorBuilder::init()
401407
/// [`try_init`]: CollectorBuilder::try_init()
402408
/// [`finish`]: CollectorBuilder::finish()
409+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
403410
pub fn fmt() -> CollectorBuilder {
404411
CollectorBuilder::default()
405412
}
@@ -411,6 +418,7 @@ pub fn fmt() -> CollectorBuilder {
411418
///
412419
/// [formatting subscriber]: Subscriber
413420
/// [composed]: super::subscribe
421+
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
414422
pub fn subscriber<C>() -> Subscriber<C> {
415423
Subscriber::default()
416424
}

0 commit comments

Comments
 (0)