diff --git a/Cargo.lock b/Cargo.lock index fc8c29cc..e255f1fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1303,6 +1303,7 @@ dependencies = [ "smallvec", "tempfile", "tracing", + "tracing-subscriber", "unicode-segmentation", "vello", "wgpu", @@ -1430,6 +1431,16 @@ dependencies = [ "jni-sys", ] +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -1569,6 +1580,12 @@ dependencies = [ "libredox", ] +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + [[package]] name = "owned_ttf_parser" version = "0.20.0" @@ -2348,6 +2365,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", ] [[package]] @@ -2356,9 +2385,12 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ + "nu-ansi-term", "sharded-slab", + "smallvec", "thread_local", "tracing-core", + "tracing-log", ] [[package]] @@ -2402,6 +2434,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "vello" version = "0.1.0" diff --git a/crates/masonry/Cargo.toml b/crates/masonry/Cargo.toml index 143abe96..f4ab9c62 100644 --- a/crates/masonry/Cargo.toml +++ b/crates/masonry/Cargo.toml @@ -36,6 +36,7 @@ pollster = "0.3.0" unicode-segmentation = "1.11.0" # TODO: Is this still the most up-to-date crate for this? xi-unicode = "0.3.0" +tracing-subscriber = "0.3.18" [dev-dependencies] float-cmp = { version = "0.8.0", features = ["std"], default-features = false } diff --git a/crates/masonry/examples/calc.rs b/crates/masonry/examples/calc.rs index 13bbd852..a8a7e4e3 100644 --- a/crates/masonry/examples/calc.rs +++ b/crates/masonry/examples/calc.rs @@ -358,5 +358,5 @@ pub fn main() { in_num: false, }; - masonry::event_loop_runner::run(build_calc(), window, event_loop, calc_state); + masonry::event_loop_runner::run(build_calc(), window, event_loop, calc_state).unwrap(); } diff --git a/crates/masonry/examples/custom_widget.rs b/crates/masonry/examples/custom_widget.rs index 1be86148..67d05be7 100644 --- a/crates/masonry/examples/custom_widget.rs +++ b/crates/masonry/examples/custom_widget.rs @@ -143,7 +143,7 @@ pub fn main() { .create_window(Window::default_attributes().with_title("Fancy colots")) .unwrap(); - masonry::event_loop_runner::run(CustomWidget(my_string), window, event_loop, Driver); + masonry::event_loop_runner::run(CustomWidget(my_string), window, event_loop, Driver).unwrap(); } fn make_image_data(width: usize, height: usize) -> Vec { diff --git a/crates/masonry/examples/hello_masonry.rs b/crates/masonry/examples/hello_masonry.rs index 01d85adf..87ec71e8 100644 --- a/crates/masonry/examples/hello_masonry.rs +++ b/crates/masonry/examples/hello_masonry.rs @@ -45,7 +45,7 @@ pub fn main() { ) .unwrap(); - masonry::event_loop_runner::run(build_root_widget(), window, event_loop, Driver); + masonry::event_loop_runner::run(build_root_widget(), window, event_loop, Driver).unwrap(); } fn build_root_widget() -> impl Widget { diff --git a/crates/masonry/examples/simple_image.rs b/crates/masonry/examples/simple_image.rs index 174d2991..4c5219b2 100644 --- a/crates/masonry/examples/simple_image.rs +++ b/crates/masonry/examples/simple_image.rs @@ -41,5 +41,5 @@ pub fn main() { ) .unwrap(); - masonry::event_loop_runner::run(image, window, event_loop, Driver); + masonry::event_loop_runner::run(image, window, event_loop, Driver).unwrap(); } diff --git a/crates/masonry/src/event_loop_runner.rs b/crates/masonry/src/event_loop_runner.rs index 8f4f0ced..ff45d8c0 100644 --- a/crates/masonry/src/event_loop_runner.rs +++ b/crates/masonry/src/event_loop_runner.rs @@ -4,6 +4,7 @@ use std::num::NonZeroUsize; use std::sync::Arc; +use tracing::subscriber::SetGlobalDefaultError; use tracing::warn; use vello::kurbo::Affine; use vello::util::{RenderContext, RenderSurface}; @@ -11,6 +12,7 @@ use vello::{peniko::Color, AaSupport, RenderParams, Renderer, RendererOptions, S use wgpu::PresentMode; use winit::application::ApplicationHandler; use winit::dpi::LogicalPosition; +use winit::error::EventLoopError; use winit::event::WindowEvent as WinitWindowEvent; use winit::event_loop::{ActiveEventLoop, EventLoop}; use winit::window::{Window, WindowId}; @@ -35,7 +37,7 @@ pub fn run( window: Window, event_loop: EventLoop<()>, app_driver: impl AppDriver + 'static, -) { +) -> Result<(), EventLoopError> { let window = Arc::new(window); let mut render_cx = RenderContext::new().unwrap(); let size = window.inner_size(); @@ -57,13 +59,20 @@ pub fn run( app_driver: Box::new(app_driver), }; - let _ = event_loop.run_app(&mut main_state); + // If there is no default tracing subscriber, we set our own. If one has + // already been set, we get an error which we swallow. + // By now, we're about to take control of the event loop. The user is unlikely + // to try to set their own subscriber once the event loop has started. + let _ = try_init_tracing(); + + event_loop.run_app(&mut main_state) } impl ApplicationHandler for MainState<'_> { fn resumed(&mut self, _event_loop: &ActiveEventLoop) { // FIXME: initialize window in this handler because initializing it before running the event loop is deprecated } + fn window_event(&mut self, event_loop: &ActiveEventLoop, _: WindowId, event: WinitWindowEvent) { match event { WinitWindowEvent::RedrawRequested => { @@ -249,3 +258,45 @@ impl MainState<'_> { device.poll(wgpu::Maintain::Wait); } } + +pub(crate) fn try_init_tracing() -> Result<(), SetGlobalDefaultError> { + #[cfg(not(target_arch = "wasm32"))] + { + use tracing_subscriber::filter::LevelFilter; + use tracing_subscriber::prelude::*; + let filter_layer = if cfg!(debug_assertions) { + LevelFilter::DEBUG + } else { + LevelFilter::INFO + }; + let fmt_layer = tracing_subscriber::fmt::layer() + // Display target (eg "my_crate::some_mod::submod") with logs + .with_target(true); + + let registry = tracing_subscriber::registry() + .with(filter_layer) + .with(fmt_layer); + tracing::dispatcher::set_global_default(registry.into()) + } + + // Note - tracing-wasm might not work in headless Node.js. Probably doesn't matter anyway, + // because this is a GUI framework, so wasm targets will virtually always be browsers. + #[cfg(target_arch = "wasm32")] + { + // Ignored if the panic hook is already set + console_error_panic_hook::set_once(); + + let max_level = if cfg!(debug_assertions) { + tracing::Level::DEBUG + } else { + tracing::Level::INFO + }; + let config = tracing_wasm::WASMLayerConfigBuilder::new() + .set_max_level(max_level) + .build(); + + tracing::subscriber::set_global_default( + Registry::default().with(tracing_wasm::WASMLayer::new(config)), + ) + } +} diff --git a/crates/masonry/src/testing/harness.rs b/crates/masonry/src/testing/harness.rs index 614ed28e..9f4aec78 100644 --- a/crates/masonry/src/testing/harness.rs +++ b/crates/masonry/src/testing/harness.rs @@ -20,6 +20,7 @@ use super::screenshots::get_image_diff; use super::snapshot_utils::get_cargo_workspace; use crate::action::Action; use crate::event::{PointerEvent, PointerState, TextEvent, WindowEvent}; +use crate::event_loop_runner::try_init_tracing; use crate::render_root::{RenderRoot, RenderRootSignal, WindowSizePolicy}; use crate::widget::{WidgetMut, WidgetRef}; use crate::{Color, Handled, Point, Size, Vec2, Widget, WidgetId}; @@ -173,6 +174,13 @@ impl TestHarness { let mouse_state = PointerState::empty(); let window_size = PhysicalSize::new(window_size.width as _, window_size.height as _); + // If there is no default tracing subscriber, we set our own. If one has + // already been set, we get an error which we swallow. + // Having a default subscriber is helpful for tests; swallowing errors means + // we don't panic if the user has already set one, or a test creates multiple + // harnesses. + let _ = try_init_tracing(); + let mut harness = TestHarness { render_root: RenderRoot::new(root_widget, WindowSizePolicy::User, 1.0), mouse_state, diff --git a/crates/xilem_masonry/src/lib.rs b/crates/xilem_masonry/src/lib.rs index b3405f9f..8f46e4c4 100644 --- a/crates/xilem_masonry/src/lib.rs +++ b/crates/xilem_masonry/src/lib.rs @@ -196,8 +196,7 @@ where Logic: 'static, View: 'static, { - event_loop_runner::run(self.root_widget, window, event_loop, self.driver); - Ok(()) + event_loop_runner::run(self.root_widget, window, event_loop, self.driver) } } pub trait MasonryView: Send + 'static {