""" Logging Configuration for Workers - ServiceManagerWeb Configuración de logging estructurado para workers Celery """ import logging import logging.config import sys from typing import Any, Dict import structlog from app.core.config import get_settings settings = get_settings() def setup_logging(): """Configure structured logging for workers.""" processors = [ structlog.stdlib.filter_by_level, structlog.stdlib.add_logger_name, structlog.stdlib.add_log_level, structlog.stdlib.PositionalArgumentsFormatter(), structlog.processors.TimeStamper(fmt="iso"), structlog.processors.StackInfoRenderer(), structlog.processors.format_exc_info, structlog.processors.UnicodeDecoder(), # Add worker-specific context structlog.processors.CallsiteParameterAdder( parameters=[ structlog.processors.CallsiteParameter.FUNC_NAME, structlog.processors.CallsiteParameter.PATHNAME, structlog.processors.CallsiteParameter.LINENO, ] ), ] if settings.LOG_FORMAT == "json": processors.append(structlog.processors.JSONRenderer()) else: processors.append(structlog.dev.ConsoleRenderer(colors=True)) structlog.configure( processors=processors, wrapper_class=structlog.stdlib.BoundLogger, logger_factory=structlog.stdlib.LoggerFactory(), context_class=dict, cache_logger_on_first_use=True, ) # Configure standard library logging for Celery logging_config = { "version": 1, "disable_existing_loggers": False, "formatters": { "json": { "()": structlog.stdlib.ProcessorFormatter, "processor": structlog.processors.JSONRenderer(), }, "console": { "()": structlog.stdlib.ProcessorFormatter, "processor": structlog.dev.ConsoleRenderer(colors=True), }, }, "handlers": { "console": { "level": settings.LOG_LEVEL, "class": "logging.StreamHandler", "stream": sys.stdout, "formatter": "json" if settings.LOG_FORMAT == "json" else "console", }, }, "loggers": { "": { # root logger "handlers": ["console"], "level": settings.LOG_LEVEL, "propagate": False, }, "celery": { "handlers": ["console"], "level": "INFO", "propagate": False, }, "celery.worker": { "handlers": ["console"], "level": "INFO", "propagate": False, }, "celery.task": { "handlers": ["console"], "level": "INFO", "propagate": False, }, "app": { "handlers": ["console"], "level": settings.LOG_LEVEL, "propagate": False, }, }, } # Add file handler if specified if settings.LOG_FILE: logging_config["handlers"]["file"] = { "level": settings.LOG_LEVEL, "class": "logging.handlers.RotatingFileHandler", "filename": settings.LOG_FILE, "maxBytes": 10 * 1024 * 1024, # 10MB "backupCount": 5, "formatter": "json", } for logger_config in logging_config["loggers"].values(): logger_config["handlers"].append("file") logging.config.dictConfig(logging_config) def get_logger(name: str = None) -> structlog.BoundLogger: """Get a configured structlog logger.""" return structlog.get_logger(name)