1#![warn(missing_docs)]
10
11use std::sync::Mutex;
12#[cfg(target_arch = "wasm32")]
13use wasm_bindgen::prelude::*;
14
15struct Logger {
16 inner: env_logger::Logger,
17}
18
19static LOGGERS: once_cell::sync::Lazy<Mutex<Vec<Box<dyn log::Log>>>> =
20 once_cell::sync::Lazy::new(|| Mutex::new(Vec::new()));
21
22impl log::Log for Logger {
23 fn enabled(&self, metadata: &log::Metadata) -> bool {
24 if !self.inner.enabled(metadata) {
25 return false;
26 }
27 match metadata.target().split_terminator(':').next().unwrap() {
28 "ws" => metadata.level() <= log::Level::Error,
29 "mio" => false,
30 _ => true,
31 }
32 }
33
34 fn log(&self, record: &log::Record) {
35 if !self.enabled(record.metadata()) {
36 return;
37 }
38 self.inner.log(record);
39 if self.inner.matches(record) {
40 for logger in LOGGERS.lock().unwrap().iter_mut() {
41 if logger.enabled(record.metadata()) {
42 logger.log(record);
43 }
44 }
45 #[cfg(target_arch = "wasm32")]
46 {
47 #[wasm_bindgen]
48 extern "C" {
49 #[wasm_bindgen(js_namespace = console, js_name = log)]
50 fn console_log(s: &str);
51 }
52 console_log(&format!("{} - {}", record.level(), record.args()));
53 }
54 }
55 }
56
57 fn flush(&self) {
58 self.inner.flush();
59 for logger in LOGGERS.lock().unwrap().iter_mut() {
60 logger.flush();
61 }
62 }
63}
64
65pub fn init_with(mut builder: env_logger::Builder) -> Result<(), log::SetLoggerError> {
67 let builder_info = format!("{builder:?}");
68 let logger = Logger {
69 inner: builder.build(),
70 };
71 log::set_max_level(logger.inner.filter());
72 log::set_boxed_logger(Box::new(logger))?;
73 log::trace!("Logger initialized with {}", builder_info);
74 std::panic::set_hook(Box::new(|info| {
75 log::error!("{}", info);
76 log::error!("{:?}", backtrace::Backtrace::new());
77 }));
78 Ok(())
79}
80
81pub fn builder() -> env_logger::Builder {
83 let mut builder = env_logger::Builder::new();
84 builder
85 .filter_level(if cfg!(debug_assertions) {
86 log::LevelFilter::Debug
87 } else {
88 log::LevelFilter::Info
89 })
90 .format_timestamp(None)
91 .format_module_path(true)
92 .format_target(false)
93 .parse_env("LOG");
94 builder
95}
96
97pub fn init() {
99 try_init().expect("Failed to initialize logger");
100}
101
102pub fn try_init() -> Result<(), log::SetLoggerError> {
104 init_with(builder())
105}
106
107pub fn init_for_tests() {
109 let mut builder = builder();
110 builder.is_test(true);
111 let _ = init_with(builder);
112}
113
114pub fn add_logger(logger: Box<dyn log::Log>) {
116 LOGGERS.lock().unwrap().push(logger);
117}