xianyun_cli/commands/
logs.rs1use anyhow::Context as _;
6use clap::Args;
7use xianyun_core::config::global::Context;
8use xianyun_core::config::latest::CaproniConfig;
9
10#[derive(Args, Debug)]
11pub struct LogsArgs {
12 #[arg(short = 'n', long = "tail", default_value_t = 25)]
14 pub tail: i64,
15
16 #[arg(long = "no-log-prefix")]
18 pub no_log_prefix: bool,
19
20 pub proc_names: Vec<String>,
22}
23
24pub fn run(args: &LogsArgs, ctx: &Context) -> anyhow::Result<()> {
25 run_logs(ctx, args.proc_names.clone(), args.tail, args.no_log_prefix)
26}
27
28pub fn run_logs(
33 ctx: &Context,
34 proc_names: Vec<String>,
35 max_lines: i64,
36 no_log_prefix: bool,
37) -> anyhow::Result<()> {
38 let container =
39 xianyun_core::config::caproni::load_from_context(ctx).context("loading configuration")?;
40
41 let logs_dir = std::path::Path::new(&container.global.config_file)
42 .parent()
43 .map_or_else(
44 || xianyun_executor::editmodelogger::DIR_NAME.to_string(),
45 |dir| {
46 dir.join(xianyun_executor::editmodelogger::DIR_NAME)
47 .to_string_lossy()
48 .into_owned()
49 },
50 );
51
52 let proc_names = if proc_names.is_empty() {
53 get_edit_mode_process_names(&container.caproni)
54 } else {
55 proc_names
56 };
57
58 for proc_name in proc_names {
59 let lines = xianyun_executor::editmodelogger::tail(&proc_name, &logs_dir, max_lines)
60 .context("tailing logs")?;
61
62 for line in lines {
63 let line = if no_log_prefix {
64 line.strip_prefix(&format!("[{proc_name}] "))
65 .unwrap_or(&line)
66 .to_string()
67 } else {
68 line
69 };
70
71 println!("{line}");
72 }
73 }
74
75 Ok(())
76}
77
78#[must_use]
82pub fn get_edit_mode_process_names(caproni_cfg: &CaproniConfig) -> Vec<String> {
83 let mut names = Vec::new();
84
85 if let Some(reloaders) = &caproni_cfg.reloaders {
86 for reloader in reloaders.values() {
87 if reloader.edit_mode
88 && let Some(mirror) = &reloader.mirror
89 && let Some(processes) = &mirror.edit_mode_processes
90 {
91 names.extend(processes.keys());
92 }
93 }
94 }
95
96 names
97}