88 lines
2.5 KiB
Python
88 lines
2.5 KiB
Python
"""
|
|
Logging configuration for VideoDetect.
|
|
|
|
Sets up JSON structured logging via python-json-logger with:
|
|
- Configurable log levels
|
|
- Standardized field names
|
|
- Log rotation
|
|
- All logs to stdout for Docker capture
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
import logging.handlers
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
def setup_logging(
|
|
level: str = "INFO",
|
|
log_format: str = "json",
|
|
rotation_max_bytes: int = 104857600, # 100MB
|
|
rotation_backup_count: int = 10,
|
|
):
|
|
"""Configure structured logging for the application."""
|
|
log_level = getattr(logging, level.upper(), logging.INFO)
|
|
|
|
# Root logger
|
|
root_logger = logging.getLogger()
|
|
root_logger.setLevel(log_level)
|
|
|
|
# Remove existing handlers
|
|
root_logger.handlers.clear()
|
|
|
|
# Handler: stdout (for Docker capture)
|
|
handler = logging.StreamHandler(sys.stdout)
|
|
handler.setLevel(log_level)
|
|
|
|
if log_format == "json":
|
|
formatter = JsonFormatter()
|
|
else:
|
|
formatter = logging.Formatter(
|
|
"%(asctime)s %(levelname)s %(name)s %(message)s",
|
|
datefmt="%Y-%m-%dT%H:%M:%S%z",
|
|
)
|
|
|
|
handler.setFormatter(formatter)
|
|
root_logger.addHandler(handler)
|
|
|
|
# Handler: file rotation (for persistence)
|
|
file_handler = logging.handlers.RotatingFileHandler(
|
|
filename="/logs/videodetect.log",
|
|
maxBytes=rotation_max_bytes,
|
|
backupCount=rotation_backup_count,
|
|
encoding="utf-8",
|
|
)
|
|
file_handler.setLevel(log_level)
|
|
file_handler.setFormatter(formatter)
|
|
root_logger.addHandler(file_handler)
|
|
|
|
logging.info("Logging configured: level=%s format=%s", level, log_format)
|
|
|
|
|
|
class JsonFormatter(logging.Formatter):
|
|
"""JSON log formatter with standardized fields."""
|
|
|
|
def format(self, record: logging.LogRecord) -> str:
|
|
log_data = {
|
|
"timestamp": datetime.fromtimestamp(record.created, tz=timezone.utc).isoformat(),
|
|
"level": record.levelname,
|
|
"logger": record.name,
|
|
"message": record.getMessage(),
|
|
"module": record.module,
|
|
"function": record.funcName,
|
|
"line": record.lineno,
|
|
}
|
|
|
|
# Add extra fields
|
|
if hasattr(record, "video_id"):
|
|
log_data["video_id"] = record.video_id
|
|
if hasattr(record, "metadata"):
|
|
log_data["metadata"] = record.metadata
|
|
|
|
# Add exception info if present
|
|
if record.exc_info and record.exc_info[0] is not None:
|
|
log_data["exception"] = self.formatException(record.exc_info)
|
|
|
|
return json.dumps(log_data, default=str)
|