diff --git a/Cargo.toml b/Cargo.toml index ba1947661a0784..9152131abebb50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,6 +70,7 @@ trace_chrome = ["trace", "bevy_internal/trace_chrome"] trace_tracy = ["trace", "bevy_internal/trace_tracy"] trace = ["bevy_internal/trace"] wgpu_trace = ["bevy_internal/wgpu_trace"] +log_to_file = ["bevy_internal/log_to_file"] # Image format support for texture loading (PNG and HDR are enabled by default) hdr = ["bevy_internal/hdr"] diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 7fccda37863d09..845fbcac672c6e 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -16,12 +16,13 @@ trace = [ "bevy_ecs/trace", "bevy_log/trace", "bevy_render?/trace", - "bevy_hierarchy/trace" + "bevy_hierarchy/trace", ] -trace_chrome = [ "bevy_log/tracing-chrome" ] -trace_tracy = ["bevy_render?/tracing-tracy", "bevy_log/tracing-tracy" ] +trace_chrome = ["bevy_log/tracing-chrome"] +trace_tracy = ["bevy_render?/tracing-tracy", "bevy_log/tracing-tracy"] wgpu_trace = ["bevy_render/wgpu_trace"] debug_asset_server = ["bevy_asset/debug_asset_server"] +log_to_file = ["bevy_log/tracing-appender"] # Image format support for texture loading (PNG and HDR are enabled by default) hdr = ["bevy_render/hdr"] @@ -76,7 +77,9 @@ bevy_input = { path = "../bevy_input", version = "0.8.0-dev" } bevy_log = { path = "../bevy_log", version = "0.8.0-dev" } bevy_math = { path = "../bevy_math", version = "0.8.0-dev" } bevy_ptr = { path = "../bevy_ptr", version = "0.8.0-dev" } -bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] } +bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = [ + "bevy", +] } bevy_scene = { path = "../bevy_scene", version = "0.8.0-dev" } bevy_time = { path = "../bevy_time", version = "0.8.0-dev" } bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" } @@ -100,4 +103,4 @@ bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.8.0-dev" } [target.'cfg(target_os = "android")'.dependencies] # This version *must* be the same as the version used by winit, # or Android will break: https://github.com/rust-windowing/winit#android -ndk-glue = {version = "0.5", features = ["logger"]} +ndk-glue = { version = "0.5", features = ["logger"] } diff --git a/crates/bevy_log/Cargo.toml b/crates/bevy_log/Cargo.toml index 008d28b9286bbc..1a9c5e4b2f6449 100644 --- a/crates/bevy_log/Cargo.toml +++ b/crates/bevy_log/Cargo.toml @@ -9,17 +9,21 @@ license = "MIT OR Apache-2.0" keywords = ["bevy"] [features] -trace = [ "tracing-error" ] +trace = ["tracing-error"] [dependencies] bevy_app = { path = "../bevy_app", version = "0.8.0-dev" } bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" } -tracing-subscriber = {version = "0.3.1", features = ["registry", "env-filter"]} +tracing-subscriber = { version = "0.3.1", features = [ + "registry", + "env-filter", +] } tracing-chrome = { version = "0.4.0", optional = true } tracing-tracy = { version = "0.10.0", optional = true } tracing-log = "0.1.2" tracing-error = { version = "0.2.0", optional = true } +tracing-appender = { version = "0.2.2", optional = true } [target.'cfg(target_os = "android")'.dependencies] android_log-sys = "0.2.0" diff --git a/crates/bevy_log/src/lib.rs b/crates/bevy_log/src/lib.rs index 2985133721a087..009ffc73636cda 100644 --- a/crates/bevy_log/src/lib.rs +++ b/crates/bevy_log/src/lib.rs @@ -13,6 +13,8 @@ #[cfg(feature = "trace")] use std::panic; +#[cfg(feature = "tracing-appender")] +use std::path::PathBuf; #[cfg(target_os = "android")] mod android_tracing; @@ -88,6 +90,48 @@ use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter}; #[derive(Default)] pub struct LogPlugin; +/// Enum to control how often a new log file will be created +#[cfg(feature = "tracing-appender")] +#[derive(Debug, Clone)] +pub enum Rolling { + /// Creates a new file every minute and appends the date to the file name + /// Date format: YYYY-MM-DD-HH-mm + Minutely, + /// Creates a new file every hour and appends the date to the file name + /// Date format: YYYY-MM-DD-HH + Hourly, + /// Creates a new file every day and appends the date to the file name + /// Date format: YYYY-MM-DD + Daily, + /// Never creates a new file + Never, +} + +/// Settings to control the `log_to_file` feature +#[cfg(feature = "tracing-appender")] +#[derive(Debug, Clone)] +pub struct FileAppenderSettings { + /// Controls how often a new file will be created + rolling: Rolling, + /// The path of the directory where the log files will be added + /// + /// Defaults to the local directory + path: PathBuf, + /// The prefix added when creating a file + prefix: String, +} + +#[cfg(feature = "tracing-appender")] +impl Default for FileAppenderSettings { + fn default() -> Self { + Self { + rolling: Rolling::Daily, + path: PathBuf::from("."), + prefix: String::from("log"), + } + } +} + /// `LogPlugin` settings pub struct LogSettings { /// Filters logs using the [`EnvFilter`] format @@ -96,6 +140,10 @@ pub struct LogSettings { /// Filters out logs that are "less than" the given level. /// This can be further filtered using the `filter` setting. pub level: Level, + + /// ConfigureFileLogging + #[cfg(feature = "tracing-appender")] + pub file_appender: FileAppenderSettings, } impl Default for LogSettings { @@ -103,6 +151,8 @@ impl Default for LogSettings { Self { filter: "wgpu=error".to_string(), level: Level::INFO, + #[cfg(feature = "tracing-appender")] + file_appender: FileAppenderSettings::default(), } } } @@ -168,6 +218,34 @@ impl Plugin for LogPlugin { let subscriber = subscriber.with(fmt_layer); + #[cfg(feature = "tracing-appender")] + let subscriber = { + let file_output = { + let settings = app.world.get_resource_or_insert_with(LogSettings::default); + settings.file_appender.clone() + }; + + let file_appender = tracing_appender::rolling::RollingFileAppender::new( + match file_output.rolling { + Rolling::Minutely => tracing_appender::rolling::Rotation::MINUTELY, + Rolling::Hourly => tracing_appender::rolling::Rotation::HOURLY, + Rolling::Daily => tracing_appender::rolling::Rotation::DAILY, + Rolling::Never => tracing_appender::rolling::Rotation::NEVER, + }, + file_output.path, + file_output.prefix, + ); + + let (non_blocking, worker_guard) = tracing_appender::non_blocking(file_appender); + let file_fmt_layer = tracing_subscriber::fmt::Layer::default() + .with_ansi(false) + .with_writer(non_blocking); + // We need to keep this somewhere so it doesn't get dropped. If it gets dropped then it will silently stop writing to the file + app.insert_resource(worker_guard); + + subscriber.with(file_fmt_layer) + }; + #[cfg(feature = "tracing-chrome")] let subscriber = subscriber.with(chrome_layer); #[cfg(feature = "tracing-tracy")]