- apps/api: FastAPI backend with Dockerfile - apps/web: Next.js frontend with Dockerfile - apps/sensor: Signal collection agent - packages: shared packages Co-Authored-By: Claude <noreply@anthropic.com>
79 lines
2.2 KiB
Python
79 lines
2.2 KiB
Python
"""
|
|
AWOOOI Structured Logging
|
|
=========================
|
|
structlog configuration for production-grade logging
|
|
|
|
Features:
|
|
- JSON output in production
|
|
- Pretty console output in development
|
|
- Request ID propagation
|
|
- Async-safe
|
|
"""
|
|
|
|
import logging
|
|
import sys
|
|
from typing import Any
|
|
|
|
import structlog
|
|
from structlog.types import Processor
|
|
|
|
from src.core.config import settings
|
|
|
|
|
|
def setup_logging() -> None:
|
|
"""Configure structlog for the application"""
|
|
|
|
# Shared processors for all environments
|
|
shared_processors: list[Processor] = [
|
|
structlog.contextvars.merge_contextvars,
|
|
structlog.processors.add_log_level,
|
|
structlog.processors.StackInfoRenderer(),
|
|
structlog.processors.TimeStamper(fmt="iso"),
|
|
structlog.processors.CallsiteParameterAdder(
|
|
parameters=[
|
|
structlog.processors.CallsiteParameter.PATHNAME,
|
|
structlog.processors.CallsiteParameter.LINENO,
|
|
]
|
|
),
|
|
]
|
|
|
|
if settings.ENVIRONMENT == "dev":
|
|
# Development: Pretty console output
|
|
processors: list[Processor] = [
|
|
*shared_processors,
|
|
structlog.processors.ExceptionPrettyPrinter(),
|
|
structlog.dev.ConsoleRenderer(colors=True),
|
|
]
|
|
else:
|
|
# Production: JSON output for log aggregation
|
|
processors = [
|
|
*shared_processors,
|
|
structlog.processors.format_exc_info,
|
|
structlog.processors.JSONRenderer(),
|
|
]
|
|
|
|
structlog.configure(
|
|
processors=processors,
|
|
wrapper_class=structlog.make_filtering_bound_logger(
|
|
logging.getLevelName(settings.LOG_LEVEL)
|
|
),
|
|
context_class=dict,
|
|
logger_factory=structlog.PrintLoggerFactory(),
|
|
cache_logger_on_first_use=True,
|
|
)
|
|
|
|
# Configure standard library logging to use structlog
|
|
logging.basicConfig(
|
|
format="%(message)s",
|
|
stream=sys.stdout,
|
|
level=logging.getLevelName(settings.LOG_LEVEL),
|
|
)
|
|
|
|
|
|
def get_logger(name: str | None = None, **initial_context: Any) -> structlog.BoundLogger:
|
|
"""Get a configured logger instance"""
|
|
logger = structlog.get_logger(name)
|
|
if initial_context:
|
|
logger = logger.bind(**initial_context)
|
|
return logger
|