use std::{
env,
fs::{self, File},
io,
path::{Path, PathBuf},
};
use anyhow::Error;
use tracing::{event, Level};
use tracing_appender::rolling::{RollingFileAppender, Rotation};
use tracing_subscriber::{
filter, fmt::time::ChronoLocal, layer::SubscriberExt, util::SubscriberInitExt, Layer,
};
pub fn setup_logging_to_stderr_and_file(
file_path: impl AsRef<Path>,
// stderr_log_level: filter::LevelFilter,
) -> Result<(), Error> {
let stderr_log_level = filter::LevelFilter::INFO;
let stderr_layer = tracing_subscriber::fmt::layer()
.pretty()
.with_writer(io::stderr);
let file_layer = tracing_subscriber::fmt::layer().pretty().with_writer(
fs::OpenOptions::new()
.append(true)
.open(file_path.as_ref())?,
);
tracing_subscriber::registry()
.with(
stderr_layer
.with_timer(ChronoLocal::rfc_3339())
.with_filter(stderr_log_level),
)
.with(
file_layer
.with_timer(ChronoLocal::rfc_3339())
.with_ansi(false)
.with_filter(filter::LevelFilter::DEBUG),
)
.try_init()?;
Ok(())
}
fn get_tmp_dir() -> String {
match env::var("TMPDIR").or_else(|_| env::var("TEMP")) {
Ok(v) => v,
Err(_) => "log".into(),
}
}
pub fn setup_logging_to_stderr_and_rolling_file(
filename_prefix: &str,
// stderr_log_level: filter::LevelFilter,
) -> Result<(), Error> {
let stderr_log_level = filter::LevelFilter::INFO;
let stderr_layer = tracing_subscriber::fmt::layer()
.pretty()
.with_writer(io::stderr);
let tmp_dir = get_tmp_dir();
let file_layer = tracing_subscriber::fmt::layer().pretty().with_writer(
RollingFileAppender::builder()
.rotation(Rotation::DAILY)
.filename_prefix(filename_prefix)
.filename_suffix("log")
.build(&tmp_dir)?,
);
tracing_subscriber::registry()
.with(
stderr_layer
.with_timer(ChronoLocal::rfc_3339())
.with_filter(stderr_log_level),
)
.with(
file_layer
.with_timer(ChronoLocal::rfc_3339())
.with_ansi(false)
.with_filter(filter::LevelFilter::DEBUG),
)
.try_init()?;
let log_dir_abs_path = match Path::new(&tmp_dir).canonicalize() {
Ok(v) => v,
Err(_) => PathBuf::from(tmp_dir),
};
event!(Level::INFO, "log dir = {}", log_dir_abs_path.display());
Ok(())
}
#[cfg(test)]
mod test {
use tracing::{event, Level};
use super::*;
#[test]
fn test_rolling() {
// setup_logging_to_stderr_and_file("test.log").unwrap();
setup_logging_to_stderr_and_rolling_file("crackle-kit").unwrap();
event!(Level::DEBUG, "debug!");
event!(Level::INFO, "info!");
event!(Level::TRACE, "trace!");
event!(Level::ERROR, "error!");
}
#[test]
fn test_append() {
setup_logging_to_stderr_and_file("test.log").unwrap();
// setup_logging_to_stderr_and_rolling_file("crackle-kit").unwrap();
event!(Level::DEBUG, "debug!");
event!(Level::INFO, "info!");
event!(Level::TRACE, "trace!");
event!(Level::ERROR, "error!");
}
}
I actually spent some time finding a proper way to do this, so hopefully, this helps someone who’s looking for the same thing.
* You should use the feature:"chrono" for tracing-subscriber crate.