systemprompt_logging/
lib.rs1pub mod extension;
26pub mod layer;
27pub mod models;
28pub mod repository;
29pub mod services;
30pub mod trace;
31
32pub use extension::LoggingExtension;
33
34pub use layer::DatabaseLayer;
35pub use models::{LogEntry, LogFilter, LogLevel};
36pub use repository::{AnalyticsEvent, AnalyticsRepository, LoggingRepository};
37#[cfg(feature = "cli")]
38pub use services::CliService;
39pub use services::{
40 DatabaseLogService, FilterSystemFields, LoggingMaintenanceService, RequestSpan,
41 RequestSpanBuilder, SystemSpan, is_startup_mode, publish_log, set_log_publisher,
42 set_startup_mode,
43};
44pub use trace::{
45 AiRequestDetail, AiRequestFilter, AiRequestInfo, AiRequestListItem, AiRequestStats,
46 AiRequestSummary, AiTraceService, AuditLookupResult, AuditToolCallRow, ConversationMessage,
47 ExecutionStep, ExecutionStepSummary, LevelCount, LinkedMcpCall, LogSearchFilter, LogSearchItem,
48 LogTimeRange, McpExecutionSummary, McpToolExecution, ModelStatsRow, ModuleCount,
49 ProviderStatsRow, TaskArtifact, TaskInfo, ToolExecutionFilter, ToolExecutionItem, ToolLogEntry,
50 TraceEvent, TraceListFilter, TraceListItem, TraceQueryService,
51};
52
53use std::sync::OnceLock;
54
55use layer::ProxyDatabaseLayer;
56use systemprompt_database::DbPool;
57use tracing_subscriber::layer::SubscriberExt;
58use tracing_subscriber::util::SubscriberInitExt;
59use tracing_subscriber::{EnvFilter, Layer};
60
61static SUBSCRIBER_INITIALIZED: OnceLock<()> = OnceLock::new();
62static DB_PROXY: OnceLock<ProxyDatabaseLayer> = OnceLock::new();
63
64const NOISE_FILTERS: &[&str] = &[
65 "tokio_cron_scheduler=warn",
66 "sqlx::postgres::notice=warn",
67 "sqlx::query=warn",
68 "handlebars=warn",
69 "systemprompt_database::lifecycle=info",
70 "systemprompt_templates=info",
71 "systemprompt_extension::registry=info",
72 "systemprompt_api::services::middleware::session=info",
73];
74
75fn build_filter(base: &str) -> EnvFilter {
76 let filter_str = std::iter::once(base.to_string())
77 .chain(NOISE_FILTERS.iter().map(ToString::to_string))
78 .collect::<Vec<_>>()
79 .join(",");
80 EnvFilter::new(filter_str)
81}
82
83fn ensure_subscriber(level_override: Option<&str>) {
84 if SUBSCRIBER_INITIALIZED.set(()).is_err() {
85 return;
86 }
87
88 let console_filter = level_override.map_or_else(
89 || {
90 if is_startup_mode() {
91 EnvFilter::new("warn")
92 } else {
93 EnvFilter::try_from_default_env().unwrap_or_else(|_| build_filter("info"))
94 }
95 },
96 |level| EnvFilter::try_from_default_env().unwrap_or_else(|_| build_filter(level)),
97 );
98
99 let fmt_layer = tracing_subscriber::fmt::layer()
100 .fmt_fields(FilterSystemFields::new())
101 .with_target(true)
102 .with_writer(std::io::stderr)
103 .with_filter(console_filter);
104
105 let proxy = DB_PROXY.get_or_init(ProxyDatabaseLayer::new).clone();
106 let db_layer = proxy.with_filter(build_filter("info"));
107
108 tracing_subscriber::registry()
109 .with(fmt_layer)
110 .with(db_layer)
111 .init();
112}
113
114pub fn init_logging(db_pool: DbPool) {
115 ensure_subscriber(None);
116
117 let proxy = DB_PROXY.get_or_init(ProxyDatabaseLayer::new);
118 proxy.attach(db_pool);
119}
120
121pub fn init_console_logging() {
122 init_console_logging_with_level(None);
123}
124
125pub fn init_console_logging_with_level(level: Option<&str>) {
126 ensure_subscriber(level);
127}