From e585e0b049ab48d82e9edade9e7185ada850ace2 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Thu, 25 Jun 2026 14:01:38 -0600 Subject: [PATCH] feat: --tail-logs can track log rollovers and incoporates a sleep timer to minimize idle CPU cycles --- src/utils/logs.rs | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/utils/logs.rs b/src/utils/logs.rs index 58c8089..b7da422 100644 --- a/src/utils/logs.rs +++ b/src/utils/logs.rs @@ -1,9 +1,11 @@ use crate::config::paths; use colored::Colorize; use fancy_regex::Regex; -use std::fs::File; +use std::fs::{self, File}; use std::io::{BufRead, BufReader, Seek, SeekFrom}; use std::process; +use std::time::Duration; +use tokio::time::sleep; pub async fn tail_logs(no_color: bool) { let re = Regex::new(r"^(?P\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+<(?P[^\s>]+)>\s+\[(?P[A-Z]+)\]\s+(?P[^:]+):(?P\d+)\s+-\s+(?P.*)$").unwrap(); @@ -16,20 +18,43 @@ pub async fn tail_logs(no_color: bool) { process::exit(1); }; - let mut lines = reader.lines(); + let mut line_buf = String::new(); loop { - if let Some(Ok(line)) = lines.next() { - if no_color { - println!("{line}"); - } else { - let colored_line = colorize_log_line(&line, &re); - println!("{colored_line}"); + match reader.read_line(&mut line_buf) { + Ok(0) => { + if file_was_rotated(&file_path, &mut reader) { + let file = File::open(&file_path).expect("Cannot open file"); + reader = BufReader::new(file); + } + sleep(Duration::from_millis(100)).await; + } + Ok(_) => { + let line = line_buf.trim_end(); + if no_color { + println!("{line}"); + } else { + let colored_line = colorize_log_line(line, &re); + println!("{colored_line}"); + } + line_buf.clear(); + } + Err(_) => { + line_buf.clear(); + sleep(Duration::from_millis(100)).await; } } } } +fn file_was_rotated(path: &std::path::Path, reader: &mut BufReader) -> bool { + let current_pos = reader.stream_position().unwrap_or(0); + match fs::metadata(path) { + Ok(metadata) => metadata.len() < current_pos, + Err(_) => true, + } +} + fn colorize_log_line(line: &str, re: &Regex) -> String { if let Some(caps) = re.captures(line).expect("Failed to capture log line") { let level = &caps["level"];