Update logging_config.py

This commit is contained in:
Saifeddine ALOUI
2025-09-05 15:39:07 +02:00
committed by GitHub
parent 49c246bf0c
commit ff6781ca6f

View File

@@ -4,7 +4,7 @@ Centralised logging configuration for the Ollama Proxy Server.
Features
--------
* Humanreadable console output by default.
* Humanreadable console output by default (with proper millisecond timestamps).
* Optional JSON output via the LOG_FORMAT envvar (kept for backwardcompatibility).
* All loggers (root, uvicorn, gunicorn, etc.) share the same configuration.
* The `setup_logging()` helper can be called from any entrypoint (FastAPI,
@@ -15,7 +15,6 @@ import logging
import logging.config
import os
import sys
from datetime import datetime
from pythonjsonlogger import jsonlogger
# ----------------------------------------------------------------------
@@ -23,14 +22,14 @@ from pythonjsonlogger import jsonlogger
# ----------------------------------------------------------------------
class HumanReadableFormatter(logging.Formatter):
"""
Example output:
2025-09-05 12:15:50,297 [ERROR] gunicorn.error Worker (pid:590871) was sent SIGINT!
Example output (note the millisecond precision):
2025-09-05 15:35:22,123 [INFO] gunicorn.error Starting gunicorn 23.0.0
"""
DEFAULT_FORMAT = "%(asctime)s [%(levelname)s] %(name)s %(message)s"
DEFAULT_DATEFMT = "%Y-%m-%d %H:%M:%S,%f"
# %(asctime)s is generated by the base Formatter; we append milliseconds via %(msecs)03d
DEFAULT_FORMAT = "%(asctime)s,%(msecs)03d [%(levelname)s] %(name)s %(message)s"
DEFAULT_DATEFMT = "%Y-%m-%d %H:%M:%S" # no %f here we add ms ourselves
def __init__(self):
# ``asctime`` already includes microseconds; we trim to milliseconds
super().__init__(self.DEFAULT_FORMAT, self.DEFAULT_DATEFMT)
# ----------------------------------------------------------------------
@@ -38,11 +37,11 @@ class HumanReadableFormatter(logging.Formatter):
# ----------------------------------------------------------------------
class JsonFormatter(jsonlogger.JsonFormatter):
"""
Emits the same fields that the original configuration emitted.
Emits JSON logs similar to the original configuration.
"""
def add_fields(self, log_record, record, message_dict):
super().add_fields(log_record, record, message_dict)
# Ensure a numeric epoch timestamp like the previous version
# Preserve a float epoch timestamp like the previous version
if not log_record.get("timestamp"):
log_record["timestamp"] = record.created
# Normalise level name to uppercase
@@ -53,7 +52,7 @@ class JsonFormatter(jsonlogger.JsonFormatter):
# ----------------------------------------------------------------------
def _build_logging_config(log_level: str = "INFO") -> dict:
"""
Returns a ``dict`` compatible with ``logging.config.dictConfig``.
Returns a dict compatible with ``logging.config.dictConfig``.
``log_level`` can be any standard level name (caseinsensitive).
"""
level = log_level.upper()
@@ -86,14 +85,17 @@ def _build_logging_config(log_level: str = "INFO") -> dict:
"stream": "ext://sys.stdout",
},
},
# ---------- ROOT LOGGER ----------
# ------------------------------------------------------------------
# ROOT LOGGER (required this was missing before)
# ------------------------------------------------------------------
"root": {
"level": level,
"handlers": ["default"],
},
# ---------- OTHER LOGGERS ----------
# ------------------------------------------------------------------
# SPECIFIC LIBRARY LOGGERS (prevent duplicate handlers)
# ------------------------------------------------------------------
"loggers": {
# Explicitly configure the popular libraries so they dont add extra handlers
"uvicorn.error": {"handlers": ["default"], "level": level, "propagate": False},
"uvicorn.access": {"handlers": ["default"], "level": level, "propagate": False},
"gunicorn.error": {"handlers": ["default"], "level": level, "propagate": False},