Files
awoooi/apps/api/src/core/logging.py
OG T 196d269b92 feat: add all application source code
- 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>
2026-03-22 18:57:44 +08:00

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