diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.rs | 64 |
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 | ||
| 477 | fn tail_logs(id: &str, show_stdout: bool, show_stderr: bool) -> Result<()> { | 485 | fn 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 | ||
| 652 | fn 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 | |||
| 611 | fn handle_file_change( | 669 | fn 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>, |
