//! logs: tail the log file of an agent (--follow for a live view). use super::*; use crate::output::print_json; use anyhow::{bail, Result}; use std::path::PathBuf; /// Resolve the log path of an agent (validates the agent first). pub fn log_path(app: &App, agent_name: &str) -> Result { let agent = require_agent(app, agent_name)?; Ok(crate::process::agent_log_path(app, &agent.name)) } pub fn run(app: &App, agent: &str, lines: usize, follow: bool) -> Result { let path = log_path(app, agent)?; if !path.exists() { bail!( "no log yet for '{}' — start it with 'am start {} --background'", agent, agent ); } if app.json() { let tail = crate::process::last_lines(&path, lines); print_json(&serde_json::json!({ "agent": agent, "log": path.display().to_string(), "tail": tail, })); return Ok(0); } if !follow { print!("{}", crate::process::last_lines(&path, lines)); return Ok(0); } // Live follow: print the initial tail, then new bytes as they arrive. let mut seen: usize = std::fs::metadata(&path).map(|m| m.len() as usize).unwrap_or(0); loop { if let Ok(text) = std::fs::read_to_string(&path) { let bytes = text.as_bytes(); if bytes.len() > seen { // Slicer sans risque de couper un caractere UTF-8. let tail: String = text .char_indices() .filter(|(i, _)| *i >= seen) .map(|(_, c)| c) .collect(); print!("{tail}"); use std::io::Write; let _ = std::io::stdout().flush(); } seen = bytes.len(); } std::thread::sleep(std::time::Duration::from_secs(1)); } }