aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs64
1 files changed, 61 insertions, 3 deletions
diff --git a/src/main.rs b/src/main.rs
index 5547d9a..89a32b4 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -178,6 +178,14 @@ struct TailArgs {
178 /// Only tail stderr 178 /// Only tail stderr
179 #[arg(long)] 179 #[arg(long)]
180 stderr: bool, 180 stderr: bool,
181
182 /// Follow mode - continuously watch for new content (like tail -f)
183 #[arg(short = 'f', long)]
184 follow: bool,
185
186 /// Number of lines to display from the end (default: 50)
187 #[arg(short = 'n', long, default_value = "50")]
188 lines: usize,
181} 189}
182 190
183#[derive(Args)] 191#[derive(Args)]
@@ -246,7 +254,7 @@ fn run_command(command: Commands) -> Result<()> {
246 Commands::Tail(args) => { 254 Commands::Tail(args) => {
247 let show_stdout = !args.stderr || args.stdout; 255 let show_stdout = !args.stderr || args.stdout;
248 let show_stderr = !args.stdout || args.stderr; 256 let show_stderr = !args.stdout || args.stderr;
249 tail_logs(&args.id, show_stdout, show_stderr) 257 tail_logs(&args.id, show_stdout, show_stderr, args.follow, args.lines)
250 } 258 }
251 Commands::Cat(args) => { 259 Commands::Cat(args) => {
252 let show_stdout = !args.stderr || args.stdout; 260 let show_stdout = !args.stderr || args.stdout;
@@ -474,11 +482,44 @@ fn cat_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<()> {
474 Ok(()) 482 Ok(())
475} 483}
476 484
477fn tail_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<()> { 485fn tail_logs(id: &str, show_stdout: bool, show_stderr: bool, follow: bool, lines: usize) -> Result<()> {
478 let stdout_file = format!("{}.stdout", id); 486 let stdout_file = format!("{}.stdout", id);
479 let stderr_file = format!("{}.stderr", id); 487 let stderr_file = format!("{}.stderr", id);
480 488
481 // First, display existing content and set up initial positions 489 if !follow {
490 // Non-follow mode: just show the last n lines and exit
491 let mut files_found = false;
492
493 if show_stdout && Path::new(&stdout_file).exists() {
494 let content = read_last_n_lines(&stdout_file, lines)?;
495 if !content.is_empty() {
496 files_found = true;
497 if show_stderr {
498 println!("==> {} <==", stdout_file);
499 }
500 print!("{}", content);
501 }
502 }
503
504 if show_stderr && Path::new(&stderr_file).exists() {
505 let content = read_last_n_lines(&stderr_file, lines)?;
506 if !content.is_empty() {
507 files_found = true;
508 if show_stdout {
509 println!("==> {} <==", stderr_file);
510 }
511 print!("{}", content);
512 }
513 }
514
515 if !files_found {
516 println!("No log files found for daemon '{}'", id);
517 }
518
519 return Ok(());
520 }
521
522 // Follow mode: original real-time monitoring behavior
482 let mut file_positions: std::collections::HashMap<String, u64> = 523 let mut file_positions: std::collections::HashMap<String, u64> =
483 std::collections::HashMap::new(); 524 std::collections::HashMap::new();
484 525
@@ -608,6 +649,23 @@ fn read_file_content(file: &mut File) -> Result<String> {
608 Ok(content) 649 Ok(content)
609} 650}
610 651
652fn read_last_n_lines(file_path: &str, n: usize) -> Result<String> {
653 let content = std::fs::read_to_string(file_path)?;
654 if content.is_empty() {
655 return Ok(String::new());
656 }
657
658 let lines: Vec<&str> = content.lines().collect();
659 let start_index = if lines.len() > n {
660 lines.len() - n
661 } else {
662 0
663 };
664
665 let last_lines: Vec<&str> = lines[start_index..].to_vec();
666 Ok(last_lines.join("\n") + if content.ends_with('\n') { "\n" } else { "" })
667}
668
611fn handle_file_change( 669fn handle_file_change(
612 file_path: &str, 670 file_path: &str,
613 positions: &mut std::collections::HashMap<String, u64>, 671 positions: &mut std::collections::HashMap<String, u64>,