[Delphi] Rotina básica para captura de exceções

Olá, caros leitores!
Há algumas semanas, eu e o Daniel Serafim, grande companheiro do blog, estávamos compartilhando algumas rotinas para capturar o máximo de informações de uma exceção ocorrida na aplicação, de forma que facilite o rastreamento e a correção do erro. Este compartilhamento resultou no artigo de hoje, no qual apresento a criação de uma rotina básica – porém, útil – para captura de exceções em uma aplicação.

Introdução

Em algumas ocasiões, temos dificuldade em reproduzir os erros que acontecem em nossas aplicações em produção, muitas vezes pela massa de dados, configuração do ambiente ou simplesmente por conta de uma sequência específica de passos que provocam a exceção. Gravar um vídeo com a ocorrência do erro é uma alternativa, no entanto, nem sempre viável. É possível que o usuário não consiga refazer os passos que causou a exceção, ou as informações contidas no próprio vídeo não sejam suficientes para identificar o problema.

Em vista desse contexto, elaborar uma rotina para captura de exceções é uma solução bem coerente. De modo geral, a rotina atua como um listener, monitorando as exceções que ocorrem no sistema e gravando-as em um arquivo de texto ou em uma tabela do banco de dados para posterior análise da equipe de desenvolvimento.

Atualmente, com o Delphi, o desenvolvedor pode optar pela instalação de excelentes ferramentas para essa finalidade, como o EurekaLog ou madExcept, que fornecem uma série de recursos para captura de exceções. Porém, alguns desenvolvedores preferem criar suas próprias rotinas para reduzir ou evitar a instalação de componentes de terceiros. Este artigo é para estes desenvolvedores!

Rotina de captura de exceções

Codificaremos, a seguir, uma rotina simples que armazenará as seguintes informações ao ocorrer uma exceção:

  • Data e hora
  • Mensagem da exceção
  • Classe da exceção
  • Nome do formulário aberto
  • Nome da Unit
  • Nome do controle visual focado
  • Nome do usuário
  • Versão do Windows
  • Imagem do formulário

Com todas essas informações, o rastreamento torna-se bem mais fácil, não? 🙂

Obtendo o nome do usuário

Acho importante iniciarmos pelos métodos que retornam as três últimas informações, já que exigem uma codificação extra. O primeiro deles, que retorna o nome do usuário, é bem simples:

Obtendo a versão do Windows

Para obter a versão do Windows, podemos trabalhar com a classe TOSVersionInfo nativa do Delphi, analisando os resultados do número de build do sistema operacional:

Obtendo a imagem do formulário

A captura da imagem do formulário, por sua vez, também é uma rotina pequena, responsável por associar a imagem dentro de um objeto do tipo TBitmap. No entanto, para que o tamanho do arquivo da imagem fique menor, recomendo a gravação do arquivo em formato JPEG utilizando um objeto da classe TJpegImage, conforme abaixo:

Com as três funções acima codificadas, partiremos para a parte principal. Adicione um componente TApplicationEvents, da paleta Additional, no formulário principal do sistema.

Componente TApplicationEvents

Por fim, codificaremos o evento OnException do componente para “interceptar” a exceção e obter os dados da aplicação naquele momento.

Observe que iremos declarar uma variável chamada DataHora. Usaremos essa variável como nome dos arquivos das imagens, de forma que o desenvolvedor possa descobrir de qual exceção cada imagem está relacionada.

É isso aí! A nossa rotina de captura de exceções está pronta!
Para testá-la, adicione um botão na tela e provoque uma exceção, como uma conversão incorreta:

Em seguida, navegue até a pasta da aplicação e verifique que dois arquivos foram criados: “LogExcecao.txt” e o arquivo de imagem. Para cada exceção subsequente, a aplicação criará uma nova imagem e atualizará o arquivo de log com os dados da nova exceção. Legal, hein?

Uma observação: para que os testes sejam mais efetivos, até mesmo em função da captura correta da imagem da tela, execute a aplicação fora do Delphi, como se estivesse em produção.

Bom, embora toda essa codificação já seja o suficiente, trago ainda algumas sugestões que possam ser úteis:

1) Mostre uma mensagem após gravar a exceção em log

Você deve ter notado que, ao ocorrer uma exceção, os arquivos são criados, mas nenhuma mensagem é exibida ao usuário, já que “interceptamos” a exceção. Esse comportamento, claro, não é o ideal, já que o usuário pode julgar que a aplicação está funcionando normalmente. Portanto, no final do evento OnException, recomendo adicionar uma mensagem para alertar o usuário de que houve um evento inesperado:

2) Envie um e-mail periodicamente contendo o arquivo de log e as imagens

Eu adicionei essa opção em um dos meus projetos. Dado um período, que pode ser diário, semanal, mensal ou sob demanda, a aplicação envia um e-mail para o meu endereço com o log e as imagens compactadas em um único arquivo. Com isso em mãos, consigo identificar os erros e aplicar as correções com mais agilidade, às vezes de forma até antecipada.

Para codificar essa funcionalidade, pode-se criar uma rotina de envio de e-mails com o TIdSMTP e dispará-la em uma Thread paralela com o TTask para não “travar” o usuário.

3) Grave as exceções em uma tabela do banco de dados

Uma boa alternativa é gravar as exceções em uma tabela do banco de dados ao invés de um arquivo de log. Neste caso, o desenvolvedor poderá desenhar uma tela para visualização das exceções em uma Grid, semelhante ao que o Daniel Serafim desenvolveu em seu projeto (boa, Daniel!):

Exemplo de visualização de exceções registradas no banco de dados

4) Crie uma classe para atuar como wrapper da exceção

Os códigos desse artigo são apenas demonstrações. Caso você realmente considere agregá-los à sua aplicação, crie uma classe específica para escrever os dados no arquivo de log, capturar as imagens e, opcionalmente, enviar e-mails. Lembre-se do princípio da responsabilidade única!

Surgiu alguma dúvida nos códigos? Baixe o projeto de exemplo deste artigo desenvolvido em Delphi Tokyo no link abaixo e estude as codificações:

Download do projeto de exemplo de captura de exceções

 

Grande abraço, pessoal!


 

André Celestino