|
|
|
|
|
""" |
|
|
Módulo de Configuração de Logging Enterprise |
|
|
|
|
|
Configura um sistema de logging assíncrono e estruturado, utilizando uma fila |
|
|
para evitar bloqueios de I/O. Inclui filtros para adicionar IDs de correlação |
|
|
e sessão a todos os registros de log, facilitando o rastreamento. |
|
|
""" |
|
|
|
|
|
import logging |
|
|
import json |
|
|
import queue |
|
|
from logging.handlers import QueueHandler, QueueListener, RotatingFileHandler |
|
|
|
|
|
|
|
|
from .config import CONFIG |
|
|
from .correlation import correlation_id, session_id |
|
|
|
|
|
|
|
|
class CorrelationFilter(logging.Filter): |
|
|
""" |
|
|
Filtro de log que injeta o ID de correlação e o ID de sessão em cada registro. |
|
|
Obtém os valores dos ContextVars, garantindo que sejam específicos do contexto. |
|
|
""" |
|
|
|
|
|
def filter(self, record: logging.LogRecord) -> bool: |
|
|
record.correlation_id = correlation_id.get() or "no-correlation-id" |
|
|
record.session_id = session_id.get() or "no-session-id" |
|
|
|
|
|
record.module_name = record.name |
|
|
return True |
|
|
|
|
|
|
|
|
class StructuredFormatter(logging.Formatter): |
|
|
""" |
|
|
Formatador de log que converte o registro de log em uma string JSON. |
|
|
Inclui campos estruturados para fácil análise por sistemas de monitoramento. |
|
|
""" |
|
|
|
|
|
def format(self, record: logging.LogRecord) -> str: |
|
|
log_data = { |
|
|
"timestamp": self.formatTime(record, self.datefmt), |
|
|
"level": record.levelname, |
|
|
"message": record.getMessage(), |
|
|
"module": record.module_name, |
|
|
"correlation_id": record.correlation_id, |
|
|
"session_id": record.session_id, |
|
|
"thread_id": record.thread, |
|
|
"process_id": record.process, |
|
|
} |
|
|
|
|
|
if record.exc_info: |
|
|
log_data["exception"] = self.formatException(record.exc_info) |
|
|
|
|
|
return json.dumps(log_data, ensure_ascii=False) |
|
|
|
|
|
|
|
|
def setup_enterprise_logging() -> logging.Logger: |
|
|
""" |
|
|
Configura e inicializa o sistema de logging da aplicação. |
|
|
|
|
|
- Usa uma Queue para fazer o logging de forma assíncrona. |
|
|
- Configura um RotatingFileHandler para salvar logs em arquivos com rotação. |
|
|
- Configura um StreamHandler para exibir logs no console. |
|
|
- Aplica o formatador estruturado (JSON) se habilitado na configuração. |
|
|
- Adiciona o filtro de correlação a todos os logs. |
|
|
|
|
|
Returns: |
|
|
A instância do logger principal da aplicação. |
|
|
""" |
|
|
log_queue = queue.Queue(-1) |
|
|
|
|
|
|
|
|
queue_handler = QueueHandler(log_queue) |
|
|
queue_handler.addFilter(CorrelationFilter()) |
|
|
|
|
|
|
|
|
file_handler = RotatingFileHandler( |
|
|
filename="superezio_enterprise.log", |
|
|
maxBytes=10 * 1024 * 1024, |
|
|
backupCount=5, |
|
|
encoding="utf-8", |
|
|
) |
|
|
|
|
|
|
|
|
console_handler = logging.StreamHandler() |
|
|
|
|
|
|
|
|
if CONFIG.structured_logging: |
|
|
formatter = StructuredFormatter() |
|
|
else: |
|
|
|
|
|
formatter = logging.Formatter( |
|
|
"%(asctime)s - %(levelname)s - [%(module_name)s] - [%(correlation_id)s] - %(message)s" |
|
|
) |
|
|
|
|
|
file_handler.setFormatter(formatter) |
|
|
console_handler.setFormatter(formatter) |
|
|
|
|
|
|
|
|
listener = QueueListener( |
|
|
log_queue, file_handler, console_handler, respect_handler_level=True |
|
|
) |
|
|
listener.start() |
|
|
|
|
|
|
|
|
logger = logging.getLogger("superezio_enterprise") |
|
|
logger.setLevel(getattr(logging, CONFIG.log_level.upper(), logging.INFO)) |
|
|
logger.addHandler(queue_handler) |
|
|
|
|
|
|
|
|
import atexit |
|
|
|
|
|
atexit.register(listener.stop) |
|
|
|
|
|
logger.info( |
|
|
"Logging Enterprise configurado com sucesso. Modo estruturado: %s", |
|
|
CONFIG.structured_logging, |
|
|
) |
|
|
|
|
|
return logger |
|
|
|