Yo traceo, tu traceas, el tracea…

fingerprintTodos en mayor o menor medida nos vemos en la necesidad de poder, en un momento dado, conocer como se está comportando nuestra aplicación mediante el uso de trazas. Como me a tocado trabajar en la arquitectura de un buen puñado de aplicaciones, me propongo recopilar aquí unas cuantas reflexiones y buenas prácticas sobre este tema. No se trata de sentar cátedra, en informática rara vez hay una única aproximación buena, sino comentar las tácticas que suelo emplear a la hora de diseñar el traceo y aquellos aspectos clave a los que se debe mirar. Cada aplicación tiene diferentes necesidades en lo que a traceo se refiere. Además me encantaría que se generase cierto debate alrededor de este tema.


Disponemos de un motón de soluciones para llevar a cabo la implementación de esta característica en nuestras aplicaciones: System.Diagnostics, Log4net, el Application Block de Microsoft para este cometido…


El principal objetivo de las trazas es poder conocer a posteriori el comportamiento de nuestra aplicación y los diferentes estados por los que ha pasado. Las trazas son las únicas huellas que la ejecución de nuestra aplicación deja en ocasiones. Generalmente necesitaremos estudiar esta información cuando surjan problemas. No considero aquí las trazas como auditoria de permisos, de uso de la aplicación, de visitas, de uso de características, solo hablo de trazas de diagnostico, que son las que aparecen en una mayor número de aplicaciones.


El traceo debe ser suficientemente eficiente. Es importante que las trazas no afecten demasiado al comportamiento de nuestro aplicación en lo que al rendimiento se refiere. Indudablemente siempre se activemos las trazas de nuestra aplicación tendremos una penalización en el rendimiento de la aplicación, aunque esta penalización es inevitable, debe ser la menor posible. Otro aspecto vital es que cuando las trazas se encuentren desactivadas tenga un impacto cercano a cero sobre el rendimiento de la aplicación. Apoyar nuestro sistema de trazas en una librería ampliamente utilizada o en las posibilidades de traceo que casi todos los frameworks de desarrollo moderno proporcionan suele ser una garantía para lograr un rendimiento aceptable.


El traceo debe ser thread safe. Una tentación habitual es utilizar un hilo adicional para realizar las actividades de traceo de nuestra aplicación. En teoria esto permite que nuestra aplicación sufra un menor impacto en su rendimiento por las trazas. Esta es una aproximación errónea por varios motivos: Primero, porque los cambios de contexto que se producirán al utilizar múltiples hilos con numerosas trazas invalidarán cualquier ventaja de rendimiento y segundo, porque una situación en la que nos resultan vitales las trazas es cuando no encontramos con problemas relacionados con el comportamiento con múltiples hilos de la aplicación (interbloqueos, condiciones de carrera, etc…) y lógicamente en esta situación lo último que necesitamos es que las trazas introduzcan más ruido en el problema. Debemos poder confiar en que las trazas se escriben de manera síncrona a la ejecución del código que las rodea y con el que están relacionadas.


El traceo debe ser simple. Las librerías y clases de traceo nos permiten utilizar una gran cantidad de parámetros de configuración que permiten controlar en gran detalle en nivel de locuacidad de las trazas, su destino, para que módulos están o no activadas y un largo etc… Pero a menudo en nuestras aplicaciones debemos enmascarar y simplificar estos aspectos para hacer utilizable y sencillo nuestro sistema de trazas, tanto para los desarrolladores que lo utilizan como para los administradores de la aplicación. Aunque poder controlar el nivel de locuacidad de las trazas es una gran idea, en la gran mayoría de las ocasiones es suficiente utilizar solo tres niveles: error, advertencia e información. Una idea que suele parecer atractiva es dejar en manos de los operadores de la aplicación la configuración del tipo de salida y de que módulos deben proporcionar traceo, pero en la práctica suele ser mucho más útil, en mi experiencia, que simplemente sea necesario seleccionar una salida y activar el nivel de trazas adecuado. La idea es mantener simple el sistema de trazas pues cuando nuestras aplicaciones tienen problemas, al otro lado de la línea de soporte, no siempre hay un avezado administrador de sistemas que conoce a fondo nuestra aplicación. Es más simple simplemente pedir que se activen todas las trazas, se nos envié el resultado y realizar una análisis detallado y tranquilo de las mismas a base de filtrar lo que no es necesario. Mejor tener información suficiente y filtrarla a posteriori que no contar con la información suficiente para hacer una análisis detallado y tener que pedir de nuevo al administrador de la aplicación que cambie tal o cual parámetro.


Las trazas deben ser facilmente filtrables. Por lo anteriormente expuesto se hace evidente que las trazas deben ser fácilmente filtrables. Para ello todas las trazas que nuestra aplicación emita deben tener la misma estructura, presentar los mismos campos y en esencia ser homogéneas entre sí. Es muy complejo filtrar trazas que proporcionan información heterogénea.


El traceo debe tener como salida las fuentes habituales. A menudo cuando se implementa un sistema de traceo se olvidan ciertas salida que los usuarios de ciertas tecnologías esperan que estén presentes. Por ejemplo, todo administrador de sistemas espera que toda traza de nivel crítico se vea reflejada en el visor de eventos, o los programadores y administradores de aplicaciones Asp.Net esperan poder ver las trazas usando trace.axd, y todos los desarrolladores del mundo esperan poder ver las trazas usando DebugView o la ventana de salida de Visual Studio. Por lo tanto, cuando diseñamos el sistema de traceo de nuestra aplicación debemos asegurarnos de que concemos y utlizamos las salidas esperadas por los desarrolladores y administradores de nuestra aplicación.


DebugView


Las trazas deben mostrar información suficiente y no excesiva. Tan importante es que la información volcada por las trazas sean suficiente como que no sea excesiva. De todos modos ante la duda, se debe tracear toda la información que pueda resultar relevante, pues siempre podremos filtrar a posteriori: Identificador del hilo que crea la traza, hora de la traza, módulo, función, pila de llamadas, mensaje de la traza, usuario, etc… Es necesario para cada dominio de aplicación hacer un esfuerzo para seleccionar de manera explicita aquella información que por su relevancia es susceptible de ser traceado.


Para terminar, fuertemente relacionado con el tema del traceo se encuentra el manejo de excepciones, quiza os interese hechar un vistazo a unos post que escribí hace algún tiempo sobre antipatrones en el manejo de excepciones (I, II y III), donde recojo algunos errores habituales al logear excepciones.


Espero sugerencias y comentarios sobre como abordáis el traceo en vuestras aplicaciones.

9 comentarios sobre “Yo traceo, tu traceas, el tracea…”

  1. Que tema Rodrigo!
    Un problema que encuentro muy importante a la hora de logear con un hilo separado es que es muy probable que cuando el sistema de logeo consulte un estado cualquiera este ya haya cambiado y, por lo tanto, muestre información incorrecta.
    Otra cosa, muchas veces es necesario logear las sentencias sql cuando se habilita cierto nivel de logeo. Por favor, no me peguen por esto! Es muy util.
    Saludos.

  2. Lucas; “loguear sentencias SQL” ??? 😐 10000 kms de distancia no son suficientes, ya mando un sicario para que te corte los dedos !!! jejeje

    en realidad se me ocurren varios escenarios donde puede ser necesario este tipo de accion, pero tambien pienso en que tal vez no sea necesario ser tan drásticos 😀 (si trabajas 100% con SPs …. para que loguearias sentencias SQLs … )

    Saludos

  3. Espinete, hay cientos de herramientas para depuración, en general las de Systeminternals son imprescindibles.

    Reflecto también es muy util y saberse manejar con las Debuging Tools for Windows también es muy util.

    Si quieres profundizar en este tema te recomiendo que leas Production Debugging for .NET Framework Applications (http://msdn2.microsoft.com/en-us/library/ms954594.aspx).

    Un libro muy recomendable es Debugging Applications for Microsoft .NET and Microsoft Windows(http://www.amazon.com/gp/product/0735615365?ie=UTF8&tag=lamaselladlab-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0735615365).

    Un saludo!!!

  4. Una cuestión habitual es si logear o no las sentencias SQL. Hay pros y contras como en todo:

    Si logeamos las sentencias SQL junto con otras trazas tendremos la información completa en su contexto. Pero el volumen de trazas puede ser enorme.

    Siempre tenemos la opción de utilizar las herramientas que proporcionan las bases de datos para tracear. Con la pega de que tendremos nuestras trazas dispersas, claro.

    Esto ocurre siempre que decidimos dejar nuestro traceo en manos de las herramientas que nos proporcionan las tecnologías que usamos.

  5. Si si, eso mismo, cada vez que lo propongo me como un latigazo de alguna parte pero trabajando con esto por un buen tiempo he valorado mucho tener el SQL en la linea anterior al mensaje de excepción. Muchas veces ha pasado que teniendo un producto bien testeado un muchos clientes, despues de alg’un tiempo (un año) nos comentan que le dió tal o cual error y los sql te salvan la vida.
    ElBruno tiene razón, si tengo 100% SPs para que quiero los sql (o como los obtengo) pero no todos los sistemas tienen 100% SPs, muchos tiran commands y otros usan ORMs propios o de terceros que podemos no saber bien que hacen.
    El tener las trazas dispersas es lo más dificil que puede haber, esa es mi experienca.
    Y por último, como dije, loguear el sql en ciertas circunstancias y no siempre y, más allá de las discuciones teóricas al respecto, creo que el pragmatismo siempre es bueno y la pureza total casi nunca lo es.
    Saludos.

  6. Hola Rodrigo,
    Muy bueno como siempre, yo utilizo logging application block de EntLib, tiene muchísimas características interesantes, incluído el logeo de WCF, y si usás exception handling application block o data access application block es la opción más lógica ya que toto se encuentra integrado.

    Saludos.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *