1pub mod compliance;
58pub mod entry;
59pub mod formats;
60pub mod persistence;
61pub mod encryption;
62pub mod redaction;
63pub mod metrics;
64
65pub use compliance::{ComplianceFramework, ComplianceReport, ComplianceReporter};
66pub use entry::{LogEntry, SecurityLevel};
67pub use formats::{CEFFormatter, LEEFFormatter, SplunkFormatter, SyslogFormatter};
68pub use persistence::{LogWriter, PersistenceConfig};
69pub use encryption::{LogEncryptor, EncryptedLogEntry};
70pub use redaction::{LogRedactor, RedactionPattern, RedactionConfig};
71pub use metrics::{LogMetrics, MetricsSnapshot};
72
73use std::sync::{Arc, Mutex};
74use std::time::{Duration, Instant};
75use std::collections::HashMap;
76use thiserror::Error;
77
78#[derive(Error, Debug)]
80pub enum LoggerError {
81 #[error("Rate limit exceeded: {0}")]
82 RateLimitExceeded(String),
83
84 #[error("Encryption error: {0}")]
85 EncryptionError(String),
86
87 #[error("Compression error: {0}")]
88 CompressionError(String),
89
90 #[error("Serialization error: {0}")]
91 SerializationError(String),
92}
93
94#[derive(Debug, Clone)]
96pub struct LoggerConfig {
97 pub enable_encryption: bool,
98 pub enable_compression: bool,
99 pub enable_redaction: bool,
100 pub correlation_id: Option<String>,
101 pub rate_limit_per_second: Option<u32>,
102 pub max_entry_size: usize,
103 pub retention_days: u32,
104 pub hash_algorithm: HashAlgorithm,
105}
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109pub enum HashAlgorithm {
110 Sha256,
111 Sha3_256,
112}
113
114impl Default for LoggerConfig {
115 fn default() -> Self {
116 Self {
117 enable_encryption: false,
118 enable_compression: false,
119 enable_redaction: true,
120 correlation_id: None,
121 rate_limit_per_second: None,
122 max_entry_size: 1024 * 1024, retention_days: 90,
124 hash_algorithm: HashAlgorithm::Sha256,
125 }
126 }
127}
128
129impl LoggerConfig {
130 pub fn with_encryption(mut self, enable: bool) -> Self {
132 self.enable_encryption = enable;
133 self
134 }
135
136 pub fn with_compression(mut self, enable: bool) -> Self {
138 self.enable_compression = enable;
139 self
140 }
141
142 pub fn with_correlation_id(mut self, id: impl Into<String>) -> Self {
144 self.correlation_id = Some(id.into());
145 self
146 }
147
148 pub fn with_rate_limit(mut self, limit: u32) -> Self {
150 self.rate_limit_per_second = Some(limit);
151 self
152 }
153
154 pub fn with_hash_algorithm(mut self, algorithm: HashAlgorithm) -> Self {
156 self.hash_algorithm = algorithm;
157 self
158 }
159
160 pub fn with_redaction(mut self, enable: bool) -> Self {
162 self.enable_redaction = enable;
163 self
164 }
165}
166
167#[derive(Debug)]
169struct RateLimiter {
170 limit: u32,
171 window_start: Instant,
172 count: u32,
173}
174
175impl RateLimiter {
176 fn new(limit: u32) -> Self {
177 Self {
178 limit,
179 window_start: Instant::now(),
180 count: 0,
181 }
182 }
183
184 fn check(&mut self) -> bool {
185 let now = Instant::now();
186 if now.duration_since(self.window_start) >= Duration::from_secs(1) {
187 self.window_start = now;
188 self.count = 0;
189 }
190
191 if self.count >= self.limit {
192 false
193 } else {
194 self.count += 1;
195 true
196 }
197 }
198}
199
200#[derive(Clone)]
202pub struct SecureLogger {
203 entries: Arc<Mutex<Vec<LogEntry>>>,
204 source: Option<String>,
205 config: LoggerConfig,
206 rate_limiter: Arc<Mutex<Option<RateLimiter>>>,
207 metrics: Arc<Mutex<LogMetrics>>,
208 redactor: Arc<LogRedactor>,
209}
210
211impl SecureLogger {
212 pub fn new() -> Self {
214 Self {
215 entries: Arc::new(Mutex::new(Vec::new())),
216 source: None,
217 config: LoggerConfig::default(),
218 rate_limiter: Arc::new(Mutex::new(None)),
219 metrics: Arc::new(Mutex::new(LogMetrics::new())),
220 redactor: Arc::new(LogRedactor::default()),
221 }
222 }
223
224 pub fn with_config(config: LoggerConfig) -> Self {
226 let rate_limiter = config.rate_limit_per_second.map(RateLimiter::new);
227 Self {
228 entries: Arc::new(Mutex::new(Vec::new())),
229 source: None,
230 config,
231 rate_limiter: Arc::new(Mutex::new(rate_limiter)),
232 metrics: Arc::new(Mutex::new(LogMetrics::new())),
233 redactor: Arc::new(LogRedactor::default()),
234 }
235 }
236
237 pub fn with_source(source: impl Into<String>) -> Self {
239 Self {
240 entries: Arc::new(Mutex::new(Vec::new())),
241 source: Some(source.into()),
242 config: LoggerConfig::default(),
243 rate_limiter: Arc::new(Mutex::new(None)),
244 metrics: Arc::new(Mutex::new(LogMetrics::new())),
245 redactor: Arc::new(LogRedactor::default()),
246 }
247 }
248
249 pub fn config(&self) -> &LoggerConfig {
251 &self.config
252 }
253
254 pub fn get_metrics(&self) -> MetricsSnapshot {
256 let metrics = self.metrics.lock().unwrap();
257 metrics.snapshot()
258 }
259
260 fn check_rate_limit(&self) -> bool {
262 let mut limiter = self.rate_limiter.lock().unwrap();
263 if let Some(ref mut rl) = *limiter {
264 rl.check()
265 } else {
266 true
267 }
268 }
269
270 fn apply_redaction(&self, message: &str) -> String {
272 if self.config.enable_redaction {
273 self.redactor.redact(message)
274 } else {
275 message.to_string()
276 }
277 }
278
279 pub fn info(&self, message: impl Into<String>) {
281 self.log(SecurityLevel::Info, message.into(), None, None);
282 }
283
284 pub fn warning(&self, message: impl Into<String>) {
286 self.log(SecurityLevel::Warning, message.into(), None, None);
287 }
288
289 pub fn security_event(&self, message: impl Into<String>, metadata: Option<serde_json::Value>) {
291 self.log(SecurityLevel::SecurityEvent, message.into(), metadata, None);
292 }
293
294 pub fn critical(&self, message: impl Into<String>, metadata: Option<serde_json::Value>) {
296 self.log(SecurityLevel::Critical, message.into(), metadata, None);
297 }
298
299 pub fn audit(&self, message: impl Into<String>, metadata: Option<serde_json::Value>) {
301 self.log(SecurityLevel::Audit, message.into(), metadata, None);
302 }
303
304 pub fn log_with_category(
306 &self,
307 level: SecurityLevel,
308 message: impl Into<String>,
309 metadata: Option<serde_json::Value>,
310 category: impl Into<String>,
311 ) {
312 self.log(level, message.into(), metadata, Some(category.into()));
313 }
314
315 fn log(
317 &self,
318 level: SecurityLevel,
319 message: String,
320 metadata: Option<serde_json::Value>,
321 category: Option<String>,
322 ) {
323 let entry =
324 LogEntry::new_with_context(level, message, metadata, self.source.clone(), category);
325 let mut entries = self.entries.lock().unwrap();
326 entries.push(entry);
327 }
328
329 pub fn get_entries(&self) -> Vec<LogEntry> {
331 let entries = self.entries.lock().unwrap();
332 entries.clone()
333 }
334
335 pub fn get_entries_by_level(&self, level: SecurityLevel) -> Vec<LogEntry> {
337 let entries = self.entries.lock().unwrap();
338 entries
339 .iter()
340 .filter(|e| e.level == level)
341 .cloned()
342 .collect()
343 }
344
345 pub fn get_entries_by_category(&self, category: &str) -> Vec<LogEntry> {
347 let entries = self.entries.lock().unwrap();
348 entries
349 .iter()
350 .filter(|e| e.category.as_deref() == Some(category))
351 .cloned()
352 .collect()
353 }
354
355 pub fn verify_all_integrity(&self) -> bool {
357 let entries = self.entries.lock().unwrap();
358 entries.iter().all(|entry| entry.verify_integrity())
359 }
360
361 pub fn export_json(&self) -> Result<String, serde_json::Error> {
363 let entries = self.entries.lock().unwrap();
364 serde_json::to_string_pretty(&*entries)
365 }
366
367 pub fn export_cef(&self) -> Vec<String> {
369 let entries = self.entries.lock().unwrap();
370 entries.iter().map(CEFFormatter::format).collect()
371 }
372
373 pub fn export_leef(&self) -> Vec<String> {
375 let entries = self.entries.lock().unwrap();
376 entries.iter().map(LEEFFormatter::format).collect()
377 }
378
379 pub fn export_syslog(&self) -> Vec<String> {
381 let entries = self.entries.lock().unwrap();
382 entries.iter().map(SyslogFormatter::format).collect()
383 }
384
385 pub fn export_splunk(&self) -> Vec<String> {
387 let entries = self.entries.lock().unwrap();
388 entries.iter().map(SplunkFormatter::format).collect()
389 }
390
391 pub fn count_by_level(&self, level: SecurityLevel) -> usize {
393 let entries = self.entries.lock().unwrap();
394 entries.iter().filter(|e| e.level == level).count()
395 }
396
397 pub fn get_entries_by_date_range(
399 &self,
400 start: chrono::DateTime<chrono::Utc>,
401 end: chrono::DateTime<chrono::Utc>,
402 ) -> Vec<LogEntry> {
403 let entries = self.entries.lock().unwrap();
404 entries
405 .iter()
406 .filter(|e| e.timestamp >= start && e.timestamp <= end)
407 .cloned()
408 .collect()
409 }
410
411 pub fn clear(&self) {
413 let mut entries = self.entries.lock().unwrap();
414 entries.clear()
415 }
416
417 pub fn get_recent_entries(&self, count: usize) -> Vec<LogEntry> {
419 let entries = self.entries.lock().unwrap();
420 let total = entries.len();
421 if total <= count {
422 entries.clone()
423 } else {
424 entries[total - count..].to_vec()
425 }
426 }
427
428 pub fn search(&self, query: &str) -> Vec<LogEntry> {
430 let entries = self.entries.lock().unwrap();
431 entries
432 .iter()
433 .filter(|e| e.message.contains(query))
434 .cloned()
435 .collect()
436 }
437
438 pub fn get_statistics(&self) -> LogStatistics {
440 let entries = self.entries.lock().unwrap();
441 let total_entries = entries.len();
442
443 let mut stats = LogStatistics {
444 total_entries,
445 info_count: 0,
446 warning_count: 0,
447 security_event_count: 0,
448 critical_count: 0,
449 audit_count: 0,
450 };
451
452 for entry in entries.iter() {
453 match entry.level {
454 SecurityLevel::Info => stats.info_count += 1,
455 SecurityLevel::Warning => stats.warning_count += 1,
456 SecurityLevel::SecurityEvent => stats.security_event_count += 1,
457 SecurityLevel::Critical => stats.critical_count += 1,
458 SecurityLevel::Audit => stats.audit_count += 1,
459 }
460 }
461
462 stats
463 }
464
465 pub fn generate_sox_report(
467 &self,
468 period_start: chrono::DateTime<chrono::Utc>,
469 period_end: chrono::DateTime<chrono::Utc>,
470 ) -> ComplianceReport {
471 let entries = self.get_entries();
472 ComplianceReporter::generate_sox_report(&entries, period_start, period_end)
473 }
474
475 pub fn generate_pci_report(
477 &self,
478 period_start: chrono::DateTime<chrono::Utc>,
479 period_end: chrono::DateTime<chrono::Utc>,
480 ) -> ComplianceReport {
481 let entries = self.get_entries();
482 ComplianceReporter::generate_pci_report(&entries, period_start, period_end)
483 }
484
485 pub fn generate_glba_report(
487 &self,
488 period_start: chrono::DateTime<chrono::Utc>,
489 period_end: chrono::DateTime<chrono::Utc>,
490 ) -> ComplianceReport {
491 let entries = self.get_entries();
492 ComplianceReporter::generate_glba_report(&entries, period_start, period_end)
493 }
494}
495
496#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
498pub struct LogStatistics {
499 pub total_entries: usize,
500 pub info_count: usize,
501 pub warning_count: usize,
502 pub security_event_count: usize,
503 pub critical_count: usize,
504 pub audit_count: usize,
505}
506
507impl Default for SecureLogger {
508 fn default() -> Self {
509 Self::new()
510 }
511}
512
513#[cfg(test)]
514mod tests {
515 use super::*;
516
517 #[test]
518 fn test_secure_logger() {
519 let logger = SecureLogger::new();
520 logger.info("Application started");
521 logger.warning("High memory usage detected");
522 logger.audit(
523 "User authentication successful",
524 Some(serde_json::json!({
525 "user_id": "12345",
526 "timestamp": "2024-11-06T00:00:00Z"
527 })),
528 );
529
530 assert_eq!(logger.get_entries().len(), 3);
531 assert_eq!(logger.count_by_level(SecurityLevel::Info), 1);
532 assert_eq!(logger.count_by_level(SecurityLevel::Warning), 1);
533 assert_eq!(logger.count_by_level(SecurityLevel::Audit), 1);
534 }
535
536 #[test]
537 fn test_thread_safety() {
538 use std::thread;
539
540 let logger = SecureLogger::new();
541 let mut handles = vec![];
542
543 for i in 0..10 {
544 let logger_clone = logger.clone();
545 let handle = thread::spawn(move || {
546 logger_clone.info(format!("Thread {} message", i));
547 });
548 handles.push(handle);
549 }
550
551 for handle in handles {
552 handle.join().unwrap();
553 }
554
555 assert_eq!(logger.get_entries().len(), 10);
556 }
557
558 #[test]
559 fn test_cef_export() {
560 let logger = SecureLogger::new();
561 logger.security_event(
562 "Failed login attempt",
563 Some(serde_json::json!({
564 "username": "admin"
565 })),
566 );
567
568 let cef_logs = logger.export_cef();
569 assert_eq!(cef_logs.len(), 1);
570 assert!(cef_logs[0].starts_with("CEF:0|"));
571 }
572
573 #[test]
574 fn test_leef_export() {
575 let logger = SecureLogger::new();
576 logger.critical("Security breach detected", None);
577
578 let leef_logs = logger.export_leef();
579 assert_eq!(leef_logs.len(), 1);
580 assert!(leef_logs[0].starts_with("LEEF:2.0|"));
581 }
582
583 #[test]
584 fn test_compliance_reporting() {
585 let logger = SecureLogger::new();
586 logger.audit(
587 "Transaction processed",
588 Some(serde_json::json!({
589 "amount": 1000,
590 "currency": "USD"
591 })),
592 );
593
594 let start = chrono::Utc::now() - chrono::Duration::hours(1);
595 let end = chrono::Utc::now();
596
597 let sox_report = logger.generate_sox_report(start, end);
598 assert_eq!(sox_report.framework, ComplianceFramework::SOX);
599 assert_eq!(sox_report.audit_events, 1);
600 }
601
602 #[test]
603 fn test_logger_with_source() {
604 let logger = SecureLogger::with_source("web-server-01");
605 logger.info("Server started");
606
607 let entries = logger.get_entries();
608 assert_eq!(entries[0].source, Some("web-server-01".to_string()));
609 }
610
611 #[test]
612 fn test_category_filtering() {
613 let logger = SecureLogger::new();
614 logger.log_with_category(
615 SecurityLevel::SecurityEvent,
616 "Login failed",
617 None,
618 "authentication",
619 );
620 logger.log_with_category(SecurityLevel::Info, "Page loaded", None, "web");
621
622 let auth_events = logger.get_entries_by_category("authentication");
623 assert_eq!(auth_events.len(), 1);
624 assert_eq!(auth_events[0].message, "Login failed");
625 }
626}