systemprompt_cli/commands/plugins/mcp/
logs_db.rs1use std::sync::Arc;
7
8use anyhow::{Context, Result, anyhow};
9use systemprompt_database::DbPool;
10use systemprompt_loader::ConfigLoader;
11use systemprompt_logging::LoggingRepository;
12use systemprompt_runtime::AppContext;
13
14use super::logs::{LogLevel, LogsArgs};
15use super::types::McpLogsOutput;
16use crate::CliConfig;
17use crate::shared::CommandOutput;
18
19pub(super) async fn execute_db_mode(args: &LogsArgs, config: &CliConfig) -> Result<CommandOutput> {
20 let ctx = Arc::new(
21 AppContext::new()
22 .await
23 .context("Failed to initialize app context")?,
24 );
25 execute_db_mode_with_pool(args, ctx.db_pool(), config).await
26}
27
28pub async fn execute_db_mode_with_pool(
29 args: &LogsArgs,
30 pool: &DbPool,
31 _config: &CliConfig,
32) -> Result<CommandOutput> {
33 let repo = LoggingRepository::new(pool)?;
34
35 let patterns = match &args.server {
36 Some(service) => build_service_patterns(service),
37 None => build_all_mcp_patterns()?,
38 };
39
40 let fetch_limit = if args.level.is_some() {
41 (args.lines * 5) as i64
42 } else {
43 args.lines as i64
44 };
45
46 let entries = repo
47 .get_logs_by_module_patterns(&patterns, fetch_limit)
48 .await
49 .context("Failed to query logs from database")?;
50
51 if entries.is_empty() {
52 return Err(anyhow!("No logs found in database for MCP services"));
53 }
54
55 let logs: Vec<String> = entries
56 .iter()
57 .filter(|e| {
58 args.level
59 .is_none_or(|level: LogLevel| level.matches(&e.level.to_string()))
60 })
61 .take(args.lines)
62 .map(|e| {
63 format!(
64 "{} {} [{}] {}",
65 e.timestamp.format("%Y-%m-%d %H:%M:%S"),
66 e.level,
67 e.module,
68 e.message
69 )
70 })
71 .collect();
72
73 let service_label = args.server.clone().unwrap_or_else(|| "all".to_owned());
74 let level_label = args.level.map_or_else(String::new, |l| {
75 format!(" [{}+]", format!("{:?}", l).to_uppercase())
76 });
77
78 let output = McpLogsOutput {
79 service: Some(service_label.clone()),
80 source: "database".to_owned(),
81 logs,
82 log_files: vec![],
83 };
84
85 Ok(CommandOutput::card_value(
86 format!("MCP Logs (DB): {}{}", service_label, level_label),
87 &output,
88 ))
89}
90
91fn build_service_patterns(service: &str) -> Vec<String> {
92 vec![format!("%{}%", service), "%rmcp%".to_owned()]
93}
94
95fn build_all_mcp_patterns() -> Result<Vec<String>> {
96 let services_config = ConfigLoader::load().context("Failed to load services config")?;
97
98 let mut patterns: Vec<String> = services_config
99 .mcp_servers
100 .keys()
101 .flat_map(|name| vec![format!("%{}%", name)])
102 .collect();
103
104 patterns.push("%rmcp%".to_owned());
105 patterns.push("%mcp%".to_owned());
106
107 Ok(patterns)
108}