Skip to content

Commit

Permalink
subscriber: add minimal #![no_std] support (tokio-rs#1648)
Browse files Browse the repository at this point in the history
Backports tokio-rs#1648 from `master`.

Depends on tokio-rs#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 `Layer` 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 `Layer` and `LookupSpan` traits are now available with
`#![no_std]`.

Fixes tokio-rs#999

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
  • Loading branch information
hawkw authored and kaffarell committed May 22, 2024
1 parent c6096c8 commit f153919
Show file tree
Hide file tree
Showing 10 changed files with 307 additions and 401 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ jobs:
run: cargo test --no-default-features
# this skips running doctests under the `--no-default-features` flag,
# as rustdoc isn't aware of cargo's feature flags.
- name: "Test tracing-subscriber with all features disabled"
- name: "Test tracing-subscriber no-std support"
run: cargo test --lib --tests --no-default-features

# all required checks except for the main test run (which we only require
Expand Down
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.1", default-features = false, features = ["std"] }
tracing-core = { path = "../tracing-core", version = "0.1" }
tracing-subscriber = { path = "../tracing-subscriber", version = "0.2", default-features = false, features = ["registry"] }
tracing-subscriber = { path = "../tracing-subscriber", version = "0.2", default-features = false, features = ["registry", "std"] }
tracing-log = { path = "../tracing-log", version = "0.1", default-features = false, optional = true }

[dev-dependencies]
Expand Down
1 change: 0 additions & 1 deletion tracing-subscriber/src/filter/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
//! [`Subscribe`]: crate::subscribe
mod filter_fn;
mod level;
pub mod targets;

feature! {
#![all(feature = "env-filter", feature = "std")]
Expand Down
18 changes: 1 addition & 17 deletions tracing-subscriber/src/fmt/fmt_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ use tracing_core::{
/// ```
///
/// [`Layer`]: ../layer/trait.Layer.html
#[cfg_attr(docsrs, doc(cfg(all(feature = "fmt", feature = "std"))))]
#[derive(Debug)]
pub struct Layer<
S,
Expand Down Expand Up @@ -864,23 +865,6 @@ where
self.ctx.lookup_current()
}

/// Returns an iterator over the [stored data] for all the spans in the
/// current context, starting the root of the trace tree and ending with
/// the current span.
///
/// [stored data]: ../registry/struct.SpanRef.html
#[deprecated(
note = "wraps layer::Context::scope, which is deprecated",
since = "0.2.19"
)]
#[allow(deprecated)]
pub fn scope(&self) -> crate::layer::Scope<'_, S>
where
S: for<'lookup> LookupSpan<'lookup>,
{
self.ctx.scope()
}

/// Returns the current span for this formatter.
pub fn current_span(&self) -> Current {
self.ctx.current_span()
Expand Down
1 change: 1 addition & 0 deletions tracing-subscriber/src/fmt/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ pub(in crate::fmt) struct WriteAdaptor<'a> {
/// `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
81 changes: 11 additions & 70 deletions tracing-subscriber/src/layer/context.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use tracing_core::{metadata::Metadata, span, subscriber::Subscriber, Event};

use crate::registry::{self, LookupSpan, SpanRef};
#[cfg(feature = "registry")]

#[cfg(all(feature = "registry", feature = "std"))]
use crate::{filter::FilterId, registry::Registry};
/// Represents information about the current context provided to [`Layer`]s by the
/// wrapped [`Subscriber`].
Expand Down Expand Up @@ -41,36 +42,10 @@ pub struct Context<'a, S> {
/// [`Filtered`]: crate::filter::Filtered
/// [`FilterId`]: crate::filter::FilterId
/// [`and`]: crate::filter::FilterId::and
#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
filter: FilterId,
}

/// An iterator over the [stored data] for all the spans in the
/// current context, starting the root of the trace tree and ending with
/// the current span.
///
/// This is returned by [`Context::scope`].
///
/// [stored data]: ../registry/struct.SpanRef.html
/// [`Context::scope`]: struct.Context.html#method.scope
#[deprecated(note = "renamed to crate::registry::ScopeFromRoot", since = "0.2.19")]
#[derive(Debug)]
pub struct Scope<'a, L>(std::iter::Flatten<std::option::IntoIter<registry::ScopeFromRoot<'a, L>>>)
where
L: LookupSpan<'a>;

#[allow(deprecated)]
impl<'a, L> Iterator for Scope<'a, L>
where
L: LookupSpan<'a>,
{
type Item = SpanRef<'a, L>;

fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
}

// === impl Context ===

impl<'a, S> Context<'a, S>
Expand Down Expand Up @@ -239,7 +214,7 @@ where
{
let span = self.subscriber.as_ref()?.span(id)?;

#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
return span.try_with_filter(self.filter);

#[cfg(not(feature = "registry"))]
Expand Down Expand Up @@ -294,7 +269,7 @@ where

// If we found a span, and our per-layer filter enables it, return that
// span!
#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
{
if let Some(span) = span?.try_with_filter(self.filter) {
Some(span)
Expand Down Expand Up @@ -324,7 +299,7 @@ where
// factored out to prevent the loop and (potentially-recursive) subscriber
// downcasting from being inlined if `lookup_current` is inlined.
#[inline(never)]
#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
fn lookup_current_filtered<'lookup>(
&self,
subscriber: &'lookup S,
Expand All @@ -339,40 +314,6 @@ where
.find_map(|id| subscriber.span(id)?.try_with_filter(self.filter))
}

/// Returns an iterator over the [stored data] for all the spans in the
/// current context, starting the root of the trace tree and ending with
/// the current span.
///
/// If this iterator is empty, then there are no spans in the current context.
///
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// <strong>Note</strong>: This requires the wrapped subscriber to
/// implement the <a href="../registry/trait.LookupSpan.html"><code>
/// LookupSpan</code></a> trait. See the documentation on
/// <a href="./struct.Context.html"><code>Context</code>'s
/// declaration</a> for details.
/// </pre>
///
/// [stored data]: ../registry/struct.SpanRef.html
#[deprecated(
note = "equivalent to `self.current_span().id().and_then(|id| self.span_scope(id).from_root())` but consider passing an explicit ID instead of relying on the contextual span",
since = "0.2.19"
)]
#[allow(deprecated)]
pub fn scope(&self) -> Scope<'_, S>
where
S: for<'lookup> LookupSpan<'lookup>,
{
Scope(
self.lookup_current()
.as_ref()
.map(registry::SpanRef::scope)
.map(registry::Scope::from_root)
.into_iter()
.flatten(),
)
}

/// Returns an iterator over the [stored data] for all the spans in the
/// current context, starting with the specified span and ending with the
/// root of the trace tree and ending with the current span.
Expand Down Expand Up @@ -427,7 +368,7 @@ where
Some(self.event_span(event)?.scope())
}

#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn with_filter(self, filter: FilterId) -> Self {
// If we already have our own `FilterId`, combine it with the provided
// one. That way, the new `FilterId` will consider a span to be disabled
Expand All @@ -439,15 +380,15 @@ where
Self { filter, ..self }
}

#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn is_enabled_for(&self, span: &span::Id, filter: FilterId) -> bool
where
S: for<'lookup> LookupSpan<'lookup>,
{
self.is_enabled_inner(span, filter).unwrap_or(false)
}

#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
pub(crate) fn if_enabled_for(self, span: &span::Id, filter: FilterId) -> Option<Self>
where
S: for<'lookup> LookupSpan<'lookup>,
Expand All @@ -459,7 +400,7 @@ where
}
}

#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
fn is_enabled_inner(&self, span: &span::Id, filter: FilterId) -> Option<bool>
where
S: for<'lookup> LookupSpan<'lookup>,
Expand All @@ -486,7 +427,7 @@ impl<'a, S> Clone for Context<'a, S> {
Context {
subscriber,

#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
filter: self.filter,
}
}
Expand Down
28 changes: 14 additions & 14 deletions tracing-subscriber/src/layer/layered.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ use crate::{
layer::{Context, Layer},
registry::LookupSpan,
};
#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
use crate::{filter::FilterId, registry::Registry};
use std::{any::TypeId, fmt, marker::PhantomData};
use core::{any::TypeId, cmp, fmt, marker::PhantomData};

/// A [`Subscriber`] composed of a `Subscriber` wrapped by one or more
/// [`Layer`]s.
Expand Down Expand Up @@ -140,16 +140,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 Subscriber;
#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
let mut guard = subscriber
.downcast_ref::<Registry>()
.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()
Expand Down Expand Up @@ -335,7 +335,7 @@ where
self.inner.span_data(id)
}

#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
fn register_filter(&mut self) -> FilterId {
self.inner.register_filter()
}
Expand All @@ -356,9 +356,10 @@ where
S: Subscriber,
{
pub(super) fn new(layer: A, inner: B, inner_has_layer_filter: bool) -> Self {
#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
let inner_is_registry = TypeId::of::<S>() == TypeId::of::<crate::registry::Registry>();
#[cfg(not(feature = "registry"))]

#[cfg(not(all(feature = "registry", feature = "std")))]
let inner_is_registry = false;

let inner_has_layer_filter = inner_has_layer_filter || inner_is_registry;
Expand Down Expand Up @@ -421,14 +422,12 @@ where
outer_hint: Option<LevelFilter>,
inner_hint: Option<LevelFilter>,
) -> Option<LevelFilter> {
use std::cmp::max;

if self.inner_is_registry {
return outer_hint;
}

if self.has_layer_filter && self.inner_has_layer_filter {
return Some(max(outer_hint?, inner_hint?));
return Some(cmp::max(outer_hint?, inner_hint?));
}

if self.has_layer_filter && inner_hint.is_none() {
Expand All @@ -439,7 +438,7 @@ where
return None;
}

max(outer_hint, inner_hint)
cmp::max(outer_hint, inner_hint)
}
}

Expand All @@ -449,13 +448,14 @@ where
B: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[cfg(feature = "registry")]
#[cfg(all(feature = "registry", feature = "std"))]
let alt = f.alternate();
let mut s = f.debug_struct("Layered");
// These additional fields are more verbose and usually only necessary
// for internal debugging purposes, so only print them if alternate mode
// is enabled.
#[cfg(feature = "registry")]

#[cfg(all(feature = "registry", feature = "std"))]
{
if alt {
s.field("inner_is_registry", &self.inner_is_registry)
Expand Down
Loading

0 comments on commit f153919

Please sign in to comment.