Log Plugin (#836)

add bevy_log plugin
This commit is contained in:
Carter Anderson 2020-11-12 17:23:57 -08:00 committed by GitHub
parent 465c3d4f7b
commit e03f17ba7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 327 additions and 316 deletions

View File

@ -48,7 +48,7 @@ bevy_gltf = ["bevy_internal/bevy_gltf"]
bevy_wgpu = ["bevy_internal/bevy_wgpu"]
bevy_winit = ["bevy_internal/bevy_winit"]
profiler = ["bevy_internal/profiler"]
trace_chrome = ["bevy_internal/trace_chrome"]
trace = ["bevy_internal/trace"]
wgpu_trace = ["bevy_internal/wgpu_trace"]
@ -74,17 +74,9 @@ bevy_internal = {path = "crates/bevy_internal", version = "0.3.0", default-featu
[dev-dependencies]
anyhow = "1.0"
log = "0.4"
rand = "0.7.3"
ron = "0.6"
serde = {version = "1", features = ["derive"]}
tracing = "0.1.21"
tracing-chrome = "0.2.0"
tracing-subscriber = "0.2.15"
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
console_error_panic_hook = "0.1.6"
console_log = {version = "0.2", features = ["color"]}
[[example]]
name = "hello_world"
@ -146,6 +138,10 @@ path = "examples/app/empty_defaults.rs"
name = "empty"
path = "examples/app/empty.rs"
[[example]]
name = "logs"
path = "examples/app/logs.rs"
[[example]]
name = "headless"
path = "examples/app/headless.rs"
@ -166,10 +162,6 @@ path = "examples/app/return_after_run.rs"
name = "thread_pool_resources"
path = "examples/app/thread_pool_resources.rs"
[[example]]
name = "tracing"
path = "examples/app/tracing.rs"
[[example]]
name = "hot_asset_reloading"
path = "examples/asset/hot_asset_reloading.rs"
@ -336,7 +328,7 @@ apk_label = "Bevy Example"
assets = "assets"
res = "assets/android-res"
icon = "@mipmap/ic_launcher"
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
min_sdk_version = 16
target_sdk_version = 29

View File

@ -13,7 +13,7 @@ license = "MIT"
keywords = ["bevy"]
[features]
trace = [ "tracing" ]
trace = []
[dependencies]
# bevy
@ -22,9 +22,7 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
log = { version = "0.4", features = ["release_max_level_info"] }
serde = { version = "1.0", features = ["derive"] }
tracing = { version = "0.1.21", optional = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2" }

View File

@ -1,7 +1,7 @@
use crate::app_builder::AppBuilder;
use bevy_ecs::{ParallelExecutor, Resources, Schedule, World};
#[cfg(feature = "trace")]
use tracing::info_span;
use bevy_utils::tracing::info_span;
#[allow(clippy::needless_doctest_main)]
/// Containers of app logic and data

View File

@ -5,6 +5,7 @@ use crate::{
stage, startup_stage, PluginGroup, PluginGroupBuilder,
};
use bevy_ecs::{FromResources, IntoSystem, Resources, System, World};
use bevy_utils::tracing::debug;
/// Configure [App]s using the builder pattern
pub struct AppBuilder {
@ -267,7 +268,7 @@ impl AppBuilder {
where
T: Plugin,
{
log::debug!("added plugin: {}", plugin.name());
debug!("added plugin: {}", plugin.name());
plugin.build(self);
self
}

View File

@ -1,5 +1,5 @@
use crate::{AppBuilder, Plugin};
use bevy_utils::HashMap;
use bevy_utils::{tracing::debug, HashMap};
use std::any::TypeId;
pub trait PluginGroup {
@ -94,7 +94,7 @@ impl PluginGroupBuilder {
for ty in self.order.iter() {
if let Some(entry) = self.plugins.get(ty) {
if entry.enabled {
log::debug!("added plugin: {}", entry.plugin.name());
debug!("added plugin: {}", entry.plugin.name());
entry.plugin.build(app);
}
}

View File

@ -33,7 +33,6 @@ crossbeam-channel = "0.4.4"
anyhow = "1.0"
thiserror = "1.0"
downcast-rs = "1.2.0"
log = { version = "0.4", features = ["release_max_level_info"] }
notify = { version = "5.0.0-pre.2", optional = true }
parking_lot = "0.11.0"
rand = "0.7.3"

View File

@ -23,7 +23,5 @@ bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
bevy_tasks = { path = "../bevy_tasks", version = "0.3.0" }
log = { version = "0.4", features = ["release_max_level_info"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
instant = { version = "0.1", features = ["wasm-bindgen"] }

View File

@ -1,5 +1,6 @@
use bevy_ecs::Resources;
use bevy_tasks::{AsyncComputeTaskPool, ComputeTaskPool, IoTaskPool, TaskPoolBuilder};
use bevy_utils::tracing::trace;
/// Defines a simple way to determine how many threads to use given the number of remaining cores
/// and number of total cores
@ -96,7 +97,7 @@ impl DefaultTaskPoolOptions {
self.min_total_threads,
self.max_total_threads,
);
log::trace!("Assigning {} cores to default task pools", total_threads);
trace!("Assigning {} cores to default task pools", total_threads);
let mut remaining_threads = total_threads;
@ -106,7 +107,7 @@ impl DefaultTaskPoolOptions {
.io
.get_number_of_threads(remaining_threads, total_threads);
log::trace!("IO Threads: {}", io_threads);
trace!("IO Threads: {}", io_threads);
remaining_threads = remaining_threads.saturating_sub(io_threads);
resources.insert(IoTaskPool(
@ -123,7 +124,7 @@ impl DefaultTaskPoolOptions {
.async_compute
.get_number_of_threads(remaining_threads, total_threads);
log::trace!("Async Compute Threads: {}", async_compute_threads);
trace!("Async Compute Threads: {}", async_compute_threads);
remaining_threads = remaining_threads.saturating_sub(async_compute_threads);
resources.insert(AsyncComputeTaskPool(
@ -141,7 +142,7 @@ impl DefaultTaskPoolOptions {
.compute
.get_number_of_threads(remaining_threads, total_threads);
log::trace!("Compute Threads: {}", compute_threads);
trace!("Compute Threads: {}", compute_threads);
resources.insert(ComputeTaskPool(
TaskPoolBuilder::default()
.num_threads(compute_threads)

View File

@ -12,8 +12,6 @@ repository = "https://github.com/bevyengine/bevy"
license = "MIT"
keywords = ["bevy"]
[features]
profiler = ["bevy_ecs/profiler"]
[dependencies]
# bevy

View File

@ -1,8 +1,6 @@
mod diagnostic;
mod frame_time_diagnostics_plugin;
mod print_diagnostics_plugin;
#[cfg(feature = "profiler")]
mod system_profiler;
pub use diagnostic::*;
pub use frame_time_diagnostics_plugin::FrameTimeDiagnosticsPlugin;
pub use print_diagnostics_plugin::PrintDiagnosticsPlugin;
@ -16,16 +14,5 @@ pub struct DiagnosticsPlugin;
impl Plugin for DiagnosticsPlugin {
fn build(&self, app: &mut AppBuilder) {
app.init_resource::<Diagnostics>();
#[cfg(feature = "profiler")]
{
use bevy_ecs::IntoSystem;
app.add_resource::<Box<dyn bevy_ecs::Profiler>>(Box::new(
system_profiler::SystemProfiler::default(),
))
.add_system_to_stage(
bevy_app::stage::LAST,
system_profiler::profiler_diagnostic_system.system(),
);
}
}
}

View File

@ -1,71 +0,0 @@
use crate::{Diagnostic, DiagnosticId, Diagnostics};
use bevy_ecs::{Profiler, Res, ResMut};
use bevy_utils::HashMap;
use parking_lot::RwLock;
use std::{borrow::Cow, sync::Arc};
#[cfg(target_arch = "wasm32")]
use instant::Instant;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
#[derive(Debug)]
struct SystemRunInfo {
start: Instant,
stop: Instant,
}
#[derive(Debug, Default)]
struct SystemProfiles {
diagnostic_id: DiagnosticId,
history: Vec<SystemRunInfo>,
current_start: Option<Instant>,
}
/// Profiles systems by recording their run duration as diagnostics.
#[derive(Debug, Default)]
pub struct SystemProfiler {
system_profiles: Arc<RwLock<HashMap<Cow<'static, str>, SystemProfiles>>>,
}
impl Profiler for SystemProfiler {
fn start(&self, scope: Cow<'static, str>) {
let mut system_profiles = self.system_profiles.write();
let profiles = system_profiles
.entry(scope.clone())
.or_insert_with(SystemProfiles::default);
profiles.current_start = Some(Instant::now());
}
fn stop(&self, scope: Cow<'static, str>) {
let now = Instant::now();
let mut system_profiles = self.system_profiles.write();
let profiles = system_profiles.get_mut(&scope).unwrap();
if let Some(current_start) = profiles.current_start.take() {
profiles.history.push(SystemRunInfo {
start: current_start,
stop: now,
});
}
}
}
pub fn profiler_diagnostic_system(
mut diagnostics: ResMut<Diagnostics>,
system_profiler: Res<Box<dyn Profiler>>,
) {
let system_profiler = system_profiler.downcast_ref::<SystemProfiler>().unwrap();
let mut system_profiles = system_profiler.system_profiles.write();
for (scope, profiles) in system_profiles.iter_mut() {
if diagnostics.get(profiles.diagnostic_id).is_none() {
diagnostics.add(Diagnostic::new(profiles.diagnostic_id, &scope, 20))
}
for profile in profiles.history.drain(..) {
diagnostics.add_measurement(
profiles.diagnostic_id,
(profile.stop - profile.start).as_secs_f64(),
);
}
}
}

View File

@ -19,5 +19,4 @@ keywords = ["bevy"]
bevy_app = { path = "../bevy_app", version = "0.3.0" }
# other
log = { version = "0.4", features = ["release_max_level_info"] }
libloading = { version = "0.6" }

View File

@ -20,7 +20,6 @@ pub trait DynamicPluginExt {
impl DynamicPluginExt for AppBuilder {
fn load_plugin(&mut self, path: &str) -> &mut Self {
let (_lib, plugin) = dynamically_load_plugin(path);
log::debug!("loaded plugin: {}", plugin.name());
plugin.build(self);
self
}

View File

@ -14,8 +14,7 @@ keywords = ["ecs", "game", "bevy"]
categories = ["game-engines", "data-structures"]
[features]
profiler = []
trace = [ "tracing" ]
trace = []
[dependencies]
bevy_hecs = { path = "hecs", features = ["macros", "serialize"], version = "0.3.0" }
@ -26,5 +25,3 @@ thiserror = "1.0"
fixedbitset = "0.3.1"
downcast-rs = "1.2.0"
parking_lot = "0.11.0"
log = { version = "0.4", features = ["release_max_level_info"] }
tracing = { version = "0.1.21", optional = true }

View File

@ -5,10 +5,11 @@ use crate::{
};
use bevy_hecs::{ArchetypesGeneration, TypeAccess, World};
use bevy_tasks::{ComputeTaskPool, CountdownEvent, TaskPool};
#[cfg(feature = "trace")]
use bevy_utils::tracing::info_span;
use bevy_utils::tracing::trace;
use fixedbitset::FixedBitSet;
use std::ops::Range;
#[cfg(feature = "trace")]
use tracing::info_span;
/// Executes each schedule stage in parallel by analyzing system dependencies.
/// System execution order is undefined except under the following conditions:
@ -68,7 +69,6 @@ impl ParallelExecutor {
let stage_span = info_span!("stage", name = stage_name.as_ref());
#[cfg(feature = "trace")]
let _stage_guard = stage_span.enter();
log::trace!("run stage {:?}", stage_name);
if let Some(stage_systems) = schedule.stages.get_mut(stage_name) {
executor_stage.run(world, resources, stage_systems, schedule_changed);
}
@ -334,12 +334,12 @@ impl ExecutorStage {
compute_pool: &TaskPool,
) {
// Generate tasks for systems in the given range and block until they are complete
log::trace!("running systems {:?}", prepared_system_range);
trace!("running systems {:?}", prepared_system_range);
compute_pool.scope(|scope| {
let start_system_index = prepared_system_range.start;
let mut system_index = start_system_index;
for system in &mut systems[prepared_system_range] {
log::trace!(
trace!(
"prepare {} {} with {} dependents and {} dependencies",
system_index,
system.name(),
@ -381,12 +381,6 @@ impl ExecutorStage {
for (trigger_event, dependent_system_index) in
trigger_events.iter().zip(dependent_systems)
{
log::trace!(
" * system ({}) triggers events: ({}): {}",
system_index,
dependent_system_index,
trigger_event.get()
);
debug_assert!(
*dependent_system_index < start_system_index || trigger_event.get() > 0
);
@ -408,12 +402,7 @@ impl ExecutorStage {
#[cfg(feature = "trace")]
let _system_guard = system_span.enter();
log::trace!("run {}", system.name());
#[cfg(feature = "profiler")]
crate::profiler_start(resources, system.name().clone());
system.run(world_ref, resources_ref);
#[cfg(feature = "profiler")]
crate::profiler_stop(resources, system.name().clone());
}
// Notify dependents that this task is done
@ -506,11 +495,10 @@ impl ExecutorStage {
let system = systems[thread_local_system_index].as_mut();
#[cfg(feature = "trace")]
let system_span = info_span!("system", name = system.name().as_ref());
let system_span = info_span!("thread_local_system", name = system.name().as_ref());
#[cfg(feature = "trace")]
let _system_guard = system_span.enter();
log::trace!("running thread local system {}", system.name());
system.run(world, resources);
system.run_thread_local(world, resources);
}
@ -527,7 +515,6 @@ impl ExecutorStage {
next_thread_local_index,
);
log::trace!("running systems {:?}", run_ready_system_index_range);
self.run_systems(
world,
resources,

View File

@ -148,8 +148,6 @@ impl Schedule {
for stage_name in self.stage_order.iter() {
if let Some(stage_systems) = self.stages.get_mut(stage_name) {
for system in stage_systems.iter_mut() {
#[cfg(feature = "profiler")]
crate::profiler_start(resources, system.name().clone());
system.update(world);
match system.thread_local_execution() {
ThreadLocalExecution::NextFlush => system.run(world, resources),
@ -159,8 +157,6 @@ impl Schedule {
system.run_thread_local(world, resources);
}
}
#[cfg(feature = "profiler")]
crate::profiler_stop(resources, system.name().clone());
}
// "flush"

View File

@ -1,6 +1,7 @@
use super::SystemId;
use crate::resource::{Resource, Resources};
use bevy_hecs::{Bundle, Component, DynamicBundle, Entity, EntityReserver, World};
use bevy_utils::tracing::debug;
use std::marker::PhantomData;
/// A [World] mutation
@ -51,7 +52,7 @@ pub(crate) struct Despawn {
impl Command for Despawn {
fn write(self: Box<Self>, world: &mut World, _resources: &mut Resources) {
if let Err(e) = world.despawn(self.entity) {
log::debug!("Failed to despawn entity {:?}: {}", self.entity, e);
debug!("Failed to despawn entity {:?}: {}", self.entity, e);
}
}
}

View File

@ -1,8 +1,6 @@
mod commands;
mod into_system;
mod into_thread_local;
#[cfg(feature = "profiler")]
mod profiler;
mod query;
#[allow(clippy::module_inception)]
mod system;
@ -11,8 +9,6 @@ mod system_param;
pub use commands::*;
pub use into_system::*;
pub use into_thread_local::*;
#[cfg(feature = "profiler")]
pub use profiler::*;
pub use query::*;
pub use system::*;
pub use system_param::*;

View File

@ -1,25 +0,0 @@
use crate::Resources;
use downcast_rs::{impl_downcast, Downcast};
use std::borrow::Cow;
/// Runs at the start and end of each system
///
/// Profilers are used to collect diagnostics about system execution.
pub trait Profiler: Downcast + Send + Sync + 'static {
fn start(&self, scope: Cow<'static, str>);
fn stop(&self, scope: Cow<'static, str>);
}
pub fn profiler_start(resources: &Resources, scope: Cow<'static, str>) {
if let Some(profiler) = resources.get::<Box<dyn Profiler>>() {
profiler.start(scope);
}
}
pub fn profiler_stop(resources: &Resources, scope: Cow<'static, str>) {
if let Some(profiler) = resources.get::<Box<dyn Profiler>>() {
profiler.stop(scope);
}
}
impl_downcast!(Profiler);

View File

@ -14,7 +14,7 @@ keywords = ["bevy"]
bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_input = { path = "../bevy_input", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
gilrs = "0.8.0"
log = { version = "0.4", features = ["release_max_level_info"] }
gilrs = "0.8.0"

View File

@ -3,6 +3,7 @@ mod gilrs_system;
use bevy_app::{prelude::*, startup_stage::PRE_STARTUP};
use bevy_ecs::prelude::*;
use bevy_utils::tracing::error;
use gilrs::GilrsBuilder;
use gilrs_system::{gilrs_event_startup_system, gilrs_event_system};
@ -27,7 +28,7 @@ impl Plugin for GilrsPlugin {
gilrs_event_system.thread_local_system(),
);
}
Err(err) => log::error!("Failed to start Gilrs. {}", err),
Err(err) => error!("Failed to start Gilrs. {}", err),
}
}
}

View File

@ -14,9 +14,9 @@ keywords = ["game", "engine", "gamedev", "graphics", "bevy"]
categories = ["game-engines", "graphics", "gui", "rendering"]
[features]
profiler = ["bevy_ecs/profiler", "bevy_diagnostic/profiler"]
wgpu_trace = ["bevy_wgpu/trace"]
trace = [ "bevy_app/trace", "bevy_ecs/trace" ]
trace_chrome = [ "bevy_log/tracing-chrome" ]
# Image format support for texture loading (PNG and HDR are enabled by default)
hdr = ["bevy_render/hdr"]
@ -44,6 +44,7 @@ bevy_derive = { path = "../bevy_derive", version = "0.3.0" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_input = { path = "../bevy_input", version = "0.3.0" }
bevy_log = { path = "../bevy_log", version = "0.3.0" }
bevy_math = { path = "../bevy_math", version = "0.3.0" }
bevy_property = { path = "../bevy_property", version = "0.3.0" }
bevy_scene = { path = "../bevy_scene", version = "0.3.0" }

View File

@ -4,6 +4,7 @@ pub struct DefaultPlugins;
impl PluginGroup for DefaultPlugins {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(bevy_log::LogPlugin::default());
group.add(bevy_type_registry::TypeRegistryPlugin::default());
group.add(bevy_core::CorePlugin::default());
group.add(bevy_transform::TransformPlugin::default());

View File

@ -34,6 +34,11 @@ pub mod input {
pub use bevy_input::*;
}
pub mod log {
//! Logging capabilities
pub use bevy_log::*;
}
pub mod math {
//! Math types (Vec3, Mat4, Quat, etc) and helpers.
pub use bevy_math::*;

View File

@ -1,7 +1,8 @@
pub use crate::{
app::prelude::*, asset::prelude::*, core::prelude::*, ecs::prelude::*, input::prelude::*,
math::prelude::*, property::prelude::*, scene::prelude::*, transform::prelude::*,
type_registry::RegisterType, window::prelude::*, DefaultPlugins, MinimalPlugins,
log::prelude::*, math::prelude::*, property::prelude::*, scene::prelude::*,
transform::prelude::*, type_registry::RegisterType, window::prelude::*, DefaultPlugins,
MinimalPlugins,
};
pub use bevy_derive::bevy_main;

View File

@ -0,0 +1,28 @@
[package]
name = "bevy_log"
version = "0.3.0"
edition = "2018"
authors = [
"Bevy Contributors <bevyengine@gmail.com>",
"Carter Anderson <mcanders1@gmail.com>",
]
description = "Provides logging for Bevy Engine"
homepage = "https://bevyengine.org"
repository = "https://github.com/bevyengine/bevy"
license = "MIT"
keywords = ["bevy"]
[dependencies]
bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
tracing-subscriber = {version = "0.2.15", features = ["registry"]}
tracing-chrome = { version = "0.2.0", optional = true }
[target.'cfg(target_os = "android")'.dependencies]
android_log-sys = "0.2.0"
[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.6"
tracing-wasm = "0.1"

View File

@ -0,0 +1,98 @@
use bevy_utils::tracing::{
field::Field,
span::{Attributes, Record},
Event, Id, Level, Subscriber,
};
use std::fmt::{Debug, Write};
use tracing_subscriber::{field::Visit, layer::Context, registry::LookupSpan, Layer};
#[derive(Default)]
pub(crate) struct AndroidLayer;
struct StringRecorder(String, bool);
impl StringRecorder {
fn new() -> Self {
StringRecorder(String::new(), false)
}
}
impl Visit for StringRecorder {
fn record_debug(&mut self, field: &Field, value: &dyn Debug) {
if field.name() == "message" {
if !self.0.is_empty() {
self.0 = format!("{:?}\n{}", value, self.0)
} else {
self.0 = format!("{:?}", value)
}
} else {
if self.1 {
// following args
write!(self.0, " ").unwrap();
} else {
// first arg
self.1 = true;
}
write!(self.0, "{} = {:?};", field.name(), value).unwrap();
}
}
}
impl core::fmt::Display for StringRecorder {
fn fmt(&self, mut f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if !self.0.is_empty() {
write!(&mut f, " {}", self.0)
} else {
Ok(())
}
}
}
impl core::default::Default for StringRecorder {
fn default() -> Self {
StringRecorder::new()
}
}
impl<S: Subscriber + for<'a> LookupSpan<'a>> Layer<S> for AndroidLayer {
fn new_span(&self, attrs: &Attributes<'_>, id: &Id, ctx: Context<'_, S>) {
let mut new_debug_record = StringRecorder::new();
attrs.record(&mut new_debug_record);
if let Some(span_ref) = ctx.span(id) {
span_ref
.extensions_mut()
.insert::<StringRecorder>(new_debug_record);
}
}
fn on_record(&self, id: &Id, values: &Record<'_>, ctx: Context<'_, S>) {
if let Some(span_ref) = ctx.span(id) {
if let Some(debug_record) = span_ref.extensions_mut().get_mut::<StringRecorder>() {
values.record(debug_record);
}
}
}
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
let mut recorder = StringRecorder::new();
event.record(&mut recorder);
let meta = event.metadata();
let level = meta.level();
let priority = match *level {
Level::TRACE => android_log_sys::LogPriority::VERBOSE,
Level::DEBUG => android_log_sys::LogPriority::DEBUG,
Level::INFO => android_log_sys::LogPriority::INFO,
Level::WARN => android_log_sys::LogPriority::WARN,
Level::ERROR => android_log_sys::LogPriority::ERROR,
};
let message = format!("{}\0", recorder);
let tag = format!("{}\0", meta.name());
unsafe {
android_log_sys::__android_log_write(
priority as android_log_sys::c_int,
tag.as_ptr() as *const android_log_sys::c_char,
message.as_ptr() as *const android_log_sys::c_char,
);
}
}
}

View File

@ -0,0 +1,89 @@
#[cfg(target_os = "android")]
mod android_tracing;
pub mod prelude {
pub use bevy_utils::tracing::{
debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn, warn_span,
};
}
pub use bevy_utils::tracing::{
debug, debug_span, error, error_span, info, info_span, trace, trace_span, warn, warn_span,
Level,
};
use bevy_app::{AppBuilder, Plugin};
use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter};
/// Adds logging to Apps.
#[derive(Default)]
pub struct LogPlugin;
/// LogPlugin settings
pub struct LogSettings {
/// Filters logs using the [EnvFilter] format
pub filter: String,
/// Filters out logs that are "less than" the given level.
/// This can be further filtered using the `filter` setting.
pub level: Level,
}
impl Default for LogSettings {
fn default() -> Self {
Self {
filter: "wgpu=warn".to_string(),
level: Level::INFO,
}
}
}
impl Plugin for LogPlugin {
fn build(&self, app: &mut AppBuilder) {
let default_filter = {
let settings = app.resources_mut().get_or_insert_with(LogSettings::default);
format!("{},{}", settings.level, settings.filter)
};
let filter_layer = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new(&default_filter))
.unwrap();
let subscriber = Registry::default().with(filter_layer);
#[cfg(all(not(target_arch = "wasm32"), not(target_os = "android")))]
{
let fmt_layer = tracing_subscriber::fmt::Layer::default();
let subscriber = subscriber.with(fmt_layer);
#[cfg(feature = "tracing-chrome")]
{
let (chrome_layer, guard) = tracing_chrome::ChromeLayerBuilder::new().build();
app.resources_mut().insert_thread_local(guard);
let subscriber = subscriber.with(chrome_layer);
bevy_utils::tracing::subscriber::set_global_default(subscriber)
.expect("Could not set global default tracing subscriber");
}
#[cfg(not(feature = "tracing-chrome"))]
{
bevy_utils::tracing::subscriber::set_global_default(subscriber)
.expect("Could not set global default tracing subscriber");
}
}
#[cfg(target_arch = "wasm32")]
{
console_error_panic_hook::set_once();
let subscriber = subscriber.with(tracing_wasm::WASMLayer::new(
tracing_wasm::WASMLayerConfig::default(),
));
bevy_utils::tracing::subscriber::set_global_default(subscriber)
.expect("Could not set global default tracing subscriber");
}
#[cfg(target_os = "android")]
{
let subscriber = subscriber.with(android_tracing::AndroidLayer::default());
bevy_utils::tracing::subscriber::set_global_default(subscriber)
.expect("Could not set global default tracing subscriber");
}
}
}

View File

@ -30,7 +30,6 @@ bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
image = { version = "0.23", default-features = false }
# misc
log = { version = "0.4", features = ["release_max_level_info"] }
uuid = { version = "0.8", features = ["v4", "serde"] }
serde = { version = "1", features = ["derive"] }
bitflags = "1.2.1"

View File

@ -13,6 +13,7 @@ use crate::{
};
use bevy_asset::{Assets, Handle};
use bevy_ecs::{HecsQuery, ReadOnlyFetch, Resources, World};
use bevy_utils::tracing::debug;
use std::{fmt, marker::PhantomData, ops::Deref};
#[derive(Debug)]
@ -274,14 +275,14 @@ where
instances.clone(),
);
} else {
log::info!("Could not draw indexed because the pipeline layout wasn't fully set for pipeline: {:?}", draw_state.pipeline);
debug!("Could not draw indexed because the pipeline layout wasn't fully set for pipeline: {:?}", draw_state.pipeline);
}
}
RenderCommand::Draw { vertices, instances } => {
if draw_state.can_draw() {
render_pass.draw(vertices.clone(), instances.clone());
} else {
log::info!("Could not draw because the pipeline layout wasn't fully set for pipeline: {:?}", draw_state.pipeline);
debug!("Could not draw because the pipeline layout wasn't fully set for pipeline: {:?}", draw_state.pipeline);
}
}
RenderCommand::SetVertexBuffer {

View File

@ -22,5 +22,4 @@ bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
log = "0.4"
smallvec = { version = "1.4", features = ["serde"] }

View File

@ -1,5 +1,6 @@
use crate::components::{Children, Parent};
use bevy_ecs::{Command, Commands, Entity, Query, Resources, World};
use bevy_utils::tracing::debug;
pub fn run_on_hierarchy<T, S>(
children_query: &Query<&Children>,
@ -62,7 +63,7 @@ fn despawn_with_children_recursive_inner(world: &mut World, entity: Entity) {
}
if let Err(e) = world.despawn(entity) {
log::debug!("Failed to despawn entity {:?}: {}", entity, e);
debug!("Failed to despawn entity {:?}: {}", entity, e);
}
}

View File

@ -13,9 +13,7 @@ pub fn parent_update_system(
// Entities with a missing `Parent` (ie. ones that have a `PreviousParent`), remove
// them from the `Children` of the `PreviousParent`.
for (entity, previous_parent) in removed_parent_query.iter() {
log::trace!("Parent was removed from {:?}", entity);
if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) {
log::trace!(" > Removing {:?} from it's prev parent's children", entity);
previous_parent_children.0.retain(|e| *e != entity);
commands.remove_one::<PreviousParent>(entity);
}
@ -26,43 +24,30 @@ pub fn parent_update_system(
// Entities with a changed Parent (that also have a PreviousParent, even if None)
for (entity, parent, possible_previous_parent) in changed_parent_query.iter_mut() {
log::trace!("Parent changed for {:?}", entity);
if let Some(mut previous_parent) = possible_previous_parent {
// New and previous point to the same Entity, carry on, nothing to see here.
if previous_parent.0 == parent.0 {
log::trace!(" > But the previous parent is the same, ignoring...");
continue;
}
// Remove from `PreviousParent.Children`.
if let Ok(mut previous_parent_children) = children_query.get_mut(previous_parent.0) {
log::trace!(" > Removing {:?} from prev parent's children", entity);
(*previous_parent_children).0.retain(|e| *e != entity);
}
// Set `PreviousParent = Parent`.
*previous_parent = PreviousParent(parent.0);
} else {
log::trace!("Adding missing PreviousParent to {:?}", entity);
commands.insert_one(entity, PreviousParent(parent.0));
};
// Add to the parent's `Children` (either the real component, or
// `children_additions`).
log::trace!("Adding {:?} to it's new parent {:?}", entity, parent.0);
if let Ok(mut new_parent_children) = children_query.get_mut(parent.0) {
// This is the parent
log::trace!(
" > The new parent {:?} already has a `Children`, adding to it.",
parent.0
);
(*new_parent_children).0.push(entity);
} else {
// The parent doesn't have a children entity, lets add it
log::trace!(
"The new parent {:?} doesn't yet have `Children` component.",
parent.0
);
children_additions
.entry(parent.0)
.or_insert_with(Default::default)
@ -74,11 +59,6 @@ pub fn parent_update_system(
// collect multiple new children that point to the same parent into the same
// SmallVec, and to prevent redundant add+remove operations.
children_additions.iter().for_each(|(k, v)| {
log::trace!(
"Flushing: Entity {:?} adding `Children` component {:?}",
k,
v
);
commands.insert_one(*k, Children::with(v));
});
}

View File

@ -31,8 +31,6 @@ fn propagate_recursive(
children_query: &Query<Option<&Children>, (With<Parent>, With<GlobalTransform>)>,
entity: Entity,
) {
log::trace!("Updating Transform for {:?}", entity);
let global_matrix = {
if let Ok((transform, mut global_transform)) = transform_query.get_mut(entity) {
*global_transform = parent.mul_transform(*transform);

View File

@ -14,6 +14,7 @@ keywords = ["bevy"]
[dependencies]
ahash = "0.5.3"
tracing = {version = "0.1", features = ["release_max_level_info"]}
[target.'cfg(target_arch = "wasm32")'.dependencies]
getrandom = {version = "0.2.0", features = ["js"]}

View File

@ -2,6 +2,7 @@ use ahash::RandomState;
use std::{future::Future, pin::Pin};
pub use ahash::AHasher;
pub use tracing;
#[cfg(not(target_arch = "wasm32"))]
pub type BoxedFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;

View File

@ -31,7 +31,6 @@ bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
wgpu = "0.6"
futures-lite = "1.4.0"
log = { version = "0.4", features = ["release_max_level_info"] }
crossbeam-channel = "0.4.4"
crossbeam-utils = "0.7.2"
parking_lot = "0.11.0"

View File

@ -15,6 +15,7 @@ use bevy_render::{
shader::Shader,
texture::{Extent3d, SamplerDescriptor, TextureDescriptor},
};
use bevy_utils::tracing::trace;
use bevy_window::{Window, WindowId};
use futures_lite::future;
use std::{borrow::Cow, ops::Range, sync::Arc};
@ -459,7 +460,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
.resources
.has_bind_group(bind_group_descriptor_id, bind_group.id)
{
log::trace!(
trace!(
"start creating bind group for RenderResourceSet {:?}",
bind_group.id
);
@ -510,7 +511,7 @@ impl RenderResourceContext for WgpuRenderResourceContext {
bind_group_info
.bind_groups
.insert(bind_group.id, wgpu_bind_group);
log::trace!(
trace!(
"created bind group for RenderResourceSet {:?}",
bind_group.id
);

View File

@ -5,6 +5,7 @@ use bevy_render::{
pipeline::{BindGroupDescriptorId, PipelineDescriptor},
renderer::{BindGroupId, BufferId, RenderContext},
};
use bevy_utils::tracing::trace;
use std::ops::Range;
#[derive(Debug)]
@ -74,7 +75,7 @@ impl<'a> RenderPass for WgpuRenderPass<'a> {
EMPTY
};
log::trace!(
trace!(
"set bind group {:?} {:?}: {:?}",
bind_group_descriptor_id,
dynamic_uniform_indices,

View File

@ -27,7 +27,6 @@ bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other
winit = { version = "0.23.0", default-features = false }
log = { version = "0.4", features = ["release_max_level_info"] }
[target.'cfg(target_arch = "wasm32")'.dependencies]
winit = { version = "0.23.0", features = ["web-sys"], default-features = false }

View File

@ -12,6 +12,7 @@ pub use winit_windows::*;
use bevy_app::{prelude::*, AppExit};
use bevy_ecs::{IntoThreadLocalSystem, Resources, World};
use bevy_math::Vec2;
use bevy_utils::tracing::trace;
use bevy_window::{
CreateWindow, CursorMoved, ReceivedCharacter, Window, WindowCloseRequested, WindowCreated,
WindowResized, Windows,
@ -160,7 +161,7 @@ pub fn winit_runner(mut app: App) {
app.initialize();
log::debug!("Entering winit event loop");
trace!("Entering winit event loop");
let should_return_from_run = app
.resources

View File

@ -44,9 +44,13 @@ Make GUI applications use X11 protocol. You could enable wayland feature to over
## Optional Features
### profiler
### trace
For profiler.
Enables system tracing (useful in tandem wit a feature like trace_chrome)
### trace_chrome
Enables [tracing-chrome](https://github.com/thoren-d/tracing-chrome) as bevy_log output. This allows you to visualize system execution.
### wgpu_trace

30
examples/app/logs.rs Normal file
View File

@ -0,0 +1,30 @@
use bevy::prelude::*;
/// This example illustrates how to use logs in bevy
fn main() {
App::build()
// Uncomment this to override the default log settings:
// .add_resource(bevy::log::LogSettings {
// level: bevy::log::Level::TRACE,
// filter: "wgpu=warn,bevy_ecs=info".to_string(),
// })
.add_plugins(DefaultPlugins)
.add_system(log_system.system())
.run();
}
fn log_system() {
// here is how you write new logs at each "log level" (in "least important" to "most important" order)
trace!("very noisy");
debug!("helpful for debugging");
info!("helpful information that is worth printing by default");
warn!("something bad happened that isn't a failure, but thats worth calling out");
error!("something failed");
// by default, trace and debug logs are ignored because they are "noisy"
// you can control what level is logged by adding the LogSettings resource
// alternatively you can set the log level via the RUST_LOG=LEVEL environment variable
// ex: RUST_LOG=trace, RUST_LOG=info,bevy_ecs=warn
// the format used here is super flexible. check out this documentation for more info:
// https://docs.rs/tracing-subscriber/*/tracing_subscriber/filter/struct.EnvFilter.html
}

View File

@ -1,49 +0,0 @@
use bevy::{input::system::exit_on_esc_system, prelude::*};
use std::{thread, time};
use tracing::info;
use tracing_chrome::ChromeLayerBuilder;
use tracing_subscriber::{fmt, prelude::*, registry::Registry, EnvFilter};
pub fn setup_global_subscriber() -> impl Drop {
let fmt_layer = fmt::Layer::default();
let filter_layer = EnvFilter::try_from_default_env()
.or_else(|_| EnvFilter::try_new("info,wgpu=warn"))
.unwrap();
let (chrome_layer, _guard) = ChromeLayerBuilder::new().build();
let subscriber = Registry::default()
.with(filter_layer)
.with(fmt_layer)
.with(chrome_layer);
tracing::subscriber::set_global_default(subscriber).expect("Could not set global default");
_guard
}
fn main() {
let _guard = setup_global_subscriber();
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(a_system.system())
.add_system(foo_bar_baz.system())
.add_system(exit_on_esc_system.system())
.run();
}
fn a_system(commands: &mut Commands) {
let ten_millis = time::Duration::from_millis(10);
thread::sleep(ten_millis);
commands.spawn((GlobalTransform::default(), Transform::default()));
}
fn foo_bar_baz(query: Query<&Transform>) {
for transform in query.iter() {
let five_millis = time::Duration::from_millis(5);
thread::sleep(five_millis);
info!(?transform);
}
}

View File

@ -1,6 +1,3 @@
#[cfg(target_arch = "wasm32")]
extern crate console_error_panic_hook;
use bevy::{
asset::{AssetLoader, AssetServerSettings, LoadContext, LoadedAsset},
prelude::*,
@ -9,12 +6,6 @@ use bevy::{
};
fn main() {
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init_with_level(log::Level::Debug).expect("cannot initialize console_log");
}
App::build()
.add_resource(AssetServerSettings {
asset_folder: "/".to_string(),
@ -45,7 +36,7 @@ fn print_asset(mut state: ResMut<State>, rust_sources: Res<Assets<RustSourceCode
}
if let Some(code) = rust_sources.get(&state.handle) {
log::info!("code: {}", code.0);
info!("code: {}", code.0);
state.printed = true;
}
}

View File

@ -1,36 +1,29 @@
#[cfg(target_arch = "wasm32")]
extern crate console_error_panic_hook;
use bevy::{
app::{ScheduleRunnerPlugin, ScheduleRunnerSettings},
log::LogPlugin,
prelude::*,
};
use std::time::Duration;
fn main() {
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init_with_level(log::Level::Debug).expect("cannot initialize console_log");
}
App::build()
.add_resource(ScheduleRunnerSettings::run_loop(Duration::from_secs_f64(
1.0 / 60.0,
)))
.add_plugin(ScheduleRunnerPlugin::default())
.add_plugin(LogPlugin::default())
.add_startup_system(hello_world_system.system())
.add_system(counter.system())
.run();
}
fn hello_world_system() {
log::info!("hello wasm");
info!("hello wasm");
}
fn counter(mut state: Local<CounterState>) {
if state.count % 60 == 0 {
log::info!("counter system: {}", state.count);
info!("counter system: {}", state.count);
}
state.count += 1;
}

View File

@ -1,18 +1,12 @@
#[cfg(target_arch = "wasm32")]
extern crate console_error_panic_hook;
use bevy::prelude::*;
use bevy::{log::LogPlugin, prelude::*};
fn main() {
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init_with_level(log::Level::Debug).expect("cannot initialize console_log");
}
App::build().add_system(hello_wasm_system.system()).run();
App::build()
.add_plugin(LogPlugin::default())
.add_system(hello_wasm_system.system())
.run();
}
fn hello_wasm_system() {
log::info!("hello wasm");
info!("hello wasm");
}

View File

@ -1,6 +1,3 @@
#[cfg(target_arch = "wasm32")]
extern crate console_error_panic_hook;
use bevy::{
input::{
keyboard::KeyboardInput,
@ -10,12 +7,6 @@ use bevy::{
};
fn main() {
#[cfg(target_arch = "wasm32")]
{
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
console_log::init_with_level(log::Level::Debug).expect("cannot initialize console_log");
}
App::build()
.add_resource(WindowDescriptor {
width: 300,
@ -34,12 +25,12 @@ fn main() {
}
fn hello_wasm_system() {
log::info!("hello wasm");
info!("hello wasm");
}
fn counter(mut state: Local<CounterState>, time: Res<Time>) {
if state.count % 60 == 0 {
log::info!(
info!(
"tick {} @ {:?} [Δ{}]",
state.count,
time.time_since_startup(),
@ -74,37 +65,36 @@ fn track_input_events(
// Keyboard input
for ev in state.keys.iter(&ev_keys) {
if ev.state.is_pressed() {
log::info!("Just pressed key: {:?}", ev.key_code);
info!("Just pressed key: {:?}", ev.key_code);
} else {
log::info!("Just released key: {:?}", ev.key_code);
info!("Just released key: {:?}", ev.key_code);
}
}
// Absolute cursor position (in window coordinates)
for ev in state.cursor.iter(&ev_cursor) {
log::info!("Cursor at: {}", ev.position);
info!("Cursor at: {}", ev.position);
}
// Relative mouse motion
for ev in state.motion.iter(&ev_motion) {
log::info!("Mouse moved {} pixels", ev.delta);
info!("Mouse moved {} pixels", ev.delta);
}
// Mouse buttons
for ev in state.mousebtn.iter(&ev_mousebtn) {
if ev.state.is_pressed() {
log::info!("Just pressed mouse button: {:?}", ev.button);
info!("Just pressed mouse button: {:?}", ev.button);
} else {
log::info!("Just released mouse button: {:?}", ev.button);
info!("Just released mouse button: {:?}", ev.button);
}
}
// scrolling (mouse wheel, touchpad, etc.)
for ev in state.scroll.iter(&ev_scroll) {
log::info!(
info!(
"Scrolled vertically by {} and horizontally by {}.",
ev.y,
ev.x
ev.y, ev.x
);
}
}