mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
Improve tracing layer customization (#13159)
# Objective - Fixes https://github.com/bevyengine/bevy/issues/12597 The current tracing customization option (the `update_subscriber` field) was basically unusable because it provides a `dyn Subscriber` and most layers require a `Subscriber` that also implements `for<'a> LookupSpan<'a, Data=Data<'a>>`, so it was impossible to add a layer on top of the `dyn Subscriber`. This PR provides an alternative way of adding additional tracing layers to the LogPlugin by instead creating an `Option<Layer>`. This is enough for most situations because `Option<Layer>` and `Vec<Layer>` both implement `Layer`. ## Solution - Replace the `update_subscriber` field of `LogPlugin` with a `custom_layer` field which is function pointer returning an `Option<BoxedLayer>` - Update the examples to showcase that this works: - with multiple additional layers - with Layers that were previously problematic, such as `bevy::log::tracing_subscriber::fmt::layer().with_file(true)` (mentioned in the issue) Note that in the example this results in duplicate logs, since we have our own layer on top of the default `fmt_layer` added in the LogPlugin; maybe in the future we might want to provide a single one? Or to let the user customize the default `fmt_layer` ? I still think this change is an improvement upon the previous solution, which was basically broken. --- ## Changelog > This section is optional. If this was a trivial fix, or has no externally-visible impact, you can delete this section. - The `LogPlugin`'s `update_subscriber` field has been replaced with `custom_layer` to allow the user to flexibly add a `tracing::Layer` to the layer stack ## Migration Guide - The `LogPlugin`'s `update_subscriber` field has been replaced with `custom_layer` --------- Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
This commit is contained in:
parent
2fd432c463
commit
ded5d523bd
3 changed files with 38 additions and 39 deletions
|
@ -49,11 +49,10 @@ pub use bevy_utils::{
|
|||
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};
|
||||
use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter};
|
||||
use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter, Layer};
|
||||
#[cfg(feature = "tracing-chrome")]
|
||||
use {bevy_ecs::system::Resource, bevy_utils::synccell::SyncCell};
|
||||
|
||||
|
@ -83,7 +82,7 @@ pub(crate) struct FlushGuard(SyncCell<tracing_chrome::FlushGuard>);
|
|||
/// .add_plugins(DefaultPlugins.set(LogPlugin {
|
||||
/// level: Level::DEBUG,
|
||||
/// filter: "wgpu=error,bevy_render=info,bevy_ecs=trace".to_string(),
|
||||
/// update_subscriber: None,
|
||||
/// custom_layer: |_| None,
|
||||
/// }))
|
||||
/// .run();
|
||||
/// }
|
||||
|
@ -121,23 +120,28 @@ pub struct LogPlugin {
|
|||
/// This can be further filtered using the `filter` setting.
|
||||
pub level: Level,
|
||||
|
||||
/// Optionally apply extra transformations to the tracing subscriber,
|
||||
/// such as adding [`Layer`](tracing_subscriber::layer::Layer)s.
|
||||
/// Optionally add an extra [`Layer`] to the tracing subscriber
|
||||
///
|
||||
/// This function is only called once, when the plugin is built.
|
||||
///
|
||||
/// Because [`BoxedLayer`] takes a `dyn Layer`, `Vec<Layer>` is also an acceptable return value.
|
||||
///
|
||||
/// Access to [`App`] is also provided to allow for communication between the [`Subscriber`]
|
||||
/// and the [`App`].
|
||||
pub update_subscriber: Option<fn(&mut App, BoxedSubscriber) -> BoxedSubscriber>,
|
||||
///
|
||||
/// Please see the `examples/log_layers.rs` for a complete example.
|
||||
pub custom_layer: fn(app: &mut App) -> Option<BoxedLayer>,
|
||||
}
|
||||
|
||||
/// Alias for a boxed [`Subscriber`].
|
||||
pub type BoxedSubscriber = Box<dyn Subscriber + Send + Sync + 'static>;
|
||||
/// A boxed [`Layer`] that can be used with [`LogPlugin`].
|
||||
pub type BoxedLayer = Box<dyn Layer<Registry> + Send + Sync + 'static>;
|
||||
|
||||
impl Default for LogPlugin {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
filter: "wgpu=error,naga=warn".to_string(),
|
||||
level: Level::INFO,
|
||||
update_subscriber: None,
|
||||
custom_layer: |_| None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,11 +159,16 @@ impl Plugin for LogPlugin {
|
|||
}
|
||||
|
||||
let finished_subscriber;
|
||||
let subscriber = Registry::default();
|
||||
|
||||
// add optional layer provided by user
|
||||
let subscriber = subscriber.with((self.custom_layer)(app));
|
||||
|
||||
let default_filter = { format!("{},{}", self.level, self.filter) };
|
||||
let filter_layer = EnvFilter::try_from_default_env()
|
||||
.or_else(|_| EnvFilter::try_new(&default_filter))
|
||||
.unwrap();
|
||||
let subscriber = Registry::default().with(filter_layer);
|
||||
let subscriber = subscriber.with(filter_layer);
|
||||
|
||||
#[cfg(feature = "trace")]
|
||||
let subscriber = subscriber.with(tracing_error::ErrorLayer::default());
|
||||
|
@ -209,12 +218,7 @@ impl Plugin for LogPlugin {
|
|||
let subscriber = subscriber.with(chrome_layer);
|
||||
#[cfg(feature = "tracing-tracy")]
|
||||
let subscriber = subscriber.with(tracy_layer);
|
||||
|
||||
if let Some(update_subscriber) = self.update_subscriber {
|
||||
finished_subscriber = update_subscriber(app, Box::new(subscriber));
|
||||
} else {
|
||||
finished_subscriber = Box::new(subscriber);
|
||||
}
|
||||
finished_subscriber = subscriber;
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
//! 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,
|
||||
};
|
||||
use bevy::log::BoxedLayer;
|
||||
use bevy::{log::tracing_subscriber::Layer, prelude::*, utils::tracing::Subscriber};
|
||||
|
||||
struct CustomLayer;
|
||||
|
||||
|
@ -24,22 +20,21 @@ impl<S: Subscriber> Layer<S> for CustomLayer {
|
|||
|
||||
// We don't need App for this example, as we are just printing log information.
|
||||
// For an example that uses App, see log_layers_ecs.
|
||||
fn update_subscriber(_: &mut App, subscriber: BoxedSubscriber) -> BoxedSubscriber {
|
||||
Box::new(subscriber.with(CustomLayer))
|
||||
fn custom_layer(_app: &mut App) -> Option<BoxedLayer> {
|
||||
// You can provide multiple layers like this, since Vec<Layer> is also a layer:
|
||||
Some(Box::new(vec![
|
||||
bevy::log::tracing_subscriber::fmt::layer()
|
||||
.with_file(true)
|
||||
.boxed(),
|
||||
CustomLayer.boxed(),
|
||||
]))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins.set(bevy::log::LogPlugin {
|
||||
update_subscriber: Some(update_subscriber),
|
||||
// You can chain multiple subscriber updates like this:
|
||||
//
|
||||
// update_subscriber: Some(|app, subscriber| {
|
||||
// let subscriber = update_subscriber_a(app, subscriber);
|
||||
// let subscriber = update_subscriber_b(app, subscriber);
|
||||
//
|
||||
// update_subscriber_c(app, subscriber)
|
||||
// }),
|
||||
custom_layer,
|
||||
|
||||
..default()
|
||||
}))
|
||||
.add_systems(Update, log_system)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
//! The way we will do this is via a [`mpsc`] channel. [`mpsc`] channels allow 2 unrelated
|
||||
//! parts of the program to communicate (in this case, [`Layer`]s and Bevy's ECS).
|
||||
//!
|
||||
//! Inside the `update_subscriber` function we will create a [`mpsc::Sender`] and a [`mpsc::Receiver`] from a
|
||||
//! Inside the `custom_layer` function we will create a [`mpsc::Sender`] and a [`mpsc::Receiver`] from a
|
||||
//! [`mpsc::channel`]. The [`Sender`](mpsc::Sender) will go into the `AdvancedLayer` and the [`Receiver`](mpsc::Receiver) will
|
||||
//! go into a non-send resource called `LogEvents` (It has to be non-send because [`Receiver`](mpsc::Receiver) is [`!Sync`](Sync)).
|
||||
//! From there we will use `transfer_log_events` to transfer log events from `LogEvents` to an ECS event called `LogEvent`.
|
||||
|
@ -13,9 +13,9 @@
|
|||
|
||||
use std::sync::mpsc;
|
||||
|
||||
use bevy::log::BoxedLayer;
|
||||
use bevy::{
|
||||
log::tracing_subscriber::{self, layer::SubscriberExt, Layer},
|
||||
log::BoxedSubscriber,
|
||||
log::tracing_subscriber::{self, Layer},
|
||||
prelude::*,
|
||||
utils::tracing,
|
||||
utils::tracing::Subscriber,
|
||||
|
@ -77,7 +77,7 @@ impl tracing::field::Visit for CaptureLayerVisitor<'_> {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn update_subscriber(app: &mut App, subscriber: BoxedSubscriber) -> BoxedSubscriber {
|
||||
fn custom_layer(app: &mut App) -> Option<BoxedLayer> {
|
||||
let (sender, receiver) = mpsc::channel();
|
||||
|
||||
let layer = CaptureLayer { sender };
|
||||
|
@ -87,13 +87,13 @@ fn update_subscriber(app: &mut App, subscriber: BoxedSubscriber) -> BoxedSubscri
|
|||
app.add_event::<LogEvent>();
|
||||
app.add_systems(Update, transfer_log_events);
|
||||
|
||||
Box::new(subscriber.with(layer))
|
||||
Some(layer.boxed())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins.set(bevy::log::LogPlugin {
|
||||
update_subscriber: Some(update_subscriber),
|
||||
custom_layer,
|
||||
..default()
|
||||
}))
|
||||
.add_systems(Startup, (log_system, setup))
|
||||
|
|
Loading…
Reference in a new issue