use std::panic;
use std::sync::OnceLock;
use ctor::ctor;
use tracing_subscriber::{EnvFilter, fmt::format::FmtSpan};
#[cfg(not(test))]
static LOGGING: OnceLock<tracing_appender::non_blocking::WorkerGuard> = OnceLock::new();
#[cfg(test)]
static LOGGING: OnceLock<()> = OnceLock::new();
pub fn install_panic_hook() {
let default_hook = panic::take_hook();
panic::set_hook(Box::new(move |info| {
let payload = if let Some(s) = info.payload().downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = info.payload().downcast_ref::<String>() {
s.clone()
} else {
"unknown panic payload".to_string()
};
let location = info
.location()
.map(|l| format!("{}:{}:{}", l.file(), l.line(), l.column()))
.unwrap_or_else(|| "unknown location".to_string());
tracing::error!(
panic.payload = %payload,
panic.location = %location,
"A panic occurred"
);
default_hook(info);
}));
}
#[ctor(unsafe)]
fn _install_global_tracing() {
LOGGING.get_or_init(|| {
let fmt = tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")),
)
.with_target(true)
.with_line_number(true)
.with_ansi(false)
.with_span_events(FmtSpan::CLOSE);
#[cfg(test)]
{
fmt.with_test_writer().init();
}
#[cfg(not(test))]
{
let log_dir = std::env::var("HYPER_MCP_REMOTE_LOG_PATH")
.map(std::path::PathBuf::from)
.unwrap_or_else(|_| {
dirs::config_dir()
.map(|mut path| {
path.push("hyper-mcp-remote");
path.push("logs");
path
})
.expect("Unable to determine log directory")
});
std::fs::create_dir_all(&log_dir).expect("Failed to create log directory");
let file_appender = tracing_appender::rolling::daily(&log_dir, "mcp-server.log");
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
fmt.with_writer(non_blocking).init();
guard
}
});
install_panic_hook();
}