todoappapi / logging.py
GrowWithTalha's picture
feat: sync backend changes from SDDRI-Hackathon-2
84c328d
"""Clean logging configuration for development.
Provides simple, readable logs for development with optional JSON mode for production.
"""
import logging
import logging.config
import sys
from typing import Optional
class CleanFormatter(logging.Formatter):
"""Simple, clean formatter for readable development logs."""
# Color codes for terminal output
COLORS = {
"DEBUG": "\033[36m", # Cyan
"INFO": "\033[32m", # Green
"WARNING": "\033[33m", # Yellow
"ERROR": "\033[31m", # Red
"CRITICAL": "\033[35m", # Magenta
"RESET": "\033[0m", # Reset
}
def __init__(self, use_colors: bool = True):
"""Initialize formatter.
Args:
use_colors: Whether to use ANSI color codes (disable for file logs)
"""
self.use_colors = use_colors
super().__init__()
def format(self, record: logging.LogRecord) -> str:
"""Format log record as a clean, readable string."""
level = record.levelname
module = record.name.split(".")[-1] if "." in record.name else record.name
message = record.getMessage()
# Build the log line
if self.use_colors:
color = self.COLORS.get(level, "")
reset = self.COLORS["RESET"]
formatted = f"{color}{level:8}{reset} {module:20} | {message}"
else:
formatted = f"{level:8} {module:20} | {message}"
# Add exception info if present
if record.exc_info:
formatted += f"\n{self.formatException(record.exc_info)}"
return formatted
def setup_logging(
level: str = "INFO",
json_mode: bool = False,
quiet_sql: bool = True
) -> None:
"""Configure logging for the application.
Args:
level: Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
json_mode: Use structured JSON logging (for production)
quiet_sql: Suppress verbose SQL query logs
"""
log_level = getattr(logging, level.upper(), logging.INFO)
# Configure root logger
logging.root.setLevel(log_level)
logging.root.handlers.clear()
# Create handler
handler = logging.StreamHandler(sys.stdout)
handler.setLevel(log_level)
# Set formatter
if json_mode:
# Import JSON formatter for production
import json
from datetime import datetime
class JSONFormatter(logging.Formatter):
def format(self, record):
log_entry = {
"timestamp": datetime.utcnow().isoformat() + "Z",
"level": record.levelname,
"logger": record.name,
"message": record.getMessage(),
}
if record.exc_info:
log_entry["exception"] = self.formatException(record.exc_info)
return json.dumps(log_entry)
handler.setFormatter(JSONFormatter())
else:
handler.setFormatter(CleanFormatter(use_colors=True))
logging.root.addHandler(handler)
# Configure third-party loggers
if quiet_sql:
logging.getLogger("sqlalchemy.engine").setLevel(logging.WARNING)
logging.getLogger("sqlalchemy.pool").setLevel(logging.WARNING)
logging.getLogger("sqlmodel").setLevel(logging.WARNING)
logging.getLogger("uvicorn.access").setLevel(logging.WARNING)
logging.getLogger("uvicorn.error").setLevel(logging.ERROR)
logging.getLogger("fastapi").setLevel(logging.INFO)
# Log startup message (but only in non-JSON mode)
if not json_mode:
logger = logging.getLogger(__name__)
logger.info(f"Logging configured at {level} level")
def get_logger(name: str) -> logging.Logger:
"""Get a logger instance.
Args:
name: Logger name (typically __name__ of the module)
Returns:
Logger instance
"""
return logging.getLogger(name)