Skip to content

Commit

Permalink
Tracing writers are now non-blocking and file pruning is now working (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
XdoctorwhoZ authored Jan 5, 2025
1 parent bd4f611 commit 72e06e1
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 18 deletions.
24 changes: 17 additions & 7 deletions src/tracing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,37 @@ pub use logger::Logger;

use csv_formatter::CSVFormatter;
use multi_writer::MultiWriter;
use tracing_appender::non_blocking::WorkerGuard;

/// Keep the non_blocking writer guard alive as long as the application is alive
/// Else writer stop working
///
static mut GUARD: Option<WorkerGuard> = None;

/// Function to initiliaze tracing for the application
///
pub fn init(enable_stdout: bool, enable_broker_log: bool, debug: bool, trace: bool) {
//
//
let level = tracing::Level::TRACE;
let multiw = MultiWriter::new(enable_stdout, enable_broker_log, debug, trace);

let (non_blocking, guard) = tracing_appender::non_blocking(multiw);

unsafe {
GUARD = Some(guard);
}

let subscriber = tracing_subscriber::fmt()
// .with_max_level(tracing::Level::TRACE)
.with_max_level(level)
.with_max_level(tracing::Level::TRACE)
// Display source code file paths
.with_file(true)
.with_file(false)
// Display source code line numbers
.with_line_number(true)
.with_line_number(false)
// Display the thread ID an event was recorded on
.with_thread_ids(true)
// Build the subscriber
.event_format(CSVFormatter {})
// Custom writer
.with_writer(move || MultiWriter::new(enable_stdout, enable_broker_log, debug, trace))
.with_writer(non_blocking)
// Ok
.finish();
// use that subscriber to process traces emitted after this point
Expand Down
102 changes: 91 additions & 11 deletions src/tracing/multi_writer.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
mod line_printer;

use std::fs;

use crate::env::system_default_log_dir;

use line_printer::print_log_line;
use tracing_appender::rolling::RollingFileAppender;
use tracing_appender::rolling::Rotation;
use tracing_subscriber::fmt::MakeWriter;

/// Maximum number of log file that must be kept in disk
/// If more than this number, platform will erase them
///
static MAX_LOG_FILES: usize = 3;

///
///
Expand All @@ -17,21 +25,93 @@ pub struct MultiWriter {
filea: tracing_appender::rolling::RollingFileAppender,
}

// tracing_appender::rolling::never(".", "platform-log.csv")
impl MultiWriter {
pub fn new(enable_stdout: bool, enable_broker_log: bool, debug: bool, trace: bool) -> Self {
MultiWriter {
//
// Because the appender wait 1 day before pruning
// without this, developpers will reboot the platform often and won't prune
Self::prune_old_logs(MAX_LOG_FILES);

let p = RollingFileAppender::builder()
.rotation(Rotation::HOURLY) // rotate log files once every day
.filename_prefix("platform") // log file names will be prefixed
.filename_suffix("csv") // log file names will be suffixed with `.log`
.max_log_files(MAX_LOG_FILES)
.build(system_default_log_dir().unwrap())
.unwrap();

Self {
enable_stdout: enable_stdout,
enable_broker_log: enable_broker_log,
debug: debug,
trace: trace,
filea: RollingFileAppender::builder()
.rotation(Rotation::DAILY) // rotate log files once every day
.filename_prefix("platform") // log file names will be prefixed
.filename_suffix("csv") // log file names will be suffixed with `.log`
.max_log_files(3) // last 3 day stored
.build(system_default_log_dir().unwrap())
.unwrap(),
filea: p,
}
}

fn prune_old_logs(max_files: usize) {
let files = fs::read_dir(system_default_log_dir().unwrap()).map(|dir| {
dir.filter_map(|entry| {
let entry = entry.ok()?;
let metadata = entry.metadata().ok()?;

// the appender only creates files, not directories or symlinks,
// so we should never delete a dir or symlink.
if !metadata.is_file() {
return None;
}

let filename = entry.file_name();
// if the filename is not a UTF-8 string, skip it.
let filename = filename.to_str()?;
// if let Some(prefix) = &self.log_filename_prefix {
if !filename.starts_with("platform") {
return None;
}
// }

// if let Some(suffix) = &self.log_filename_suffix {
if !filename.ends_with("csv") {
return None;
}
// }

// if self.log_filename_prefix.is_none()
// && self.log_filename_suffix.is_none()
// && Date::parse(filename, &self.date_format).is_err()
// {
// return None;
// }

let created = metadata.created().ok()?;
Some((entry, created))
})
.collect::<Vec<_>>()
});

let mut files = match files {
Ok(files) => files,
Err(error) => {
eprintln!("Error reading the log directory/files: {}", error);
return;
}
};
if files.len() < max_files {
return;
}

// sort the files by their creation timestamps.
files.sort_by_key(|(_, created_at)| *created_at);

// delete files, so that (n-1) files remain, because we will create another log file
for (file, _) in files.iter().take(files.len() - (max_files - 1)) {
if let Err(error) = fs::remove_file(file.path()) {
eprintln!(
"Failed to remove old log file {}: {}",
file.path().display(),
error
);
}
}
}
}
Expand All @@ -40,7 +120,7 @@ impl std::io::Write for MultiWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
//
// Store in log file
self.filea.write_all(buf).unwrap();
self.filea.make_writer().write_all(buf).unwrap();

//
// Stdout logs ?
Expand All @@ -52,7 +132,7 @@ impl std::io::Write for MultiWriter {
}

fn flush(&mut self) -> std::io::Result<()> {
self.filea.flush().unwrap();
self.filea.make_writer().flush().unwrap();
Ok(())
}
}

0 comments on commit 72e06e1

Please sign in to comment.