Skip to main content

systemprompt_logging/
lib.rs

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