use std::sync::atomic::AtomicIsize;
use tracing_subscriber::prelude::*;
#[cfg(not(target_arch = "wasm32"))]
const LOG_FILE_LINE: bool = false;
pub fn setup_logging() {
setup_logging_with_filter(&crate::default_log_filter());
}
pub fn setup_logging_with_filter(log_filter: &str) {
#[cfg(not(target_arch = "wasm32"))]
fn create_tracing_subscriber(log_filter: &str) -> impl tracing::Subscriber {
if cfg!(debug_assertions) && std::env::var("RUST_BACKTRACE").is_err() {
#[expect(unsafe_code)]
unsafe {
std::env::set_var("RUST_BACKTRACE", "1"); }
}
let fmt_layer = tracing_subscriber::fmt::layer()
.with_writer(std::io::stderr)
.with_file(LOG_FILE_LINE)
.with_line_number(LOG_FILE_LINE);
let env_filter = tracing_subscriber::EnvFilter::new(log_filter);
let panic_on_warn = PanicOnWarn {
always_enabled: env_var_bool("RERUN_PANIC_ON_WARN") == Some(true),
};
tracing_subscriber::registry()
.with(env_filter)
.with(fmt_layer)
.with(panic_on_warn)
.with(crate::channel_logger::channel_logger())
}
#[cfg(target_arch = "wasm32")]
fn create_tracing_subscriber(_log_filter: &str) -> impl tracing::Subscriber {
let fmt_layer = tracing_subscriber::Layer::with_filter(
tracing_subscriber::fmt::layer()
.with_ansi(false)
.without_time()
.with_writer(tracing_web::MakeWebConsoleWriter::new()),
tracing_subscriber::filter::LevelFilter::DEBUG,
);
tracing_subscriber::registry()
.with(fmt_layer)
.with(crate::channel_logger::channel_logger())
}
use std::sync::Once;
static START: Once = Once::new();
START.call_once(|| {
use std::str::FromStr as _;
if cfg!(target_os = "macos") && cfg!(target_arch = "x86_64") {
crate::warn!("Rerun does not officially support Intel Macs (x86/x64)");
}
let primary_log_filter = log_filter.split(',').next().unwrap_or("info");
let max_level =
log::LevelFilter::from_str(primary_log_filter).unwrap_or(log::LevelFilter::Info);
log::set_max_level(max_level);
if let Err(err) = tracing_log::LogTracer::init() {
eprintln!("Failed to set log to tracing forwarding: {err}");
}
let subscriber = create_tracing_subscriber(log_filter);
if tracing::subscriber::set_global_default(subscriber).is_err() {
eprintln!(
"Failed to set global tracing subscriber. This can cause problems with log messages not being captured."
);
crate::debug_panic!(
"Failed to set global tracing subscriber. This can cause problems with log messages not being captured."
);
}
});
}
thread_local! {
static PANIC_ON_WARN_SCOPE_DEPTH: AtomicIsize = const { AtomicIsize::new(0) };
}
#[cfg(not(target_arch = "wasm32"))]
pub struct PanicOnWarnScope {
not_send_sync: std::marker::PhantomData<std::cell::Cell<()>>,
}
#[cfg(not(target_arch = "wasm32"))]
impl PanicOnWarnScope {
#[expect(clippy::new_without_default)]
pub fn new() -> Self {
PANIC_ON_WARN_SCOPE_DEPTH.with(|enabled| {
enabled.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
});
Self {
not_send_sync: Default::default(),
}
}
}
#[cfg(not(target_arch = "wasm32"))]
impl Drop for PanicOnWarnScope {
fn drop(&mut self) {
PANIC_ON_WARN_SCOPE_DEPTH.with(|enabled| {
enabled.fetch_sub(1, std::sync::atomic::Ordering::Relaxed);
});
}
}
#[cfg(not(target_arch = "wasm32"))]
fn env_var_bool(name: &str) -> Option<bool> {
let s = std::env::var(name).ok()?;
match s.to_lowercase().as_str() {
"0" | "false" | "off" | "no" => Some(false),
"1" | "true" | "on" | "yes" => Some(true),
_ => {
crate::warn!(
"Invalid value for environment variable {name}={s:?}. Expected 'on' or 'off'. It will be ignored"
);
None
}
}
}
#[cfg(not(target_arch = "wasm32"))]
struct PanicOnWarn {
always_enabled: bool,
}
#[cfg(not(target_arch = "wasm32"))]
impl<S> tracing_subscriber::Layer<S> for PanicOnWarn
where
S: tracing::Subscriber,
{
fn on_event(
&self,
event: &tracing::Event<'_>,
_ctx: tracing_subscriber::layer::Context<'_, S>,
) {
let metadata = event.metadata();
let level = match *metadata.level() {
tracing::Level::ERROR => "error",
tracing::Level::WARN => "warning",
tracing::Level::INFO | tracing::Level::DEBUG | tracing::Level::TRACE => return,
};
let enabled = self.always_enabled
|| PANIC_ON_WARN_SCOPE_DEPTH
.with(|enabled| enabled.load(std::sync::atomic::Ordering::Relaxed) > 0);
if enabled {
let mut visitor = crate::event_visitor::EventVisitor::default();
event.record(&mut visitor);
panic!(
"{level} logged with RERUN_PANIC_ON_WARN: {}",
visitor.format_as_string()
);
}
}
}