Voltar ao Glossario
Glossario Python

Logging: O que É e Como Funciona | Python Brasil

Domine o modulo logging em Python: niveis, handlers, formatters, configuracao avancada e boas praticas para registrar eventos na sua aplicacao.

O que e Logging?

Logging e o mecanismo de registrar eventos que ocorrem durante a execucao de um programa. O modulo logging da biblioteca padrao do Python oferece um sistema flexivel e configuravel para emitir mensagens de log com diferentes niveis de severidade. Diferente de print(), o logging permite controlar o que e registrado, para onde vai (arquivo, console, servicos externos) e em que formato, sem modificar o codigo da aplicacao.

Em aplicacoes profissionais, logging e essencial para depuracao, monitoramento, auditoria e diagnostico de problemas em producao.

Niveis de Log

O Python define cinco niveis padrao de severidade, em ordem crescente:

import logging

# DEBUG — informacoes detalhadas para diagnostico
logging.debug('Variavel x = 42')

# INFO — confirmacao de que as coisas estao funcionando
logging.info('Servidor iniciado na porta 8000')

# WARNING — algo inesperado ou potencial problema
logging.warning('Disco com 90%% de uso')

# ERROR — erro que impede uma funcionalidade
logging.error('Falha ao conectar ao banco de dados')

# CRITICAL — erro grave que pode encerrar o programa
logging.critical('Memoria insuficiente, encerrando')

Configuracao Basica

import logging

# Configuracao rapida
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
)

# Usando
logging.info('Aplicacao iniciada')
logging.warning('Configuracao nao encontrada, usando padrao')

Loggers, Handlers e Formatters

O sistema de logging do Python e composto por tres componentes principais que trabalham juntos.

import logging

# Criar logger com nome (geralmente __name__)
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

# Formatter — define o formato da mensagem
formatter = logging.Formatter(
    '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S',
)

# Handler para console
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)

# Handler para arquivo
file_handler = logging.FileHandler('app.log', encoding='utf-8')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)

# Adicionar handlers ao logger
logger.addHandler(console_handler)
logger.addHandler(file_handler)

# Usar o logger
logger.debug('Informacao detalhada (so vai para o arquivo)')
logger.info('Informacao geral (console e arquivo)')
logger.error('Erro encontrado (console e arquivo)')

Logging com Rotacao de Arquivos

import logging
from logging.handlers import RotatingFileHandler, TimedRotatingFileHandler

logger = logging.getLogger('minha_app')
logger.setLevel(logging.INFO)

# Rotacao por tamanho
handler_tamanho = RotatingFileHandler(
    'app.log',
    maxBytes=5 * 1024 * 1024,  # 5 MB
    backupCount=5,              # manter 5 arquivos antigos
    encoding='utf-8',
)

# Rotacao por tempo
handler_tempo = TimedRotatingFileHandler(
    'app.log',
    when='midnight',     # rotacionar a meia-noite
    interval=1,          # a cada 1 dia
    backupCount=30,      # manter 30 dias
    encoding='utf-8',
)

formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler_tamanho.setFormatter(formatter)
logger.addHandler(handler_tamanho)

Configuracao com Dicionario

import logging
import logging.config

config = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'padrao': {
            'format': '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        },
        'simples': {
            'format': '%(levelname)s - %(message)s',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': 'INFO',
            'formatter': 'simples',
        },
        'arquivo': {
            'class': 'logging.handlers.RotatingFileHandler',
            'level': 'DEBUG',
            'formatter': 'padrao',
            'filename': 'app.log',
            'maxBytes': 10485760,
            'backupCount': 5,
        },
    },
    'loggers': {
        '': {  # root logger
            'level': 'DEBUG',
            'handlers': ['console', 'arquivo'],
        },
    },
}

logging.config.dictConfig(config)
logger = logging.getLogger(__name__)

Logging Estruturado

import logging
import json

class JsonFormatter(logging.Formatter):
    """Formatter que gera logs em JSON."""

    def format(self, record):
        log_data = {
            'timestamp': self.formatTime(record),
            'level': record.levelname,
            'logger': record.name,
            'message': record.getMessage(),
        }
        if record.exc_info:
            log_data['exception'] = self.formatException(record.exc_info)
        if hasattr(record, 'extra_data'):
            log_data['data'] = record.extra_data
        return json.dumps(log_data, ensure_ascii=False)

# Configurar
logger = logging.getLogger('api')
handler = logging.StreamHandler()
handler.setFormatter(JsonFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)

# Usar
logger.info('Requisicao recebida', extra={'extra_data': {'metodo': 'GET', 'path': '/api/users'}})

Logging em Funcoes e Classes

import logging

logger = logging.getLogger(__name__)

def processar_pedido(pedido_id: int) -> dict:
    """Processa um pedido com logging adequado."""
    logger.info('Iniciando processamento do pedido %d', pedido_id)

    try:
        # logica de processamento
        logger.debug('Validando pedido %d', pedido_id)
        resultado = {'pedido_id': pedido_id, 'status': 'processado'}
        logger.info('Pedido %d processado com sucesso', pedido_id)
        return resultado

    except ValueError as e:
        logger.warning('Dados invalidos no pedido %d: %s', pedido_id, e)
        raise

    except Exception as e:
        logger.exception('Erro inesperado ao processar pedido %d', pedido_id)
        raise

class ServicoEmail:
    def __init__(self):
        self.logger = logging.getLogger(f'{__name__}.{self.__class__.__name__}')

    def enviar(self, destinatario: str, assunto: str):
        self.logger.info('Enviando email para %s: %s', destinatario, assunto)

Erros Comuns

O erro mais frequente e usar print() em vez de logging para depuracao, tornando dificil controlar e filtrar as mensagens. Outro erro e chamar logging.basicConfig() multiplas vezes esperando que reconfigure — ele so funciona na primeira chamada. Tambem e comum incluir dados sensiveis como senhas e tokens em mensagens de log. Usar logging.exception() fora de um bloco except e outro erro, pois ele espera informacoes de excecao ativa. Formatar a string antes de passar para o logger com f-strings (logger.info(f'valor: {x}')) e menos eficiente que usar formatacao preguicosa (logger.info('valor: %s', x)).

Boas Praticas

Use logging.getLogger(__name__) para criar loggers com nomes hierarquicos. Prefira formatacao preguicosa (%s) em vez de f-strings em chamadas de log. Use logger.exception() dentro de blocos except para incluir o traceback. Configure logging no ponto de entrada da aplicacao, nao dentro de bibliotecas. Nunca registre dados sensiveis. Use niveis de log apropriados — DEBUG para desenvolvimento, INFO para operacao normal, WARNING para situacoes inesperadas.

Quando Usar

Logging deve ser usado em toda aplicacao que va para producao. Substitua print() por logging desde o inicio do projeto. Em APIs web, registre cada requisicao com tempo de resposta. Em scripts de processamento, registre progresso e erros. Em bibliotecas, use logging mas deixe a configuracao para a aplicacao consumidora.