add documentation on LogPlugin and more log usage (#1973)

Fixes #1895 

Changed most `println` to `info` in examples, some to `warn` when it was useful to differentiate from other more noisy logs.

Added doc on `LogPlugin`, how to configure it, and why (and how) you may need to disable it
This commit is contained in:
François 2021-04-22 23:30:48 +00:00
parent 6508b4ed25
commit e3fb23d4d3
27 changed files with 173 additions and 78 deletions

View file

@ -1,55 +1,107 @@
use bevy_app::{PluginGroup, PluginGroupBuilder};
use bevy_app::ScheduleRunnerPlugin;
use bevy_asset::AssetPlugin;
#[cfg(feature = "bevy_audio")]
use bevy_audio::AudioPlugin;
use bevy_core::CorePlugin;
use bevy_diagnostic::DiagnosticsPlugin;
#[cfg(feature = "bevy_gilrs")]
use bevy_gilrs::GilrsPlugin;
#[cfg(feature = "bevy_gltf")]
use bevy_gltf::GltfPlugin;
use bevy_input::InputPlugin;
use bevy_log::LogPlugin;
#[cfg(feature = "bevy_pbr")]
use bevy_pbr::PbrPlugin;
#[cfg(feature = "bevy_render")]
use bevy_render::RenderPlugin;
use bevy_scene::ScenePlugin;
#[cfg(feature = "bevy_sprite")]
use bevy_sprite::SpritePlugin;
#[cfg(feature = "bevy_text")]
use bevy_text::TextPlugin;
use bevy_transform::TransformPlugin;
#[cfg(feature = "bevy_ui")]
use bevy_ui::UiPlugin;
#[cfg(feature = "bevy_wgpu")]
use bevy_wgpu::WgpuPlugin;
use bevy_window::WindowPlugin;
#[cfg(feature = "bevy_winit")]
use bevy_winit::WinitPlugin;
/// This plugin group will add all the default plugins:
/// * [`LogPlugin`]
/// * [`CorePlugin`]
/// * [`TransformPlugin`]
/// * [`DiagnosticsPlugin`]
/// * [`InputPlugin`]
/// * [`WindowPlugin`]
/// * [`AssetPlugin`]
/// * [`ScenePlugin`]
/// * [`RenderPlugin`] - with feature `bevy_render`
/// * [`SpritePlugin`] - with feature `bevy_sprite`
/// * [`PbrPlugin`] - with feature `bevy_pbr`
/// * [`UiPlugin`] - with feature `bevy_ui`
/// * [`TextPlugin`] - with feature `bevy_text`
/// * [`AudioPlugin`] - with feature `bevy_audio`
/// * [`GilrsPlugin`] - with feature `bevy_gilrs`
/// * [`GltfPlugin`] - with feature `bevy_gltf`
/// * [`WinitPlugin`] - with feature `bevy_winit`
/// * [`WgpuPlugin`] - with feature `bevy_wgpu`
pub struct DefaultPlugins;
impl PluginGroup for DefaultPlugins {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(bevy_log::LogPlugin::default());
group.add(bevy_core::CorePlugin::default());
group.add(bevy_transform::TransformPlugin::default());
group.add(bevy_diagnostic::DiagnosticsPlugin::default());
group.add(bevy_input::InputPlugin::default());
group.add(bevy_window::WindowPlugin::default());
group.add(bevy_asset::AssetPlugin::default());
group.add(bevy_scene::ScenePlugin::default());
group.add(LogPlugin::default());
group.add(CorePlugin::default());
group.add(TransformPlugin::default());
group.add(DiagnosticsPlugin::default());
group.add(InputPlugin::default());
group.add(WindowPlugin::default());
group.add(AssetPlugin::default());
group.add(ScenePlugin::default());
#[cfg(feature = "bevy_render")]
group.add(bevy_render::RenderPlugin::default());
group.add(RenderPlugin::default());
#[cfg(feature = "bevy_sprite")]
group.add(bevy_sprite::SpritePlugin::default());
group.add(SpritePlugin::default());
#[cfg(feature = "bevy_pbr")]
group.add(bevy_pbr::PbrPlugin::default());
group.add(PbrPlugin::default());
#[cfg(feature = "bevy_ui")]
group.add(bevy_ui::UiPlugin::default());
group.add(UiPlugin::default());
#[cfg(feature = "bevy_text")]
group.add(bevy_text::TextPlugin::default());
group.add(TextPlugin::default());
#[cfg(feature = "bevy_audio")]
group.add(bevy_audio::AudioPlugin::default());
group.add(AudioPlugin::default());
#[cfg(feature = "bevy_gilrs")]
group.add(bevy_gilrs::GilrsPlugin::default());
group.add(GilrsPlugin::default());
#[cfg(feature = "bevy_gltf")]
group.add(bevy_gltf::GltfPlugin::default());
group.add(GltfPlugin::default());
#[cfg(feature = "bevy_winit")]
group.add(bevy_winit::WinitPlugin::default());
group.add(WinitPlugin::default());
#[cfg(feature = "bevy_wgpu")]
group.add(bevy_wgpu::WgpuPlugin::default());
group.add(WgpuPlugin::default());
}
}
/// Minimal plugin group that will add the following plugins:
/// * [`CorePlugin`]
/// * [`ScheduleRunnerPlugin`]
pub struct MinimalPlugins;
impl PluginGroup for MinimalPlugins {
fn build(&mut self, group: &mut PluginGroupBuilder) {
group.add(bevy_core::CorePlugin::default());
group.add(bevy_app::ScheduleRunnerPlugin::default());
group.add(CorePlugin::default());
group.add(ScheduleRunnerPlugin::default());
}
}

View file

@ -26,3 +26,6 @@ android_log-sys = "0.2.0"
[target.'cfg(target_arch = "wasm32")'.dependencies]
console_error_panic_hook = "0.1.6"
tracing-wasm = "0.2"
[dev-dependencies]
bevy_internal = { path = "../bevy_internal", version = "0.5.0" }

View file

@ -16,13 +16,53 @@ use bevy_app::{AppBuilder, Plugin};
use tracing_subscriber::fmt::{format::DefaultFields, FormattedFields};
use tracing_subscriber::{prelude::*, registry::Registry, EnvFilter};
/// Adds logging to Apps.
/// Adds logging to Apps. This plugin is part of the `DefaultPlugins`. Adding
/// this plugin will setup a collector appropriate to your target platform:
/// * Using [`tracing-subscriber`](https://crates.io/crates/tracing-subscriber) by default,
/// logging to `stdout`.
/// * Using [`android_log-sys`](https://crates.io/crates/android_log-sys) on Android,
/// logging to Android logs.
/// * Using [`tracing-wasm`](https://crates.io/crates/tracing-wasm) in WASM, logging
/// to the browser console.
///
/// You can configure this plugin using the resource [`LogSettings`].
/// ```no_run
/// # use bevy_internal::DefaultPlugins;
/// # use bevy_app::App;
/// # use bevy_log::LogSettings;
/// # use bevy_utils::tracing::Level;
/// fn main() {
/// App::build()
/// .insert_resource(LogSettings {
/// level: Level::DEBUG,
/// filter: "wgpu=error,bevy_render=info".to_string(),
/// })
/// .add_plugins(DefaultPlugins)
/// .run();
/// }
/// ```
///
/// Log level can also be changed using the `RUST_LOG` environment variable.
/// It has the same syntax has the field [`LogSettings::filter`], see [`EnvFilter`].
///
/// If you want to setup your own tracing collector, you should disable this
/// plugin from `DefaultPlugins` with [`AppBuilder::add_plugins_with`]:
/// ```no_run
/// # use bevy_internal::DefaultPlugins;
/// # use bevy_app::App;
/// # use bevy_log::LogPlugin;
/// fn main() {
/// App::build()
/// .add_plugins_with(DefaultPlugins, |group| group.disable::<LogPlugin>())
/// .run();
/// }
/// ```
#[derive(Default)]
pub struct LogPlugin;
/// LogPlugin settings
pub struct LogSettings {
/// Filters logs using the [EnvFilter] format
/// Filters logs using the [`EnvFilter`] format
pub filter: String,
/// Filters out logs that are "less than" the given level.

View file

@ -90,7 +90,7 @@ fn tick(time: Res<Time>, sprites: Query<&Sprite>, mut query: Query<&mut PrintTim
timer.0.tick(time.delta());
if timer.0.just_finished() {
println!("Sprites: {}", sprites.iter().count(),);
info!("Sprites: {}", sprites.iter().count(),);
}
}
}

View file

@ -9,6 +9,6 @@ fn main() {
fn file_drag_and_drop_system(mut events: EventReader<FileDragAndDrop>) {
for event in events.iter() {
println!("{:?}", event);
info!("{:?}", event);
}
}

View file

@ -40,6 +40,6 @@ struct PrintMessageState {
fn print_message_system(mut state: ResMut<PrintMessageState>, time: Res<Time>) {
if state.timer.tick(time.delta()).finished() {
println!("{}", state.message);
info!("{}", state.message);
}
}

View file

@ -34,7 +34,7 @@ impl Plugin for PrintHelloPlugin {
}
fn print_hello_system() {
println!("hello");
info!("hello");
}
pub struct PrintWorldPlugin;
@ -46,5 +46,5 @@ impl Plugin for PrintWorldPlugin {
}
fn print_world_system() {
println!("world");
info!("world");
}

View file

@ -31,9 +31,9 @@ fn setup(
// You might notice that this doesn't run! This is because assets load in parallel without
// blocking. When an asset has loaded, it will appear in relevant Assets<T>
// collection.
println!("{:?}", sphere.primitive_topology());
info!("{:?}", sphere.primitive_topology());
} else {
println!("sphere hasn't loaded yet");
info!("sphere hasn't loaded yet");
}
// You can load all assets in a folder like this. They will be loaded in parallel without

View file

@ -60,6 +60,6 @@ fn print_on_load(mut state: ResMut<State>, custom_assets: ResMut<Assets<CustomAs
return;
}
println!("Custom asset loaded: {:?}", custom_asset.unwrap());
info!("Custom asset loaded: {:?}", custom_asset.unwrap());
state.printed = true;
}

View file

@ -14,7 +14,7 @@ struct CustomAssetIo(Box<dyn AssetIo>);
impl AssetIo for CustomAssetIo {
fn load_path<'a>(&'a self, path: &'a Path) -> BoxedFuture<'a, Result<Vec<u8>, AssetIoError>> {
println!("load_path({:?})", path);
info!("load_path({:?})", path);
self.0.load_path(path)
}
@ -22,22 +22,22 @@ impl AssetIo for CustomAssetIo {
&self,
path: &Path,
) -> Result<Box<dyn Iterator<Item = PathBuf>>, AssetIoError> {
println!("read_directory({:?})", path);
info!("read_directory({:?})", path);
self.0.read_directory(path)
}
fn is_directory(&self, path: &Path) -> bool {
println!("is_directory({:?})", path);
info!("is_directory({:?})", path);
self.0.is_directory(path)
}
fn watch_path_for_changes(&self, path: &Path) -> Result<(), AssetIoError> {
println!("watch_path_for_changes({:?})", path);
info!("watch_path_for_changes({:?})", path);
self.0.watch_path_for_changes(path)
}
fn watch_for_changes(&self) -> Result<(), AssetIoError> {
println!("watch_for_changes()");
info!("watch_for_changes()");
self.0.watch_for_changes()
}
}

View file

@ -44,6 +44,6 @@ fn event_trigger_system(
// prints events as they come in
fn event_listener_system(mut events: EventReader<MyEvent>) {
for my_event in events.iter() {
println!("{}", my_event.message);
info!("{}", my_event.message);
}
}

View file

@ -30,18 +30,18 @@ fn main() {
}
fn frame_update(mut last_time: Local<f64>, time: Res<Time>) {
println!("update: {}", time.seconds_since_startup() - *last_time);
info!("update: {}", time.seconds_since_startup() - *last_time);
*last_time = time.seconds_since_startup();
}
fn fixed_update(mut last_time: Local<f64>, time: Res<Time>, fixed_timesteps: Res<FixedTimesteps>) {
println!(
info!(
"fixed_update: {}",
time.seconds_since_startup() - *last_time,
);
let fixed_timestep = fixed_timesteps.get(LABEL).unwrap();
println!(
info!(
" overstep_percentage: {}",
fixed_timestep.overstep_percentage()
);

View file

@ -10,6 +10,6 @@ fn main() {
/// This system prints out all char events as they come in
fn print_char_event_system(mut char_input_events: EventReader<ReceivedCharacter>) {
for event in char_input_events.iter() {
println!("{:?}: '{}'", event, event.char);
info!("{:?}: '{}'", event, event.char);
}
}

View file

@ -26,11 +26,11 @@ fn connection_system(
match &event {
GamepadEvent(gamepad, GamepadEventType::Connected) => {
lobby.gamepads.insert(*gamepad);
println!("{:?} Connected", gamepad);
info!("{:?} Connected", gamepad);
}
GamepadEvent(gamepad, GamepadEventType::Disconnected) => {
lobby.gamepads.remove(gamepad);
println!("{:?} Disconnected", gamepad);
info!("{:?} Disconnected", gamepad);
}
_ => (),
}
@ -45,23 +45,23 @@ fn gamepad_system(
) {
for gamepad in lobby.gamepads.iter().cloned() {
if button_inputs.just_pressed(GamepadButton(gamepad, GamepadButtonType::South)) {
println!("{:?} just pressed South", gamepad);
info!("{:?} just pressed South", gamepad);
} else if button_inputs.just_released(GamepadButton(gamepad, GamepadButtonType::South)) {
println!("{:?} just released South", gamepad);
info!("{:?} just released South", gamepad);
}
let right_trigger = button_axes
.get(GamepadButton(gamepad, GamepadButtonType::RightTrigger2))
.unwrap();
if right_trigger.abs() > 0.01 {
println!("{:?} RightTrigger2 value is {}", gamepad, right_trigger);
info!("{:?} RightTrigger2 value is {}", gamepad, right_trigger);
}
let left_stick_x = axes
.get(GamepadAxis(gamepad, GamepadAxisType::LeftStickX))
.unwrap();
if left_stick_x.abs() > 0.01 {
println!("{:?} LeftStickX value is {}", gamepad, left_stick_x);
info!("{:?} LeftStickX value is {}", gamepad, left_stick_x);
}
}
}

View file

@ -14,16 +14,16 @@ fn gamepad_events(mut gamepad_event: EventReader<GamepadEvent>) {
for event in gamepad_event.iter() {
match &event {
GamepadEvent(gamepad, GamepadEventType::Connected) => {
println!("{:?} Connected", gamepad);
info!("{:?} Connected", gamepad);
}
GamepadEvent(gamepad, GamepadEventType::Disconnected) => {
println!("{:?} Disconnected", gamepad);
info!("{:?} Disconnected", gamepad);
}
GamepadEvent(gamepad, GamepadEventType::ButtonChanged(button_type, value)) => {
println!("{:?} of {:?} is changed to {}", button_type, gamepad, value);
info!("{:?} of {:?} is changed to {}", button_type, gamepad, value);
}
GamepadEvent(gamepad, GamepadEventType::AxisChanged(axis_type, value)) => {
println!("{:?} of {:?} is changed to {}", axis_type, gamepad, value);
info!("{:?} of {:?} is changed to {}", axis_type, gamepad, value);
}
}
}

View file

@ -13,14 +13,14 @@ fn main() {
/// This system prints 'A' key state
fn keyboard_input_system(keyboard_input: Res<Input<KeyCode>>) {
if keyboard_input.pressed(KeyCode::A) {
println!("'A' currently pressed");
info!("'A' currently pressed");
}
if keyboard_input.just_pressed(KeyCode::A) {
println!("'A' just pressed");
info!("'A' just pressed");
}
if keyboard_input.just_released(KeyCode::A) {
println!("'A' just released");
info!("'A' just released");
}
}

View file

@ -10,6 +10,6 @@ fn main() {
/// This system prints out all keyboard events as they come in
fn print_keyboard_event_system(mut keyboard_input_events: EventReader<KeyboardInput>) {
for event in keyboard_input_events.iter() {
println!("{:?}", event);
info!("{:?}", event);
}
}

View file

@ -16,6 +16,6 @@ fn keyboard_input_system(input: Res<Input<KeyCode>>) {
let ctrl = input.pressed(KeyCode::LControl) || input.pressed(KeyCode::RControl);
if ctrl && shift && input.just_pressed(KeyCode::A) {
println!("Just pressed Ctrl + Shift + A!");
info!("Just pressed Ctrl + Shift + A!");
}
}

View file

@ -10,14 +10,14 @@ fn main() {
// This system prints messages when you press or release the left mouse button:
fn mouse_click_system(mouse_button_input: Res<Input<MouseButton>>) {
if mouse_button_input.pressed(MouseButton::Left) {
println!("left mouse currently pressed");
info!("left mouse currently pressed");
}
if mouse_button_input.just_pressed(MouseButton::Left) {
println!("left mouse just pressed");
info!("left mouse just pressed");
}
if mouse_button_input.just_released(MouseButton::Left) {
println!("left mouse just released");
info!("left mouse just released");
}
}

View file

@ -19,18 +19,18 @@ fn print_mouse_events_system(
mut mouse_wheel_events: EventReader<MouseWheel>,
) {
for event in mouse_button_input_events.iter() {
println!("{:?}", event);
info!("{:?}", event);
}
for event in mouse_motion_events.iter() {
println!("{:?}", event);
info!("{:?}", event);
}
for event in cursor_moved_events.iter() {
println!("{:?}", event);
info!("{:?}", event);
}
for event in mouse_wheel_events.iter() {
println!("{:?}", event);
info!("{:?}", event);
}
}

View file

@ -9,7 +9,7 @@ fn main() {
fn touch_system(touches: Res<Touches>) {
for touch in touches.iter_just_pressed() {
println!(
info!(
"just pressed touch with id: {:?}, at: {:?}",
touch.id(),
touch.position()
@ -17,7 +17,7 @@ fn touch_system(touches: Res<Touches>) {
}
for touch in touches.iter_just_released() {
println!(
info!(
"just released touch with id: {:?}, at: {:?}",
touch.id(),
touch.position()
@ -25,12 +25,12 @@ fn touch_system(touches: Res<Touches>) {
}
for touch in touches.iter_just_cancelled() {
println!("cancelled touch with id: {:?}", touch.id());
info!("cancelled touch with id: {:?}", touch.id());
}
// you can also iterate all current touches and retrieve their state like this:
for touch in touches.iter() {
println!("active touch: {:?}", touch);
println!(" just_pressed: {}", touches.just_pressed(touch.id()));
info!("active touch: {:?}", touch);
info!(" just_pressed: {}", touches.just_pressed(touch.id()));
}
}

View file

@ -9,6 +9,6 @@ fn main() {
fn touch_event_system(mut touch_events: EventReader<TouchInput>) {
for event in touch_events.iter() {
println!("{:?}", event);
info!("{:?}", event);
}
}

View file

@ -19,7 +19,7 @@ fn setup(type_registry: Res<TypeRegistry>) {
let type_registry = type_registry.read();
let registration = type_registry.get(TypeId::of::<MyType<u32>>()).unwrap();
println!("Registration for {} exists", registration.short_name());
info!("Registration for {} exists", registration.short_name());
// MyType<String> was not manually registered, so it does not exist
assert!(type_registry.get(TypeId::of::<MyType<String>>()).is_none());

View file

@ -75,7 +75,7 @@ fn setup(type_registry: Res<TypeRegistry>) {
let serializer = ReflectSerializer::new(&value, &type_registry);
let ron_string =
ron::ser::to_string_pretty(&serializer, ron::ser::PrettyConfig::default()).unwrap();
println!("{}\n", ron_string);
info!("{}\n", ron_string);
// Dynamic properties can be deserialized
let reflect_deserializer = ReflectDeserializer::new(&type_registry);

View file

@ -66,7 +66,7 @@ fn setup() {
// `Struct` is a trait automatically implemented for structs that derive Reflect. This trait
// allows you to interact with fields via their string names or indices
ReflectRef::Struct(value) => {
println!(
info!(
"This is a 'struct' type with an 'x' value of {}",
value.get_field::<usize>("x").unwrap()
)

View file

@ -51,7 +51,7 @@ fn setup(type_registry: Res<TypeRegistry>) {
let my_trait: &dyn DoThing = reflect_do_thing.get(&*reflect_value).unwrap();
// Which means we can now call do_thing(). Magic!
println!("{}", my_trait.do_thing());
info!("{}", my_trait.do_thing());
// This works because the #[reflect(MyTrait)] we put on MyType informed the Reflect derive to
// insert a new instance of ReflectDoThing into MyType's registration. The instance knows

View file

@ -9,7 +9,7 @@ fn main() {
.add_startup_system(save_scene_system.exclusive_system())
.add_startup_system(load_scene_system.system())
.add_startup_system(infotext_system.system())
.add_system(print_system.system())
.add_system(log_system.system())
.run();
}
@ -62,12 +62,12 @@ fn load_scene_system(asset_server: Res<AssetServer>, mut scene_spawner: ResMut<S
asset_server.watch_for_changes().unwrap();
}
// This system prints all ComponentA components in our world. Try making a change to a ComponentA in
// This system logs all ComponentA components in our world. Try making a change to a ComponentA in
// load_scene_example.scn. You should immediately see the changes appear in the console.
fn print_system(query: Query<(Entity, &ComponentA), Changed<ComponentA>>) {
fn log_system(query: Query<(Entity, &ComponentA), Changed<ComponentA>>) {
for (entity, component_a) in query.iter() {
println!(" Entity({})", entity.id());
println!(
info!(" Entity({})", entity.id());
info!(
" ComponentA: {{ x: {} y: {} }}\n",
component_a.x, component_a.y
);
@ -95,7 +95,7 @@ fn save_scene_system(world: &mut World) {
let scene = DynamicScene::from_world(&scene_world, &type_registry);
// Scenes can be serialized like this:
println!("{}", scene.serialize_ron(&type_registry).unwrap());
info!("{}", scene.serialize_ron(&type_registry).unwrap());
// TODO: save scene
}