use std::path::PathBuf;
use tracing_subscriber::{
filter::EnvFilter,
fmt::{self, time::LocalTime},
layer::SubscriberExt,
util::SubscriberInitExt,
Layer,
};
pub fn log_dir() -> PathBuf {
crate::platform::environment::mlstack_logs_dir()
}
pub fn init_logging(context: &str) -> Option<tracing_appender::non_blocking::WorkerGuard> {
let log_path = log_dir();
if let Err(e) = std::fs::create_dir_all(&log_path) {
eprintln!(
"[WARN] Could not create log directory {}: {}",
log_path.display(),
e
);
let filter = EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("rusty_stack=info,warn"));
let stdout_layer = fmt::layer().with_target(false).with_filter(filter);
tracing_subscriber::registry().with(stdout_layer).init();
return None;
}
let file_appender =
tracing_appender::rolling::daily(&log_path, format!("{}-rusty-stack", context));
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let file_layer = fmt::layer()
.json()
.with_timer(LocalTime::rfc_3339())
.with_writer(non_blocking)
.with_target(true)
.with_span_events(fmt::format::FmtSpan::CLOSE)
.with_filter(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("rusty_stack=debug,info")),
);
let stdout_layer = fmt::layer()
.with_target(false)
.with_timer(fmt::time::LocalTime::new(
time::format_description::well_known::iso8601::Iso8601::DEFAULT,
))
.with_filter(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("rusty_stack=info,warn")),
);
tracing_subscriber::registry()
.with(file_layer)
.with(stdout_layer)
.init();
tracing::info!(
context = context,
log_dir = %log_path.display(),
"Logging initialized"
);
Some(guard)
}
pub fn init_batch_logging(context: &str) -> Option<tracing_appender::non_blocking::WorkerGuard> {
let log_path = log_dir();
if let Err(e) = std::fs::create_dir_all(&log_path) {
eprintln!(
"[WARN] Could not create log directory {}: {}",
log_path.display(),
e
);
return None;
}
let file_appender =
tracing_appender::rolling::daily(&log_path, format!("{}-rusty-stack", context));
let (non_blocking, guard) = tracing_appender::non_blocking(file_appender);
let file_layer = fmt::layer()
.json()
.with_timer(LocalTime::rfc_3339())
.with_writer(non_blocking)
.with_target(true)
.with_span_events(fmt::format::FmtSpan::CLOSE)
.with_filter(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("rusty_stack=debug")),
);
let stderr_layer = fmt::layer()
.with_target(false)
.with_writer(std::io::stderr)
.with_filter(
EnvFilter::try_from_default_env()
.unwrap_or_else(|_| EnvFilter::new("rusty_stack=warn")),
);
tracing_subscriber::registry()
.with(file_layer)
.with(stderr_layer)
.init();
tracing::info!(
context = context,
log_dir = %log_path.display(),
"Batch logging initialized"
);
Some(guard)
}
pub fn log_file_path(context: &str) -> PathBuf {
log_dir().join(format!("{}-rusty-stack", context))
}
mod time {
pub use time::format_description;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_log_dir_is_under_mlstack() {
let dir = log_dir();
assert!(dir.to_string_lossy().contains(".mlstack"));
assert!(dir.to_string_lossy().contains("logs"));
}
#[test]
fn test_log_file_path_contains_context() {
let path = log_file_path("update");
assert!(path.to_string_lossy().contains("update-rusty-stack"));
}
}