11 abril 2008

Cazando errores con EurekaLog

Cuando uno encuentra herramientas como esta, a veces le dan ganas de darse cabezazos contra la pared después de haber sufrido los castigos del debugger de Delphi. EurekaLog es un experto que se acopla perfectamente a cualquier versión de Delphi y que permite capturar excepciones, access violation y pérdidas de memoria todo ello en una sóla herramienta (y además sin modificar para nada las opciones de Delphi o de nuestro proyecto).

Funciona incluso con las últimas versiones de Delphi (Delphi for Win32 y RadStudio 2007). Para versiones muy antiguas de Delphi, como por ejemplo Delphi 5 a veces requiere tener instalado algún Update que otro.

Aunque sea un programa comercial podemos bajar la demo de su página oficial:

http://www.eurekalog.com/downloads.php

La última versión a fecha de este artículo es la 6.0.12, teniendo el archivo de instalación un tamaño de 12.4 MB. Antes de ejecutar la instalación es conveniente tener todos los Delphi cerrados. La instalación no tiene muchas complicaciones:

Vamos pulsado el botón Next hasta que finalice la instalación. En uno de estos pasos reconoce las distintas versiones de Delphi que tenemos instaladas, permitiendo seleccionar las que nos interesen:

Cuando termina la instalación nos da la posibilidad de visualizar un videotutorial online sobre cómo funciona EurekaLog, lo cual facilita mucho las cosas.

Ahora arrancamos Delphi y abrimos un proyecto cualquiera para probarlo. Para activar EurekaLog en nuestro proyecto hay que ejecutar las opciones Proyect -> Eureka Options:

En la ventana que aparece debemos activar la opción Activate EurekaLog. Esto hará que intercepte los errores en tiempo de ejecución sin necesidad de tener activada la opción Integrated Debugging del propio Delphi. Si también queremos interceptar los errores de pérdida de memoria debemos irnos a la sección llamada Avanced Options y seleccionar la opción Catch Memory Leaks:

Después pulsamos el botón Ok y ya tenemos EurekaLog listo para cazar bichos. Vamos a verlo con unos ejemplos.

CAPTURANDO ACCESS VIOLATIONS

Uno de los errores que más solemos cometer es el utilizar objetos que no hemos creado. Por ejemplo, voy a crear un formulario con un botón en el cual si hago clic intentaré añadir un elemento a un objeto StringList sin haberlo creado anteriormente:

procedure TForm1.Button1Click( Sender: TObject );
var S: TStringList;
begin
S.Add( 'añadiendo elemento' );
end;

Veamos como se comporta EurekaLog en este caso. Al hacer clic sobre el botón nos aparece esta ventana en vez de la típica de Access Violation:

Si pulsamos la opción click here nos mostrará esta otra ventana:

En la primera pestaña (General) nos informa de la excepción que ha provocado la aplicación así como todas las características del equipo donde se está ejecutando. Esta información es muy interesante para averiguar en que máquina esta corriendo nuestra aplicación.

En la segunda pestaña (Call Stack) podemos ver en que línea de código se ha producido el error:

Y ahora viene lo mejor de todo. Si hacemos doble clic sobre la línea azul saltará directamente a Delphi y se irá a la línea de código donde se ha producido el error. Vosotros os preguntareis ahora, ¿y que tiene de especial si el depurador de Delphi ya lo hace? Pues porque EurekaLog caza errores donde Delphi no llega. ¿Cuántos access violations os ha llevado Delphi al depurador en ensamblador? ¿Cuántas veces os ha explotado Delphi sin tener ni idea donde se ha producido el error? A mi por lo menos se me ha quedado el puntero del depurador en Application.Run y se ha quedado como Dios.

Con EurekaLog he llegado a cazar el 95% de errores de Delphi donde el debugger no llegaba. Además me sitúa el cursor exactamente en la línea de código donde se ha producido el error.

En la tercera pestaña (Modules) podemos ver nuestro ejecutable y cuantas librerías DLL hay cargadas en memoria:

En la cuarta pestaña (Processes) se ve los ejecutables que estaban corriendo en el sistema en el momento del error:

En la quinta pestaña (Assembler) nos muestra el punto de ejecución en ensamblador donde se ha quedado el procesador:

Y en la última pestaña (CPU) tenemos un volcado de los registros del procesador, la pila y la memoria del segmento actual:

Si pulsamos el botón Ok, la aplicación seguirá su curso y devolverá el control a Delphi.

AVERIGUANDO DONDE SE PRODUCEN LAS PERDIDAS DE MEMORIA

Este es otro de los agujeros negros que sufrimos los programadores de Delphi, las pérdidas de memoria (Memory Leaks). Yo hasta ahora había utilizado la unidad MemCheck.pas para cazar los errores, pero es muy incómoda su instalación y seguimiento. En este caso EurekaLog también es insuperable, cazando las perdidas de memoria al vuelo. Veamos otro ejemplo.

Voy a crear un StringList y a salirme del programa sin hacer Free del objeto:

procedure TForm1.Button1Click( Sender: TObject );
var S: TStringList;
begin
S := TStringList.Create;
S.Add( 'añadiendo elemento' );
end;

Al finalizar el programa saltará la siguiente ventana de EurekaLog:

Cuando pulsemos sobre la opción click here y nos vayamos a la pestaña Call Stack nos dirá exactamente que línea ha creado algo en memoria y no lo ha liberado:

Haciendo doble clic sobre la misma saltará a la línea de código responsable del problema:

S := TStringList.Create;

Esto deja a Delphi 2007 en ridículo en cuestión de cazar pérdidas de memoria, ya que este último IDE de CodeGear no dice ni en que unidad ni en que línea se ha producido la perdida de memoria, sólo nos dice que objetos han quedado sin liberar. Yo no se vosotros, pero para mi, eso y nada es lo mismo.

ENVIANDO LOS ERRORES POR CORREO ELECTRONICO

¿Cuántas veces os ha ocurrido que a un cliente vuestro le salta un Access Violation y a vosotros os funciona bien con la misma base de datos? Eso a mi me ha pasado un día si y otro también. Pues en ese caso enviamos el ejecutable de nuestra aplicación a nuestros clientes con EurekaLog activado y compilado, y en momento que se produzca la explosión a ellos también les aparecerá la misma ventana de EurekaLog con el error, con lo cual podrán decirnos en que unidad y línea de código se ha producido el error.

Pero no sólo eso, si no queremos complicarnos la vida, EurekaLog permite enviar por correo electrónico toda la información perteneciente al error que se ha producido. Para ello volvemos a la ventana de opciones de EurekaLog y nos situamos en la primera sección (Email & WebSend):

Seleccionamos la opción SMTP Client dentro del campo Send Mode y rellenamos el resto de campos con la cuenta de correo que vamos a utilizar para enviar los errores. Esa cuenta se puede utilizar para enviarse errores así misma, gastando pocos recursos de nuestro servidor SMTP.

Cuando a nuestro cliente le ocurra un error con nuestra aplicación le aparecerá esta ventana:

Cuando pulse el botón Send Error Report comenzará a enviar el error por correo electrónico con los datos de la cuenta que le hemos dicho (si os fijáis en la imagen se puede enviar a otro correo opcional):

Junto con el mensaje de correo llevará adjunto un archivo comprimido con zip llamado BugReport.zip. Este a su vez tiene dos archivos dentro:

Screenshot.png que contiene una imagen capturada de todo el escritorio de Windows cuando se produjo el error.

ProbandoEureka.elf (Igual que el nombre de nuestro ejecutable pero con extensión .elf) que al doble clic sobre el mismo y nos abrirá un visor con el error:

Es decir, nos manda la pantalla capturada (para saber que estaba haciendo el usuario antes de saltar el error) y el archivo de depuración con la línea de código que provocó el error.

Aunque EurekaLog sea una herramienta comercial (cuesta 99 €) sin duda merece la pena comprarla si eso va a mejorar la productividad y ahorrarnos muchos dolores de cabeza. En resumen, otra herramienta imprescindible para Delphi.

Pruebas realizadas en Delphi 7.

Publicidad