systemprompt_logging/repository/
mod.rs1use std::io::Write;
12use std::sync::Arc;
13
14use chrono::{DateTime, Utc};
15use sqlx::PgPool;
16use systemprompt_database::DbPool;
17use systemprompt_identifiers::LogId;
18
19use crate::models::{LogEntry, LogFilter, LoggingError};
20
21pub mod analytics;
22mod operations;
23
24pub use analytics::{AnalyticsEvent, AnalyticsRepository};
25
26#[derive(Clone, Debug)]
27pub struct LoggingRepository {
28 pool: Arc<PgPool>,
29 write_pool: Arc<PgPool>,
30 terminal_output: bool,
31 db_output: bool,
32}
33
34impl LoggingRepository {
35 pub fn new(db: &DbPool) -> Result<Self, LoggingError> {
36 let pool = db.pool_arc()?;
37 let write_pool = db.write_pool_arc()?;
38 Ok(Self {
39 pool,
40 write_pool,
41 terminal_output: true,
42 db_output: false,
43 })
44 }
45
46 #[must_use]
47 pub const fn with_terminal(mut self, enabled: bool) -> Self {
48 self.terminal_output = enabled;
49 self
50 }
51
52 #[must_use]
53 pub const fn with_database(mut self, enabled: bool) -> Self {
54 self.db_output = enabled;
55 self
56 }
57
58 pub async fn log(&self, entry: LogEntry) -> Result<(), LoggingError> {
59 entry.validate()?;
60
61 if self.terminal_output {
62 let mut stdout = std::io::stdout();
63 writeln!(stdout, "{entry}").ok();
64 }
65
66 if self.db_output {
67 operations::create_log(&self.write_pool, &entry).await?;
68 }
69
70 Ok(())
71 }
72
73 pub async fn get_recent_logs(&self, limit: i64) -> Result<Vec<LogEntry>, LoggingError> {
74 operations::list_logs(&self.pool, limit).await
75 }
76
77 pub async fn get_logs_by_module_patterns(
78 &self,
79 patterns: &[String],
80 limit: i64,
81 ) -> Result<Vec<LogEntry>, LoggingError> {
82 operations::list_logs_by_module_patterns(&self.pool, patterns, limit).await
83 }
84
85 pub async fn cleanup_old_logs(&self, older_than: DateTime<Utc>) -> Result<u64, LoggingError> {
86 operations::cleanup_logs_before(&self.write_pool, older_than).await
87 }
88
89 pub async fn count_logs_before(&self, cutoff: DateTime<Utc>) -> Result<u64, LoggingError> {
90 operations::count_logs_before(&self.pool, cutoff).await
91 }
92
93 pub async fn clear_all_logs(&self) -> Result<u64, LoggingError> {
94 operations::clear_all_logs(&self.write_pool).await
95 }
96
97 pub async fn get_logs_paginated(
98 &self,
99 filter: &LogFilter,
100 ) -> Result<(Vec<LogEntry>, i64), LoggingError> {
101 operations::list_logs_paginated(&self.pool, filter).await
102 }
103
104 pub async fn get_by_id(&self, id: &LogId) -> Result<Option<LogEntry>, LoggingError> {
105 operations::get_log(&self.pool, id).await
106 }
107
108 pub async fn update_log_entry(
109 &self,
110 id: &LogId,
111 entry: &LogEntry,
112 ) -> Result<bool, LoggingError> {
113 operations::update_log(&self.write_pool, id, entry).await
114 }
115
116 pub async fn delete_log_entry(&self, id: &LogId) -> Result<bool, LoggingError> {
117 operations::delete_log(&self.write_pool, id).await
118 }
119
120 pub async fn delete_log_entries(&self, ids: &[LogId]) -> Result<u64, LoggingError> {
121 operations::delete_logs_multiple(&self.write_pool, ids).await
122 }
123}