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}
18
19impl<'a> Default for TailOpts<'a> {
20 fn default() -> Self {
21 TailOpts {
22 job_id: "",
23 root: None,
24 tail_lines: 50,
25 max_bytes: 65536,
26 }
27 }
28}
29
30pub fn execute(opts: TailOpts) -> Result<()> {
32 let root = resolve_root(opts.root);
33 let job_dir = JobDir::open(&root, opts.job_id)?;
34
35 let stdout_log_path = job_dir.stdout_path();
36 let stderr_log_path = job_dir.stderr_path();
37
38 let stdout = job_dir.read_tail_metrics("stdout.log", opts.tail_lines, opts.max_bytes);
40 let stderr = job_dir.read_tail_metrics("stderr.log", opts.tail_lines, opts.max_bytes);
41
42 let response = Response::new(
43 "tail",
44 TailData {
45 job_id: job_dir.job_id.clone(),
46 stdout: stdout.tail,
47 stderr: stderr.tail,
48 encoding: "utf-8-lossy".to_string(),
49 stdout_log_path: stdout_log_path.display().to_string(),
50 stderr_log_path: stderr_log_path.display().to_string(),
51 stdout_range: stdout.range,
52 stderr_range: stderr.range,
53 stdout_total_bytes: stdout.observed_bytes,
54 stderr_total_bytes: stderr.observed_bytes,
55 },
56 );
57 response.print();
58 Ok(())
59}