chore: standardize security and quality foundations
This commit is contained in:
@@ -3,6 +3,7 @@ import json
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from datetime import datetime, timezone
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from typing import Any, Mapping, Optional
|
||||
from urllib.parse import parse_qs
|
||||
@@ -39,6 +40,22 @@ class RequestContextFilter(logging.Filter):
|
||||
return True
|
||||
|
||||
|
||||
class JsonLogFormatter(logging.Formatter):
|
||||
"""Stable JSON output for production log collectors."""
|
||||
|
||||
def format(self, record: logging.LogRecord) -> str:
|
||||
payload: dict[str, Any] = {
|
||||
"timestamp": datetime.fromtimestamp(record.created, timezone.utc).isoformat(),
|
||||
"level": record.levelname,
|
||||
"logger": record.name,
|
||||
"request_id": getattr(record, "request_id", "-"),
|
||||
"message": record.getMessage(),
|
||||
}
|
||||
if record.exc_info:
|
||||
payload["exception"] = self.formatException(record.exc_info)
|
||||
return json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
|
||||
|
||||
|
||||
def bind_request_id(request_id: str) -> contextvars.Token[str]:
|
||||
return REQUEST_ID_CONTEXT.set(request_id or "-")
|
||||
|
||||
@@ -150,6 +167,7 @@ def configure_logging(
|
||||
log_file_backup_count: int = 10,
|
||||
log_http_client_level: Optional[str] = "INFO",
|
||||
log_background_sync_level: Optional[str] = "INFO",
|
||||
log_format: Optional[str] = "text",
|
||||
) -> None:
|
||||
level_name = (log_level or "INFO").upper()
|
||||
level = getattr(logging, level_name, logging.INFO)
|
||||
@@ -176,10 +194,13 @@ def configure_logging(
|
||||
handlers.append(file_handler)
|
||||
|
||||
context_filter = RequestContextFilter()
|
||||
formatter = logging.Formatter(
|
||||
fmt="%(asctime)s | %(levelname)s | %(name)s | request_id=%(request_id)s | %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
if str(log_format or "text").strip().lower() == "json":
|
||||
formatter: logging.Formatter = JsonLogFormatter()
|
||||
else:
|
||||
formatter = logging.Formatter(
|
||||
fmt="%(asctime)s | %(levelname)s | %(name)s | request_id=%(request_id)s | %(message)s",
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
for handler in handlers:
|
||||
handler.addFilter(context_filter)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
Reference in New Issue
Block a user