Foto de uma mesa de escritório com dois monitores Dell. O monitor esquerdo mostra o VS Code com código Python para tratamento de erros (error_handling.py). O monitor direito exibe um painel de monitoramento de erros com gráficos, principais exceções e feeds de logs em tempo real. Um teclado mecânico e uma caneca ASL Engineering estão na mesa.
Ilustração técnica apresentando uma estação de desenvolvimento dual-monitor: o monitor à esquerda exibe blocos de código Python focados em tratamento de exceções e tratamento de erros no VS Code, enquanto o monitor à direita exibe um painel de observabilidade com gráficos de taxa de erro e um feed de logs estruturados em tempo real.

Em ambiente de desenvolvimento, um erro aparece direto no terminal e é resolvido em segundos. Em produção, esse mesmo erro pode acontecer às três da manhã, afetando centenas de usuários, sem ninguém olhando o terminal. A diferença entre uma equipe que resolve esse incidente em minutos e uma que leva horas quase sempre está em como a aplicação trata erros e registra logs. Neste artigo, vamos além do básico de try/except e discutimos como estruturar tratamento de erros e logging de forma que realmente ajudem quando o problema acontece de verdade.

1. Pare de capturar exceções genéricas

Um dos anti-padrões mais comuns é o uso de except Exception (ou pior, except: sem especificar nada) para "engolir" qualquer erro. Isso esconde problemas reais, dificulta a depuração e pode mascarar bugs graves como se fossem falhas esperadas. A prática correta é capturar exceções específicas, tratando cada tipo de falha de forma apropriada, e deixar exceções verdadeiramente inesperadas propagarem para serem registradas e investigadas.

# Evite isto
try:
    processar_pagamento(pedido)
except Exception:
    pass  # erro silenciado, ninguém nunca saberá

# Prefira isto
try:
    processar_pagamento(pedido)
except PagamentoRecusadoError as e:
    logger.warning("Pagamento recusado", extra={"pedido_id": pedido.id, "motivo": str(e)})
    notificar_cliente(pedido)
except GatewayIndisponivelError:
    logger.error("Gateway de pagamento indisponível", exc_info=True)
    raise

2. Crie exceções customizadas para seu domínio

Exceções nativas do Python (ValueError, KeyError) descrevem problemas técnicos, mas não comunicam o contexto de negócio. Criar exceções customizadas — como SaldoInsuficienteError ou PedidoJaCanceladoError — torna o código mais legível e permite tratamento diferenciado em cada camada da aplicação, além de facilitar a geração de mensagens de erro mais úteis para o usuário final ou para outros desenvolvedores.

3. Logging estruturado em vez de strings soltas

Registrar logs como texto livre (print() ou logger.info("erro no pedido 123")) dificulta buscas e análises automatizadas. Logging estruturado — registrando dados em formato JSON com campos padronizados como timestamp, nivel, servico e campos customizados relevantes ao contexto — permite que ferramentas de observabilidade filtrem, agreguem e correlacionem eventos com muito mais eficiência do que fazendo busca textual em arquivos de log tradicionais.

Um log que não pode ser filtrado, buscado ou correlacionado automaticamente é, na prática, quase tão inútil quanto não ter log nenhum.

4. Use os níveis de log corretamente

É comum ver aplicações que usam INFO para tudo, incluindo erros críticos, ou que geram tantos logs em DEBUG em produção que informações importantes ficam perdidas no ruído. A disciplina de usar corretamente DEBUG (detalhes técnicos para desenvolvimento), INFO (eventos normais relevantes), WARNING (situações anômalas mas não críticas), ERROR (falhas que precisam de atenção) e CRITICAL (falhas que exigem ação imediata) é o que torna possível configurar alertas eficazes sem gerar fadiga de notificação na equipe.

5. Sempre inclua contexto suficiente para investigar depois

Um log como "erro ao processar pedido" é praticamente inútil sem saber qual pedido, qual usuário, e em que etapa do processo o erro ocorreu. Incluir identificadores relevantes (ID do pedido, ID do usuário, correlation ID da requisição) em cada log permite reconstruir o que aconteceu sem precisar reproduzir o problema manualmente — o que, em produção, muitas vezes é impossível.

6. Centralize e monitore, não confie apenas em arquivos locais

Logs armazenados apenas em arquivos locais no servidor são difíceis de consultar em tempo real e se perdem quando a instância é reiniciada ou substituída (comum em ambientes de contêineres). Ferramentas como Sentry, Datadog ou a stack ELK (Elasticsearch, Logstash, Kibana) centralizam logs de múltiplas instâncias, permitem alertas automáticos e mantêm histórico consultável, essencial para investigar incidentes que aconteceram há dias ou semanas.

7. Não exponha stack traces completos ao usuário final

Embora stack traces sejam essenciais para o time de desenvolvimento, exibi-los diretamente na resposta da API para o usuário final é um risco de segurança, já que pode revelar detalhes internos da estrutura do sistema. A prática correta é registrar o erro completo internamente (com todo o contexto técnico) e retornar ao usuário uma mensagem genérica e segura, junto de um identificador único que a equipe de suporte pode usar para localizar o log correspondente.

Considerações finais

Tratamento de erros e logging bem estruturados não são "extras" de um projeto maduro — são o que diferencia uma aplicação depurável de uma caixa-preta. Investir tempo nisso desde o início reduz drasticamente o tempo médio de resolução de incidentes e melhora a confiabilidade percebida pelos usuários. Se sua aplicação precisa de uma revisão em observabilidade e tratamento de erros, a equipe da ASL Software Engineering pode ajudar a estruturar isso corretamente. Fale com a gente.

continue lendo

Posts relacionados