O Módulo logging
O pacote logging da biblioteca padrão (stdlib) roteia registros de log de loggers através de handlers para saídas (console, arquivos, syslog). Configure níveis, formatadores e hierarquia de loggers uma vez na inicialização - bibliotecas registram em loggers nomeados sem configurar handlers.
Receita
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s: %(message)s")
log = logging.getLogger(__name__)
log.info("iniciando servidor")
log.warning("disco %s%% cheio", 92)Quando usar isso:
- Serviços de produção precisam de diagnósticos com níveis, filtráveis
- Bibliotecas emitem logs sem escolher o destino da saída
- Múltiplos handlers (stderr + arquivo rotativo) por logger
- Campos estruturados mapeados posteriormente a partir de atributos de LogRecord
- Substituindo depuração por
printpor trilhas operáveis
Exemplo de Trabalho
import logging
from logging.handlers import RotatingFileHandler
def configure_logging() -> None:
root = logging.getLogger()
root.setLevel(logging.INFO)
fmt = logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s")
console = logging.StreamHandler()
console.setFormatter(fmt)
root.addHandler(console)
file_handler = RotatingFileHandler("app.log", maxBytes=1_000_000, backupCount=3)
file_handler.setFormatter(fmt)
root.addHandler(file_handler)
configure_logging()
log = logging.getLogger("billing")
log.info("cobrança processada id=%s", "inv-1")
try:
1 / 0
except ZeroDivisionError:
log.exception("falha matemática inesperada")O que isso demonstra:
- Alternativa ao
basicConfig: anexo explícito de handler na raiz - Loggers nomeados herdam o nível e os handlers da raiz
- Formatação
%preguiçosa - argumentos adiados se o nível for filtrado log.exceptioninclui o traceback quando chamado dentro de umexcept
Mergulho Profundo
Como Funciona
- Loggers formam uma hierarquia por nomes pontilhados (
app.api,app.db) - Registros fluem: logger -> filtros -> handlers -> formatadores -> IO
- Níveis: DEBUG < INFO < WARNING < ERROR < CRITICAL
propagatecontrola o borbulhamento para loggers pais- Bibliotecas chamam apenas
getLogger(__name__)- sem configuração de handler
Componentes
| Peça | Papel |
|---|---|
| Logger | Ponto de entrada log.info(...) |
| Handler | Destino de saída |
| Formatter | String de layout |
| Filter | Gating extra |
Armadilhas
basicConfigno-op se a raiz já estiver configurada - segunda chamada ignorada. Correção: configure uma vez nomainou usedictConfig.- Logs duplicados de
propagate- filho e raiz ambos têm handlers. Correção: definalogger.propagate = Falseou use handlers apenas na raiz. - f-strings em chamadas de log - avaliação antecipada mesmo quando filtrada. Correção:
log.info("x=%s", x). printem bibliotecas - ignora níveis e agregação. Correção: use apenaslogging.- DEBUG em produção sempre ativo - volume e vazamento de segredos. Correção: nível controlado por env, amostrar debug.
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| structlog | Pipelines JSON, variáveis de contexto | Scripts pequenos |
| OpenTelemetry logs | Traces/métricas/logs unificados | Nenhum coletor ainda |
| Exploração de REPL | Serviços |
FAQs
Onde configuro o logging?
Ponto de entrada da aplicação (main, lifespan do FastAPI, dicionário LOGGING do Django) - nunca em módulos de biblioteca.
Qual nome de logger devo usar?
logging.getLogger(__name__) para que os nomes espelhem a estrutura do pacote.
Como registrar exceções?
log.exception("msg") dentro de um bloco except, ou log.error("msg", exc_info=True).
dictConfig vs basicConfig?
dictConfig escala para múltiplos handlers/formatadores e substituições de teste.
Como silenciar bibliotecas barulhentas?
logging.getLogger("urllib3").setLevel(logging.WARNING).
Loggers são thread-safe?
Sim - o módulo logging serializa a emissão do handler; ainda assim, evite contexto mutável sem locks.
Como funcionam os arquivos rotativos?
RotatingFileHandler por tamanho; TimedRotatingFileHandler por intervalo - combine com envio de logs.
Devo usar LoggerAdapter?
Para contexto estático (prefixo de ID de requisição) antes de bibliotecas de logging estruturado.
E os níveis de log em testes?
O fixture caplog no pytest captura registros por nome de logger e nível.
Como isso se compara ao logging do Django?
Django usa dictConfig internamente - mesmos conceitos, padrões fornecidos pelo framework.
Relacionados
- Logging Estruturado e Contextual - JSON e IDs de correlação
- Avisos e Depreciações - separado do logging
- Básico de Exceções - registrar e levantar
- Melhores Práticas de Erros e Logging - políticas
Versões do Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+ e uv 0.6+.