Skip to content

Commit

Permalink
subscriber: add minimal #![no_std] support (#1648)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
hawkw committed Oct 19, 2021
1 parent ae37598 commit 226f605
Show file tree
Hide file tree
Showing 20 changed files with 448 additions and 326 deletions.
2 changes: 1 addition & 1 deletion tracing-opentelemetry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
6 changes: 4 additions & 2 deletions tracing-subscriber/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand All @@ -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" }
Expand Down
24 changes: 15 additions & 9 deletions tracing-subscriber/src/field/debug.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -84,13 +84,19 @@ where
}
}

impl<V> VisitWrite for Alt<V>
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<V> VisitWrite for Alt<V>
where
V: VisitWrite,
{
#[inline]
fn writer(&mut self) -> &mut dyn io::Write {
self.0.writer()
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion tracing-subscriber/src/field/delimited.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -133,6 +133,7 @@ where
}

#[cfg(test)]
#[cfg(all(test, feature = "alloc"))]
mod test {
use super::*;
use crate::field::test_util::*;
Expand Down
24 changes: 15 additions & 9 deletions tracing-subscriber/src/field/display.rs
Original file line number Diff line number Diff line change
@@ -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`
Expand Down Expand Up @@ -90,13 +90,19 @@ where
}
}

impl<V> VisitWrite for Messages<V>
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<V> VisitWrite for Messages<V>
where
V: VisitWrite,
{
#[inline]
fn writer(&mut self) -> &mut dyn io::Write {
self.0.writer()
}
}
}

Expand Down
22 changes: 14 additions & 8 deletions tracing-subscriber/src/field/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down Expand Up @@ -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<Result<(), io::Error>> {
/// 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<Result<(), io::Error>> {
/// 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
Expand Down Expand Up @@ -223,7 +228,7 @@ where
#[derive(Debug)]
#[doc(hidden)]
pub struct MakeExtMarker<T> {
_p: std::marker::PhantomData<T>,
_p: PhantomData<T>,
}

#[derive(Debug)]
Expand All @@ -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},
Expand Down
5 changes: 2 additions & 3 deletions tracing-subscriber/src/filter/env/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -121,7 +120,7 @@ type FilterVec<T> = Vec<T>;

/// 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,
Expand Down
10 changes: 5 additions & 5 deletions tracing-subscriber/src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
}
1 change: 1 addition & 0 deletions tracing-subscriber/src/fmt/fmt_subscriber.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<C, N = format::DefaultFields, E = format::Format, W = fn() -> io::Stdout> {
make_writer: W,
fmt_fields: N,
Expand Down
8 changes: 8 additions & 0 deletions tracing-subscriber/src/fmt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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,
Expand All @@ -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<N = format::DefaultFields, E = format::Format, W = fn() -> io::Stdout> =
subscribe::Layered<fmt_subscriber::Subscriber<Registry, N, E, W>, 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,
Expand Down Expand Up @@ -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()
}
Expand All @@ -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<C>() -> Subscriber<C> {
Subscriber::default()
}
Expand Down
11 changes: 7 additions & 4 deletions tracing-subscriber/src/fmt/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! [`io::Write`]: std::io::Write

use std::{
fmt::{self, Debug},
fmt,
io::{self, Write},
sync::{Mutex, MutexGuard},
};
Expand Down Expand Up @@ -642,6 +642,7 @@ pub struct Tee<A, B> {
/// `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,
}
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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<usize> {
let s =
Expand All @@ -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 { .. }")
Expand Down
Loading

0 comments on commit 226f605

Please sign in to comment.