use std::fmt::Write as _;
use std::sync::atomic::{AtomicUsize, Ordering};
use wasm_bindgen::prelude::*;
static MAX_LEVEL: AtomicUsize = AtomicUsize::new(2);
fn level_rank(level: &tracing::Level) -> usize {
match *level {
tracing::Level::ERROR => 0,
tracing::Level::WARN => 1,
tracing::Level::INFO => 2,
tracing::Level::DEBUG => 3,
tracing::Level::TRACE => 4,
}
}
struct ConsoleSubscriber;
struct FieldFormatter {
out: String,
}
impl tracing::field::Visit for FieldFormatter {
fn record_debug(&mut self, field: &tracing::field::Field, value: &dyn std::fmt::Debug) {
if field.name() == "message" {
let msg = format!("{value:?}");
let msg = msg.trim_matches('"');
if self.out.is_empty() {
self.out.push_str(msg);
} else {
let _ = write!(self.out, " {msg}");
}
} else {
let _ = write!(self.out, " {}={:?}", field.name(), value);
}
}
}
impl tracing::Subscriber for ConsoleSubscriber {
fn enabled(&self, metadata: &tracing::Metadata<'_>) -> bool {
level_rank(metadata.level()) <= MAX_LEVEL.load(Ordering::Relaxed)
}
fn new_span(&self, _span: &tracing::span::Attributes<'_>) -> tracing::span::Id {
tracing::span::Id::from_u64(1)
}
fn record(&self, _span: &tracing::span::Id, _values: &tracing::span::Record<'_>) {}
fn record_follows_from(&self, _span: &tracing::span::Id, _follows: &tracing::span::Id) {}
fn event(&self, event: &tracing::Event<'_>) {
let mut fmt = FieldFormatter { out: String::new() };
event.record(&mut fmt);
let line = format!("[{}] {}", event.metadata().target(), fmt.out);
let js = JsValue::from_str(&line);
match *event.metadata().level() {
tracing::Level::ERROR => web_sys::console::error_1(&js),
tracing::Level::WARN => web_sys::console::warn_1(&js),
tracing::Level::INFO => web_sys::console::info_1(&js),
_ => web_sys::console::debug_1(&js),
}
}
fn enter(&self, _span: &tracing::span::Id) {}
fn exit(&self, _span: &tracing::span::Id) {}
}
#[wasm_bindgen(js_name = initConsoleTracing)]
pub fn init_console_tracing(level: String) {
let rank = match level.as_str() {
"error" => 0,
"warn" => 1,
"debug" => 3,
"trace" => 4,
_ => 2, };
MAX_LEVEL.store(rank, Ordering::Relaxed);
let _ = tracing::subscriber::set_global_default(ConsoleSubscriber);
}