1use anyhow::Result;
4
5use crate::jobstore::{JobDir, resolve_root};
6use crate::schema::{Response, TailData};
7
8#[derive(Debug)]
10pub struct TailOpts<'a> {
11 pub job_id: &'a str,
12 pub root: Option<&'a str>,
13 pub tail_lines: u64,
15 pub max_bytes: u64,
17 pub compression_mode: crate::compress::CompressionMode,
18}
19
20impl<'a> Default for TailOpts<'a> {
21 fn default() -> Self {
22 TailOpts {
23 job_id: "",
24 root: None,
25 tail_lines: 50,
26 max_bytes: 65536,
27 compression_mode: crate::compress::CompressionMode::default(),
28 }
29 }
30}
31
32pub fn execute(opts: TailOpts) -> Result<()> {
34 let root = resolve_root(opts.root);
35 let job_dir = JobDir::open(&root, opts.job_id)?;
36
37 let stdout_log_path = job_dir.stdout_path();
38 let stderr_log_path = job_dir.stderr_path();
39
40 let stdout = job_dir.read_tail_metrics("stdout.log", opts.tail_lines, opts.max_bytes);
42 let stderr = job_dir.read_tail_metrics("stderr.log", opts.tail_lines, opts.max_bytes);
43 let meta = job_dir.read_meta()?;
44 let compression = crate::compress::compress(crate::compress::CompressionInput {
45 command: &meta.command,
46 stdout: &stdout.tail,
47 stderr: &stderr.tail,
48 stdout_original_bytes: stdout.observed_bytes,
49 stderr_original_bytes: stderr.observed_bytes,
50 mode: opts.compression_mode,
51 });
52
53 let response = Response::new(
54 "tail",
55 TailData {
56 job_id: job_dir.job_id.clone(),
57 stdout: stdout.tail,
58 stderr: stderr.tail,
59 encoding: "utf-8-lossy".to_string(),
60 stdout_log_path: stdout_log_path.display().to_string(),
61 stderr_log_path: stderr_log_path.display().to_string(),
62 stdout_range: stdout.range,
63 stderr_range: stderr.range,
64 stdout_total_bytes: stdout.observed_bytes,
65 stderr_total_bytes: stderr.observed_bytes,
66 compression,
67 },
68 );
69 response.print();
70 Ok(())
71}