1pub mod entry;
34pub mod persistence;
35pub mod formats;
36pub mod compliance;
37
38pub use entry::{LogEntry, SecurityLevel};
39pub use persistence::{LogWriter, PersistenceConfig};
40pub use formats::{CEFFormatter, LEEFFormatter, SyslogFormatter, SplunkFormatter};
41pub use compliance::{ComplianceFramework, ComplianceReport, ComplianceReporter};
42
43use std::sync::{Arc, Mutex};
44
45#[derive(Clone)]
47pub struct SecureLogger {
48 entries: Arc<Mutex<Vec<LogEntry>>>,
49 source: Option<String>,
50}
51
52impl SecureLogger {
53 pub fn new() -> Self {
55 Self {
56 entries: Arc::new(Mutex::new(Vec::new())),
57 source: None,
58 }
59 }
60
61 pub fn with_source(source: impl Into<String>) -> Self {
63 Self {
64 entries: Arc::new(Mutex::new(Vec::new())),
65 source: Some(source.into()),
66 }
67 }
68
69 pub fn info(&self, message: impl Into<String>) {
71 self.log(SecurityLevel::Info, message.into(), None, None);
72 }
73
74 pub fn warning(&self, message: impl Into<String>) {
76 self.log(SecurityLevel::Warning, message.into(), None, None);
77 }
78
79 pub fn security_event(&self, message: impl Into<String>, metadata: Option<serde_json::Value>) {
81 self.log(SecurityLevel::SecurityEvent, message.into(), metadata, None);
82 }
83
84 pub fn critical(&self, message: impl Into<String>, metadata: Option<serde_json::Value>) {
86 self.log(SecurityLevel::Critical, message.into(), metadata, None);
87 }
88
89 pub fn audit(&self, message: impl Into<String>, metadata: Option<serde_json::Value>) {
91 self.log(SecurityLevel::Audit, message.into(), metadata, None);
92 }
93
94 pub fn log_with_category(
96 &self,
97 level: SecurityLevel,
98 message: impl Into<String>,
99 metadata: Option<serde_json::Value>,
100 category: impl Into<String>,
101 ) {
102 self.log(level, message.into(), metadata, Some(category.into()));
103 }
104
105 fn log(&self, level: SecurityLevel, message: String, metadata: Option<serde_json::Value>, category: Option<String>) {
107 let entry = LogEntry::new_with_context(level, message, metadata, self.source.clone(), category);
108 let mut entries = self.entries.lock().unwrap();
109 entries.push(entry);
110 }
111
112 pub fn get_entries(&self) -> Vec<LogEntry> {
114 let entries = self.entries.lock().unwrap();
115 entries.clone()
116 }
117
118 pub fn get_entries_by_level(&self, level: SecurityLevel) -> Vec<LogEntry> {
120 let entries = self.entries.lock().unwrap();
121 entries
122 .iter()
123 .filter(|e| e.level == level)
124 .cloned()
125 .collect()
126 }
127
128 pub fn get_entries_by_category(&self, category: &str) -> Vec<LogEntry> {
130 let entries = self.entries.lock().unwrap();
131 entries
132 .iter()
133 .filter(|e| e.category.as_deref() == Some(category))
134 .cloned()
135 .collect()
136 }
137
138 pub fn verify_all_integrity(&self) -> bool {
140 let entries = self.entries.lock().unwrap();
141 entries.iter().all(|entry| entry.verify_integrity())
142 }
143
144 pub fn export_json(&self) -> Result<String, serde_json::Error> {
146 let entries = self.entries.lock().unwrap();
147 serde_json::to_string_pretty(&*entries)
148 }
149
150 pub fn export_cef(&self) -> Vec<String> {
152 let entries = self.entries.lock().unwrap();
153 entries.iter().map(|e| CEFFormatter::format(e)).collect()
154 }
155
156 pub fn export_leef(&self) -> Vec<String> {
158 let entries = self.entries.lock().unwrap();
159 entries.iter().map(|e| LEEFFormatter::format(e)).collect()
160 }
161
162 pub fn export_syslog(&self) -> Vec<String> {
164 let entries = self.entries.lock().unwrap();
165 entries.iter().map(|e| SyslogFormatter::format(e)).collect()
166 }
167
168 pub fn export_splunk(&self) -> Vec<String> {
170 let entries = self.entries.lock().unwrap();
171 entries.iter().map(|e| SplunkFormatter::format(e)).collect()
172 }
173
174 pub fn count_by_level(&self, level: SecurityLevel) -> usize {
176 let entries = self.entries.lock().unwrap();
177 entries.iter().filter(|e| e.level == level).count()
178 }
179
180 pub fn get_entries_by_date_range(
182 &self,
183 start: chrono::DateTime<chrono::Utc>,
184 end: chrono::DateTime<chrono::Utc>,
185 ) -> Vec<LogEntry> {
186 let entries = self.entries.lock().unwrap();
187 entries
188 .iter()
189 .filter(|e| e.timestamp >= start && e.timestamp <= end)
190 .cloned()
191 .collect()
192 }
193
194 pub fn clear(&self) {
196 let mut entries = self.entries.lock().unwrap();
197 entries.clear()
198 }
199
200 pub fn get_recent_entries(&self, count: usize) -> Vec<LogEntry> {
202 let entries = self.entries.lock().unwrap();
203 let total = entries.len();
204 if total <= count {
205 entries.clone()
206 } else {
207 entries[total - count..].to_vec()
208 }
209 }
210
211 pub fn search(&self, query: &str) -> Vec<LogEntry> {
213 let entries = self.entries.lock().unwrap();
214 entries
215 .iter()
216 .filter(|e| e.message.contains(query))
217 .cloned()
218 .collect()
219 }
220
221 pub fn get_statistics(&self) -> LogStatistics {
223 let entries = self.entries.lock().unwrap();
224 let total_entries = entries.len();
225
226 let mut stats = LogStatistics {
227 total_entries,
228 info_count: 0,
229 warning_count: 0,
230 security_event_count: 0,
231 critical_count: 0,
232 audit_count: 0,
233 };
234
235 for entry in entries.iter() {
236 match entry.level {
237 SecurityLevel::Info => stats.info_count += 1,
238 SecurityLevel::Warning => stats.warning_count += 1,
239 SecurityLevel::SecurityEvent => stats.security_event_count += 1,
240 SecurityLevel::Critical => stats.critical_count += 1,
241 SecurityLevel::Audit => stats.audit_count += 1,
242 }
243 }
244
245 stats
246 }
247
248 pub fn generate_sox_report(
250 &self,
251 period_start: chrono::DateTime<chrono::Utc>,
252 period_end: chrono::DateTime<chrono::Utc>,
253 ) -> ComplianceReport {
254 let entries = self.get_entries();
255 ComplianceReporter::generate_sox_report(&entries, period_start, period_end)
256 }
257
258 pub fn generate_pci_report(
260 &self,
261 period_start: chrono::DateTime<chrono::Utc>,
262 period_end: chrono::DateTime<chrono::Utc>,
263 ) -> ComplianceReport {
264 let entries = self.get_entries();
265 ComplianceReporter::generate_pci_report(&entries, period_start, period_end)
266 }
267
268 pub fn generate_glba_report(
270 &self,
271 period_start: chrono::DateTime<chrono::Utc>,
272 period_end: chrono::DateTime<chrono::Utc>,
273 ) -> ComplianceReport {
274 let entries = self.get_entries();
275 ComplianceReporter::generate_glba_report(&entries, period_start, period_end)
276 }
277}
278
279#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
281pub struct LogStatistics {
282 pub total_entries: usize,
283 pub info_count: usize,
284 pub warning_count: usize,
285 pub security_event_count: usize,
286 pub critical_count: usize,
287 pub audit_count: usize,
288}
289
290impl Default for SecureLogger {
291 fn default() -> Self {
292 Self::new()
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn test_secure_logger() {
302 let logger = SecureLogger::new();
303 logger.info("Application started");
304 logger.warning("High memory usage detected");
305 logger.audit("User authentication successful", Some(serde_json::json!({
306 "user_id": "12345",
307 "timestamp": "2024-11-06T00:00:00Z"
308 })));
309
310 assert_eq!(logger.get_entries().len(), 3);
311 assert_eq!(logger.count_by_level(SecurityLevel::Info), 1);
312 assert_eq!(logger.count_by_level(SecurityLevel::Warning), 1);
313 assert_eq!(logger.count_by_level(SecurityLevel::Audit), 1);
314 }
315
316 #[test]
317 fn test_thread_safety() {
318 use std::thread;
319
320 let logger = SecureLogger::new();
321 let mut handles = vec![];
322
323 for i in 0..10 {
324 let logger_clone = logger.clone();
325 let handle = thread::spawn(move || {
326 logger_clone.info(format!("Thread {} message", i));
327 });
328 handles.push(handle);
329 }
330
331 for handle in handles {
332 handle.join().unwrap();
333 }
334
335 assert_eq!(logger.get_entries().len(), 10);
336 }
337
338 #[test]
339 fn test_cef_export() {
340 let logger = SecureLogger::new();
341 logger.security_event("Failed login attempt", Some(serde_json::json!({
342 "username": "admin"
343 })));
344
345 let cef_logs = logger.export_cef();
346 assert_eq!(cef_logs.len(), 1);
347 assert!(cef_logs[0].starts_with("CEF:0|"));
348 }
349
350 #[test]
351 fn test_leef_export() {
352 let logger = SecureLogger::new();
353 logger.critical("Security breach detected", None);
354
355 let leef_logs = logger.export_leef();
356 assert_eq!(leef_logs.len(), 1);
357 assert!(leef_logs[0].starts_with("LEEF:2.0|"));
358 }
359
360 #[test]
361 fn test_compliance_reporting() {
362 let logger = SecureLogger::new();
363 logger.audit("Transaction processed", Some(serde_json::json!({
364 "amount": 1000,
365 "currency": "USD"
366 })));
367
368 let start = chrono::Utc::now() - chrono::Duration::hours(1);
369 let end = chrono::Utc::now();
370
371 let sox_report = logger.generate_sox_report(start, end);
372 assert_eq!(sox_report.framework, ComplianceFramework::SOX);
373 assert_eq!(sox_report.audit_events, 1);
374 }
375
376 #[test]
377 fn test_logger_with_source() {
378 let logger = SecureLogger::with_source("web-server-01");
379 logger.info("Server started");
380
381 let entries = logger.get_entries();
382 assert_eq!(entries[0].source, Some("web-server-01".to_string()));
383 }
384
385 #[test]
386 fn test_category_filtering() {
387 let logger = SecureLogger::new();
388 logger.log_with_category(
389 SecurityLevel::SecurityEvent,
390 "Login failed",
391 None,
392 "authentication"
393 );
394 logger.log_with_category(
395 SecurityLevel::Info,
396 "Page loaded",
397 None,
398 "web"
399 );
400
401 let auth_events = logger.get_entries_by_category("authentication");
402 assert_eq!(auth_events.len(), 1);
403 assert_eq!(auth_events[0].message, "Login failed");
404 }
405}