1pub struct WebLogger {
3 filter: log::LevelFilter,
4}
5
6impl WebLogger {
7 pub fn init(filter: log::LevelFilter) -> Result<(), log::SetLoggerError> {
9 log::set_max_level(filter);
10 log::set_boxed_logger(Box::new(Self::new(filter)))
11 }
12
13 pub fn new(filter: log::LevelFilter) -> Self {
16 Self { filter }
17 }
18}
19
20impl log::Log for WebLogger {
21 fn enabled(&self, metadata: &log::Metadata<'_>) -> bool {
22 const CRATES_AT_INFO_LEVEL: &[&str] = &[
24 "naga",
26 "wgpu_core",
27 "wgpu_hal",
28 ];
29
30 if CRATES_AT_INFO_LEVEL
31 .iter()
32 .any(|crate_name| metadata.target().starts_with(crate_name))
33 {
34 return metadata.level() <= log::LevelFilter::Info;
35 }
36
37 metadata.level() <= self.filter
38 }
39
40 fn log(&self, record: &log::Record<'_>) {
41 #![expect(clippy::match_same_arms)]
42
43 if !self.enabled(record.metadata()) {
44 return;
45 }
46
47 let msg = if let (Some(file), Some(line)) = (record.file(), record.line()) {
48 let file = shorten_file_path(file);
49 format!("[{}] {file}:{line}: {}", record.target(), record.args())
50 } else {
51 format!("[{}] {}", record.target(), record.args())
52 };
53
54 match record.level() {
55 log::Level::Trace => console::debug(&msg),
57
58 log::Level::Debug => console::debug(&msg),
59 log::Level::Info => console::info(&msg),
60 log::Level::Warn => console::warn(&msg),
61
62 log::Level::Error => console::warn(&format!("ERROR: {msg}")),
66 }
67 }
68
69 fn flush(&self) {}
70}
71
72mod console {
74 use wasm_bindgen::prelude::*;
75
76 #[wasm_bindgen]
77 extern "C" {
78 #[wasm_bindgen(js_namespace = console)]
80 pub fn trace(s: &str);
81
82 #[wasm_bindgen(js_namespace = console)]
84 pub fn debug(s: &str);
85
86 #[wasm_bindgen(js_namespace = console)]
88 pub fn info(s: &str);
89
90 #[wasm_bindgen(js_namespace = console)]
92 pub fn warn(s: &str);
93
94 }
100}
101
102#[allow(clippy::allow_attributes, dead_code)] fn shorten_file_path(file_path: &str) -> &str {
115 if let Some(i) = file_path.rfind("/src/") {
116 if let Some(prev_slash) = file_path[..i].rfind('/') {
117 &file_path[prev_slash + 1..]
118 } else {
119 file_path
120 }
121 } else {
122 file_path
123 }
124}
125
126#[test]
127fn test_shorten_file_path() {
128 for (before, after) in [
129 (
130 "/Users/emilk/.cargo/registry/src/github.com-1ecc6299db9ec823/tokio-1.24.1/src/runtime/runtime.rs",
131 "tokio-1.24.1/src/runtime/runtime.rs",
132 ),
133 ("crates/rerun/src/main.rs", "rerun/src/main.rs"),
134 (
135 "/rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/ops/function.rs",
136 "core/src/ops/function.rs",
137 ),
138 ("/weird/path/file.rs", "/weird/path/file.rs"),
139 ] {
140 assert_eq!(shorten_file_path(before), after);
141 }
142}