50 lines
1.8 KiB
Python
50 lines
1.8 KiB
Python
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")
|