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