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: opts.job_id.to_string(),
46 stdout_tail: stdout.tail,
47 stderr_tail: stderr.tail,
48 truncated: stdout.truncated || stderr.truncated,
49 encoding: "utf-8-lossy".to_string(),
50 stdout_log_path: stdout_log_path.display().to_string(),
51 stderr_log_path: stderr_log_path.display().to_string(),
52 stdout_observed_bytes: stdout.observed_bytes,
53 stderr_observed_bytes: stderr.observed_bytes,
54 stdout_included_bytes: stdout.included_bytes,
55 stderr_included_bytes: stderr.included_bytes,
56 },
57 );
58 response.print();
59 Ok(())
60}