koprogo_api/infrastructure/
audit_logger.rs

1use crate::application::ports::AuditLogRepository;
2use crate::infrastructure::audit::AuditLogEntry;
3use std::sync::Arc;
4
5/// AuditLogger manages both stdout logging and database persistence
6pub struct AuditLogger {
7    repository: Option<Arc<dyn AuditLogRepository>>,
8}
9
10impl AuditLogger {
11    /// Create a new AuditLogger with optional database persistence
12    pub fn new(repository: Option<Arc<dyn AuditLogRepository>>) -> Self {
13        Self { repository }
14    }
15
16    /// Log an audit entry to stdout and optionally persist to database
17    pub async fn log(&self, entry: &AuditLogEntry) {
18        // Always log to stdout for real-time monitoring
19        entry.log();
20
21        // Persist to database if repository is available
22        if let Some(repo) = &self.repository {
23            if let Err(e) = repo.create(entry).await {
24                log::error!("[AUDIT] Failed to persist audit log to database: {}", e);
25            }
26        }
27    }
28}
29
30#[cfg(test)]
31mod tests {
32    use super::*;
33    use crate::infrastructure::audit::{AuditEventType, AuditLogEntry};
34    use uuid::Uuid;
35
36    #[tokio::test]
37    async fn test_audit_logger_without_repository() {
38        let logger = AuditLogger::new(None);
39        let entry = AuditLogEntry::new(
40            AuditEventType::UserLogin,
41            Some(Uuid::new_v4()),
42            Some(Uuid::new_v4()),
43        );
44
45        // Should not panic even without repository
46        logger.log(&entry).await;
47    }
48}