systemprompt_cli/commands/admin/agents/
logs.rs1use std::path::PathBuf;
2
3use anyhow::{Context, Result};
4use clap::Args;
5
6use super::logs_db::execute_db_mode;
7use super::logs_disk::{execute_disk_mode, execute_follow_mode};
8use crate::CliConfig;
9use crate::interactive::Prompter;
10use crate::shared::CommandOutput;
11
12#[derive(Debug, Args)]
13pub struct LogsArgs {
14 #[arg(help = "Agent name (optional - shows all agent logs if not specified)")]
15 pub agent: Option<String>,
16
17 #[arg(
18 long,
19 short = 'n',
20 default_value = "50",
21 help = "Number of lines to show"
22 )]
23 pub lines: usize,
24
25 #[arg(long, short, help = "Follow log output continuously (disk only)")]
26 pub follow: bool,
27
28 #[arg(long, help = "Force reading from disk files instead of database")]
29 pub disk: bool,
30
31 #[arg(long, help = "Custom logs directory path")]
32 pub logs_dir: Option<String>,
33}
34
35pub(super) async fn execute(
36 args: LogsArgs,
37 prompter: &dyn Prompter,
38 config: &CliConfig,
39) -> Result<CommandOutput> {
40 let logs_path = match args.logs_dir.as_deref() {
41 Some(dir) => PathBuf::from(dir),
42 None => PathBuf::from(
43 systemprompt_models::Config::get()
44 .context("agent log directory requires an initialised profile")?
45 .logs_path(),
46 ),
47 };
48
49 if args.follow {
50 return execute_follow_mode(&args, prompter, config, &logs_path);
51 }
52
53 if args.disk {
54 return execute_disk_mode(&args, prompter, config, &logs_path);
55 }
56
57 match execute_db_mode(&args, config).await {
58 Ok(result) => Ok(result),
59 Err(e) => {
60 tracing::debug!(error = %e, "DB log query failed, falling back to disk");
61 execute_disk_mode(&args, prompter, config, &logs_path)
62 },
63 }
64}