use crate::logging::XbpLogger;
pub async fn view_logs(
command_filter: Option<String>,
lines: Option<usize>,
follow: bool,
list_files: bool,
debug: bool,
) -> Result<(), String> {
let logger: XbpLogger = XbpLogger::new(debug).await?;
if list_files {
return list_log_files(&logger).await;
}
if follow {
return follow_logs(&logger, command_filter, debug).await;
}
view_recent_logs(&logger, command_filter, lines.unwrap_or(50)).await
}
async fn list_log_files(logger: &XbpLogger) -> Result<(), String> {
println!("\x1b[96m📋 Available XBP Log Files\x1b[0m");
println!("Log directory: {}", logger.log_dir().display());
println!();
let files = logger.list_log_files().await?;
if files.is_empty() {
println!("\x1b[93mNo log files found.\x1b[0m");
return Ok(());
}
for file in files {
let metadata: std::fs::Metadata =
std::fs::metadata(&file).map_err(|e| format!("Failed to read file metadata: {}", e))?;
let size_kb: u64 = metadata.len() / 1024;
let modified: std::time::SystemTime = metadata
.modified()
.map_err(|e| format!("Failed to get modification time: {}", e))?;
let modified_str: chrono::format::DelayedFormat<chrono::format::StrftimeItems<'_>> =
chrono::DateTime::<chrono::Local>::from(modified).format("%Y-%m-%d %H:%M:%S");
println!(
" \x1b[94m{}\x1b[0m",
file.file_name().unwrap().to_string_lossy()
);
println!(" Size: {} KB, Modified: {}", size_kb, modified_str);
}
Ok(())
}
async fn view_recent_logs(
logger: &XbpLogger,
command_filter: Option<String>,
lines: usize,
) -> Result<(), String> {
let files = logger.list_log_files().await?;
if files.is_empty() {
println!("\x1b[93mNo log files found.\x1b[0m");
return Ok(());
}
let target_file: Option<std::path::PathBuf> = if let Some(command) = &command_filter {
files
.iter()
.find(|f| {
f.file_stem()
.unwrap()
.to_string_lossy()
.starts_with(command)
})
.or_else(|| files.last())
.cloned()
} else {
files
.iter()
.find(|f| f.file_stem().unwrap().to_string_lossy().starts_with("xbp-"))
.or_else(|| files.last())
.cloned()
};
let file: std::path::PathBuf = target_file.ok_or("No suitable log file found")?;
println!("\x1b[96m📖 Viewing logs from: {}\x1b[0m", file.display());
if let Some(cmd) = &command_filter {
println!("Filter: command = {}", cmd);
}
println!("Showing last {} lines", lines);
println!("{}", "─".repeat(80));
let log_lines: Vec<String> = logger.read_recent_logs(&file, lines).await?;
for line in log_lines {
if let Some(filter) = &command_filter {
if !line.contains(&format!("command={}", filter)) {
continue;
}
}
let colored_line = colorize_log_line(&line);
println!("{}", colored_line);
}
Ok(())
}
async fn follow_logs(
logger: &XbpLogger,
command_filter: Option<String>,
_debug: bool,
) -> Result<(), String> {
println!("\x1b[96m👁️ Following XBP logs (Press Ctrl+C to stop)\x1b[0m");
if let Some(cmd) = &command_filter {
println!("Filter: command = {}", cmd);
}
println!("{}", "─".repeat(80));
view_recent_logs(logger, command_filter, 20).await?;
println!("\x1b[93mNote: Real-time following not implemented yet. Showing recent logs.\x1b[0m");
Ok(())
}
fn colorize_log_line(line: &str) -> String {
if line.contains("level=ERROR") {
format!("\x1b[91m{}\x1b[0m", line)
} else if line.contains("level=WARN") {
format!("\x1b[93m{}\x1b[0m", line)
} else if line.contains("level=SUCCESS") {
format!("\x1b[92m{}\x1b[0m", line)
} else if line.contains("level=DEBUG") {
format!("\x1b[90m{}\x1b[0m", line)
} else {
format!("\x1b[94m{}\x1b[0m", line)
}
}
pub fn parse_logs_args(args: &[String]) -> (Option<String>, Option<usize>, bool, bool) {
let mut command_filter: Option<String> = None;
let mut lines: Option<usize> = None;
let mut follow: bool = false;
let mut list_files: bool = false;
let mut i: usize = 0;
while i < args.len() {
match args[i].as_str() {
"--command" | "-c" => {
if i + 1 < args.len() {
command_filter = Some(args[i + 1].clone());
i += 2;
} else {
i += 1;
}
}
"--lines" | "-n" => {
if i + 1 < args.len() {
if let Ok(n) = args[i + 1].parse::<usize>() {
lines = Some(n);
}
i += 2;
} else {
i += 1;
}
}
"--follow" | "-f" => {
follow = true;
i += 1;
}
"--list" | "-l" => {
list_files = true;
i += 1;
}
_ => {
i += 1;
}
}
}
(command_filter, lines, follow, list_files)
}