Add support for updating the tracing subscriber in LogPlugin (#10822)

# Objective

This PR is heavily inspired by
https://github.com/bevyengine/bevy/pull/7682
It aims to solve the same problem: allowing the user to extend the
tracing subscriber with extra layers.

(in my case, I'd like to use `use
metrics_tracing_context::{MetricsLayer, TracingContextLayer};`)


## Solution

I'm proposing a different api where the user has the opportunity to take
the existing `subscriber` and apply any transformations on it.

---

## Changelog

- Added a `update_subscriber` option on the `LogPlugin` that lets the
user modify the `subscriber` (for example to extend it with more tracing
`Layers`


## Migration Guide

> This section is optional. If there are no breaking changes, you can
delete this section.

- Added a new field `update_subscriber` in the `LogPlugin`

---------

Co-authored-by: Charles Bournhonesque <cbournhonesque@snapchat.com>
This commit is contained in:
Charles Bournhonesque 2024-01-15 10:26:13 -05:00 committed by GitHub
parent 8a523de8db
commit 8c6d9b8103
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 1 deletions

View file

@ -1035,6 +1035,16 @@ description = "Illustrate how to use generate log output"
category = "Application" category = "Application"
wasm = true wasm = true
[[example]]
name = "log_layers"
path = "examples/app/log_layers.rs"
[package.metadata.example.log_layers]
name = "Log layers"
description = "Illustrate how to add custom log layers"
category = "Application"
wasm = false
[[example]] [[example]]
name = "plugin" name = "plugin"
path = "examples/app/plugin.rs" path = "examples/app/plugin.rs"

View file

@ -38,8 +38,10 @@ pub use bevy_utils::tracing::{
debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn, warn_span, debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn, warn_span,
Level, Level,
}; };
pub use tracing_subscriber;
use bevy_app::{App, Plugin}; use bevy_app::{App, Plugin};
use bevy_utils::tracing::Subscriber;
use tracing_log::LogTracer; use tracing_log::LogTracer;
#[cfg(feature = "tracing-chrome")] #[cfg(feature = "tracing-chrome")]
use tracing_subscriber::fmt::{format::DefaultFields, FormattedFields}; use tracing_subscriber::fmt::{format::DefaultFields, FormattedFields};
@ -64,6 +66,7 @@ use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter};
/// .add_plugins(DefaultPlugins.set(LogPlugin { /// .add_plugins(DefaultPlugins.set(LogPlugin {
/// level: Level::DEBUG, /// level: Level::DEBUG,
/// filter: "wgpu=error,bevy_render=info,bevy_ecs=trace".to_string(), /// filter: "wgpu=error,bevy_render=info,bevy_ecs=trace".to_string(),
/// update_subscriber: None,
/// })) /// }))
/// .run(); /// .run();
/// } /// }
@ -100,13 +103,21 @@ pub struct LogPlugin {
/// Filters out logs that are "less than" the given level. /// Filters out logs that are "less than" the given level.
/// This can be further filtered using the `filter` setting. /// This can be further filtered using the `filter` setting.
pub level: Level, pub level: Level,
/// Optionally apply extra transformations to the tracing subscriber.
/// For example add [`Layers`](tracing_subscriber::layer::Layer)
pub update_subscriber: Option<fn(BoxedSubscriber) -> BoxedSubscriber>,
} }
/// Alias for a boxed [`Subscriber`].
pub type BoxedSubscriber = Box<dyn Subscriber + Send + Sync + 'static>;
impl Default for LogPlugin { impl Default for LogPlugin {
fn default() -> Self { fn default() -> Self {
Self { Self {
filter: "wgpu=error,naga=warn".to_string(), filter: "wgpu=error,naga=warn".to_string(),
level: Level::INFO, level: Level::INFO,
update_subscriber: None,
} }
} }
} }
@ -179,7 +190,11 @@ impl Plugin for LogPlugin {
#[cfg(feature = "tracing-tracy")] #[cfg(feature = "tracing-tracy")]
let subscriber = subscriber.with(tracy_layer); let subscriber = subscriber.with(tracy_layer);
finished_subscriber = subscriber; if let Some(update_subscriber) = self.update_subscriber {
finished_subscriber = update_subscriber(Box::new(subscriber));
} else {
finished_subscriber = Box::new(subscriber);
}
} }
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]

View file

@ -171,6 +171,7 @@ Example | Description
[Empty](../examples/app/empty.rs) | An empty application (does nothing) [Empty](../examples/app/empty.rs) | An empty application (does nothing)
[Empty with Defaults](../examples/app/empty_defaults.rs) | An empty application with default plugins [Empty with Defaults](../examples/app/empty_defaults.rs) | An empty application with default plugins
[Headless](../examples/app/headless.rs) | An application that runs without default plugins [Headless](../examples/app/headless.rs) | An application that runs without default plugins
[Log layers](../examples/app/log_layers.rs) | Illustrate how to add custom log layers
[Logs](../examples/app/logs.rs) | Illustrate how to use generate log output [Logs](../examples/app/logs.rs) | Illustrate how to use generate log output
[No Renderer](../examples/app/no_renderer.rs) | An application that runs with default plugins and displays an empty window, but without an actual renderer [No Renderer](../examples/app/no_renderer.rs) | An application that runs with default plugins and displays an empty window, but without an actual renderer
[Plugin](../examples/app/plugin.rs) | Demonstrates the creation and registration of a custom plugin [Plugin](../examples/app/plugin.rs) | Demonstrates the creation and registration of a custom plugin

View file

@ -0,0 +1,47 @@
//! This example illustrates how to add custom log layers in bevy.
use bevy::{
log::tracing_subscriber::{layer::SubscriberExt, Layer},
log::BoxedSubscriber,
prelude::*,
utils::tracing::Subscriber,
};
struct CustomLayer;
impl<S: Subscriber> Layer<S> for CustomLayer {
fn on_event(
&self,
event: &bevy::utils::tracing::Event<'_>,
_ctx: bevy::log::tracing_subscriber::layer::Context<'_, S>,
) {
println!("Got event!");
println!(" level={:?}", event.metadata().level());
println!(" target={:?}", event.metadata().target());
println!(" name={:?}", event.metadata().name());
}
}
fn update_subscriber(subscriber: BoxedSubscriber) -> BoxedSubscriber {
Box::new(subscriber.with(CustomLayer))
}
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(bevy::log::LogPlugin {
update_subscriber: Some(update_subscriber),
..default()
}))
.add_systems(Update, log_system)
.run();
}
fn log_system() {
// here is how you write new logs at each "log level" (in "most import" to
// "least important" order)
error!("something failed");
warn!("something bad happened that isn't a failure, but thats worth calling out");
info!("helpful information that is worth printing by default");
debug!("helpful for debugging");
trace!("very noisy");
}

View file

@ -14,6 +14,7 @@ fn main() {
.add_plugins(LogPlugin { .add_plugins(LogPlugin {
level: Level::TRACE, level: Level::TRACE,
filter: "".to_string(), filter: "".to_string(),
..default()
}) })
.add_systems( .add_systems(
Update, Update,