From 8c6d9b8103d79cfa62ba107fce2aaf46474e1b0a Mon Sep 17 00:00:00 2001 From: Charles Bournhonesque Date: Mon, 15 Jan 2024 10:26:13 -0500 Subject: [PATCH] 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 --- Cargo.toml | 10 ++++++++ crates/bevy_log/src/lib.rs | 17 ++++++++++++- examples/README.md | 1 + examples/app/log_layers.rs | 47 +++++++++++++++++++++++++++++++++++ examples/ecs/system_piping.rs | 1 + 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 examples/app/log_layers.rs diff --git a/Cargo.toml b/Cargo.toml index fe49a885a6..d5b1fa1cb7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1035,6 +1035,16 @@ description = "Illustrate how to use generate log output" category = "Application" 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]] name = "plugin" path = "examples/app/plugin.rs" diff --git a/crates/bevy_log/src/lib.rs b/crates/bevy_log/src/lib.rs index 9c0e641de6..ad07c9ec91 100644 --- a/crates/bevy_log/src/lib.rs +++ b/crates/bevy_log/src/lib.rs @@ -38,8 +38,10 @@ pub use bevy_utils::tracing::{ debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn, warn_span, Level, }; +pub use tracing_subscriber; use bevy_app::{App, Plugin}; +use bevy_utils::tracing::Subscriber; use tracing_log::LogTracer; #[cfg(feature = "tracing-chrome")] use tracing_subscriber::fmt::{format::DefaultFields, FormattedFields}; @@ -64,6 +66,7 @@ use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter}; /// .add_plugins(DefaultPlugins.set(LogPlugin { /// level: Level::DEBUG, /// filter: "wgpu=error,bevy_render=info,bevy_ecs=trace".to_string(), +/// update_subscriber: None, /// })) /// .run(); /// } @@ -100,13 +103,21 @@ pub struct LogPlugin { /// Filters out logs that are "less than" the given level. /// This can be further filtered using the `filter` setting. pub level: Level, + + /// Optionally apply extra transformations to the tracing subscriber. + /// For example add [`Layers`](tracing_subscriber::layer::Layer) + pub update_subscriber: Option BoxedSubscriber>, } +/// Alias for a boxed [`Subscriber`]. +pub type BoxedSubscriber = Box; + impl Default for LogPlugin { fn default() -> Self { Self { filter: "wgpu=error,naga=warn".to_string(), level: Level::INFO, + update_subscriber: None, } } } @@ -179,7 +190,11 @@ impl Plugin for LogPlugin { #[cfg(feature = "tracing-tracy")] 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")] diff --git a/examples/README.md b/examples/README.md index d31f801676..b932db2c82 100644 --- a/examples/README.md +++ b/examples/README.md @@ -171,6 +171,7 @@ Example | Description [Empty](../examples/app/empty.rs) | An empty application (does nothing) [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 +[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 [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 diff --git a/examples/app/log_layers.rs b/examples/app/log_layers.rs new file mode 100644 index 0000000000..144fac28bd --- /dev/null +++ b/examples/app/log_layers.rs @@ -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 Layer 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"); +} diff --git a/examples/ecs/system_piping.rs b/examples/ecs/system_piping.rs index 7cd5f2c1bd..63579a2b61 100644 --- a/examples/ecs/system_piping.rs +++ b/examples/ecs/system_piping.rs @@ -14,6 +14,7 @@ fn main() { .add_plugins(LogPlugin { level: Level::TRACE, filter: "".to_string(), + ..default() }) .add_systems( Update,