import json import logging import time from pathlib import Path from typing import Any, Dict class AuditLogger: def __init__(self, log_path: str): self.log_path = Path(log_path) self.log_path.parent.mkdir(parents=True, exist_ok=True) self.json_log_path = self.log_path.with_suffix(".jsonl") self.text_logger = logging.getLogger("audit_text") self.text_logger.setLevel(logging.INFO) if not self.text_logger.handlers: handler = logging.FileHandler(self.log_path, encoding="utf-8") formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s") handler.setFormatter(formatter) self.text_logger.addHandler(handler) @staticmethod def sanitize(payload: Dict[str, Any]) -> Dict[str, Any]: hidden_keys = {"token", "authorization", "password", "password_hash", "command"} sanitized: Dict[str, Any] = {} for key, value in payload.items(): if key.lower() in hidden_keys: sanitized[key] = "***" else: sanitized[key] = value return sanitized def log(self, **kwargs: Any) -> None: start = time.perf_counter() record = self.sanitize(kwargs) record["ts"] = time.time() record["duration_ms"] = int((time.perf_counter() - start) * 1000) self.text_logger.info( "operation=%s target=%s result=%s code=%s request_id=%s", record.get("operation"), record.get("target"), record.get("result"), record.get("error_code"), record.get("request_id"), ) with self.json_log_path.open("a", encoding="utf-8") as file: file.write(json.dumps(record, ensure_ascii=False) + "\n")