Skip to main content

systemprompt_logging/repository/
mod.rs

1#![allow(clippy::print_stdout)]
2
3use chrono::{DateTime, Utc};
4use systemprompt_database::DbPool;
5use systemprompt_identifiers::LogId;
6
7use crate::models::{LogEntry, LogFilter, LogLevel, LoggingError};
8
9pub mod analytics;
10mod operations;
11
12pub use analytics::{AnalyticsEvent, AnalyticsRepository};
13
14#[derive(Clone, Debug)]
15pub struct LoggingRepository {
16    db_pool: DbPool,
17    terminal_output: bool,
18    db_output: bool,
19}
20
21impl LoggingRepository {
22    #[must_use]
23    pub const fn new(db_pool: DbPool) -> Self {
24        Self {
25            db_pool,
26            terminal_output: true,
27            db_output: false,
28        }
29    }
30
31    #[must_use]
32    pub const fn with_terminal(mut self, enabled: bool) -> Self {
33        self.terminal_output = enabled;
34        self
35    }
36
37    #[must_use]
38    pub const fn with_database(mut self, enabled: bool) -> Self {
39        self.db_output = enabled;
40        self
41    }
42
43    pub async fn log(&self, entry: LogEntry) -> Result<(), LoggingError> {
44        entry.validate()?;
45
46        if self.terminal_output {
47            println!("{entry}");
48        }
49
50        if self.db_output {
51            operations::create_log(&self.db_pool, &entry).await?;
52        }
53
54        Ok(())
55    }
56
57    pub async fn log_message(
58        &self,
59        level: LogLevel,
60        module: &str,
61        message: &str,
62    ) -> Result<(), LoggingError> {
63        let entry = LogEntry::new(level, module, message);
64        self.log(entry).await
65    }
66
67    pub async fn log_message_with_metadata(
68        &self,
69        level: LogLevel,
70        module: &str,
71        message: &str,
72        metadata: serde_json::Value,
73    ) -> Result<(), LoggingError> {
74        let entry = LogEntry::new(level, module, message).with_metadata(metadata);
75        self.log(entry).await
76    }
77
78    pub async fn error(&self, module: &str, message: &str) -> Result<(), LoggingError> {
79        self.log_message(LogLevel::Error, module, message).await
80    }
81
82    pub async fn warn(&self, module: &str, message: &str) -> Result<(), LoggingError> {
83        self.log_message(LogLevel::Warn, module, message).await
84    }
85
86    pub async fn info(&self, module: &str, message: &str) -> Result<(), LoggingError> {
87        self.log_message(LogLevel::Info, module, message).await
88    }
89
90    pub async fn debug(&self, module: &str, message: &str) -> Result<(), LoggingError> {
91        self.log_message(LogLevel::Debug, module, message).await
92    }
93
94    pub async fn trace(&self, module: &str, message: &str) -> Result<(), LoggingError> {
95        self.log_message(LogLevel::Trace, module, message).await
96    }
97
98    pub async fn get_recent_logs(&self, limit: i64) -> Result<Vec<LogEntry>, LoggingError> {
99        operations::list_logs(&self.db_pool, limit).await
100    }
101
102    pub async fn get_logs_by_module_patterns(
103        &self,
104        patterns: &[String],
105        limit: i64,
106    ) -> Result<Vec<LogEntry>, LoggingError> {
107        operations::list_logs_by_module_patterns(&self.db_pool, patterns, limit).await
108    }
109
110    pub async fn cleanup_old_logs(&self, older_than: DateTime<Utc>) -> Result<u64, LoggingError> {
111        operations::cleanup_logs_before(&self.db_pool, older_than).await
112    }
113
114    pub async fn count_logs_before(&self, cutoff: DateTime<Utc>) -> Result<u64, LoggingError> {
115        operations::count_logs_before(&self.db_pool, cutoff).await
116    }
117
118    pub async fn clear_all_logs(&self) -> Result<u64, LoggingError> {
119        operations::clear_all_logs(&self.db_pool).await
120    }
121
122    pub async fn get_logs_paginated(
123        &self,
124        filter: &LogFilter,
125    ) -> Result<(Vec<LogEntry>, i64), LoggingError> {
126        operations::list_logs_paginated(&self.db_pool, filter).await
127    }
128
129    pub async fn get_by_id(&self, id: &LogId) -> Result<Option<LogEntry>, LoggingError> {
130        operations::get_log(&self.db_pool, id).await
131    }
132
133    pub async fn update_log_entry(
134        &self,
135        id: &LogId,
136        entry: &LogEntry,
137    ) -> Result<bool, LoggingError> {
138        operations::update_log(&self.db_pool, id, entry).await
139    }
140
141    pub async fn delete_log_entry(&self, id: &LogId) -> Result<bool, LoggingError> {
142        operations::delete_log(&self.db_pool, id).await
143    }
144
145    pub async fn delete_log_entries(&self, ids: &[LogId]) -> Result<u64, LoggingError> {
146        operations::delete_logs_multiple(&self.db_pool, ids).await
147    }
148}