Ir al contenido principal

Trazabilidad y control de errores - 2ª parte: trazabilidad estructurada

En esta nueva entrega de la publicación Trazabilidad y control de errores vamos a centrarnos en el que es quizá el más interesante aspecto de la trazabilidad. Structured Logging es la técnica que nos permitirá realizar análisis automatizados de nuestra trazabilidad, mediante software de detección de eventos.

En la primera parte de la publicación incorporamos a nuestra plataforma de test Open Source la librería NLog, y configuramos la generación de dos ficheros de texto plano para trazas, uno para dejar la información de los posibles errores no controlados, y otro para los avisos, o warnings. Además asociamos la consola para crear trazas de información para la depuración.

Hoy vamos a configurar la creación de un tercer fichero, que almacenará igualmente información de los errores, pero en este caso guardará la información no en texto plano, sino estructurada, con notación JSON que después podría ser procesada.

Para este fin NLOG nos proporciona el JSON Layout. Vamos a ponernos manos a la obra. Lo primero que haremos será ir al web.config, donde encontramos nuestra configuración para NLOG, y ahí crearemos un nuevo target:

      <target name="jsonlogfileerror" xsi:type="File" fileName="logs/jsonerror_${shortdate}.txt">  
        <layout type='JsonLayout'>
          <attribute name='type' layout='${exception:format=Type}' />
          <attribute name='message' layout='${exception:format=Message}'/>
          <attribute name='data' layout='${exception:Data}'/>
        </layout>
      </target>
      
    </targets>


Definimos los atributos, correspondientes a las informaciones que queremos guardar. recuerden recurrir a la documentación de NLog para verificar todas las opciones posibles, que son muchas. En nuestro caso en nuestro fichero JSON reflejaremos el tipo de excepción y el mensaje, y un valor interesante, la propiedad Data.

Data es una propiedad de las excepciones que ofrece gran versatilidad. Se trata de un diccionario cuyos valores pueden ser informados por el programador en el momento en que se genera la excepción, y podemos usarla, entre otras cosas, para guardar el contexto del error. 

Vamos a seguir con el ejemplo del Test1: multithreading vs singlethreading  que ya usamos en la primera entrega de este post. Aquí tenemos el testcase MultithreadingCaseWithErrors donde estamos generando un par de errores no controlados durante la ejecución del proceso. Vamos a ver cómo en el control de errores informamos la propiedad Data de la excepción:

        private static void CalcFiboWithErrors(int index)
        {
            try
            {
                _logger.Info("Inicia cálculo serie Fibo - Index " + index.ToString());

                if (index == 1)
                {
                    //error 1: 
                    object o2 = null; int i2 = (int)o2;
                }
                else if (index == 2)
                {
                    //error 2: 
                    int a = 0; int b = 1 / a;
                }

                fibo_functions.CalcFibo(200);

                _lst_process_control[index].Estado = objects.process_control.enumEstadoProceso.Finalizado;

                _logger.Info("Finaliza cálculo serie Fibo - Index " + index.ToString());
            }
            catch (Exception ex)
            {
                ex.Data.Add("test", "test1_multithreading_vs_singlethreading");
                ex.Data.Add("case", "CalcFiboWithErrors");
                ex.Data.Add("index", index.ToString());

                _logger.Error(ex, " CalcFiboWithErrors - Index " + index.ToString());

                _lst_process_control[index].Estado = objects.process_control.enumEstadoProceso.Erroneo;
            }
        }

Tan solo configurando un target para el JSON Layout en el web.config, sin tocar nada más, obtenemos un segundo fichero de errores cuyo contenido paso a mostrarles:



Como podrán Uds. deducir, la ventaja de este fichero respecto del anterior en formato de texto plano es la estructura, que nos facilitará el tratamiento automatizado de las excepciones. Para ello disponemos de muy distintas opciones. Una es usar el Database Target, y directamente guardar las trazas en una base de datos dedicada sobre la que poder implementar sus propias consultas.

NLOG también admite protocolos de red, por lo que puede Ud. personalizar su propio servidor HTTP por ejemplo, para implementar un tratamiento personalizado.

Por otro lado buscando en la web también encontrará multitud de herramientas ya desarrolladas, de mayor o menos complejidad.

A modo de ejemplo les presento la solución Seq, de instalación y uso muy agradable. Pasos a seguir:

1. Instalar MSI aquí.
2. Instalar Nuget
Install-Package NLog.Targets.Seq
3. Configurar en web.config:

  <!--NLOG Configuration-->
  <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" autoReload="true">

    <extensions>
      <add assembly="NLog.Targets.Seq"/>
    </extensions>
    
    <variable name="ExceptionLayout" value="${machinename} | ${longdate} | ${level:upperCase=true} | ${message} | ${exception:format=ToString,Properties,Data}  " />

    <targets async="true">
      
      <default-target-parameters xsi:type="File" keepFileOpen="false"/>

      <target name="logconsole" xsi:type="Console" />

      <target name="logfilewarning" xsi:type="File" fileName="logs/warning_${shortdate}.txt" />
      <target name="logfileerror" xsi:type="File" fileName="logs/error_${shortdate}.txt" layout="${ExceptionLayout}" />
      
      <target name="jsonlogfileerror" xsi:type="File" fileName="logs/jsonerror_${shortdate}.txt">  
        <layout type='JsonLayout'>
          <attribute name='type' layout='${exception:format=Type}' />
          <attribute name='message' layout='${exception:format=Message}'/>
          <attribute name='data' layout='${exception:Data}'/>
        </layout>
      </target>

      <target name="seq" xsi:type="Seq" serverUrl="http://localhost:5341" apiKey="">
        <property name="type" value="${exception:format=Type}" />
        <property name="message" value="${exception:format=Message}" />
      </target>
      
    </targets>

    <rules>
      <logger name="*" minlevel="Debug" maxlevel="Warn" writeTo="logconsole" />
      
      <logger name="*" minlevel="Warn" maxlevel="Warn" writeTo="logfilewarning"  />
      <logger name="*" minlevel="Error" writeTo="logfileerror" />
      <logger name="*" minlevel="Error" writeTo="jsonlogfileerror" />
      <logger name="*" minlevel="Error" writeTo="seq" />
      
    </rules>
    
  </nlog>

4. Navegar a http://localhost:5341/ para obtener este resultado:


Bonito ¿verdad?

Llegados a este punto amigos, me pregunto si no sería ésta la ocasión perfecta para montar con C# un servidor UDP, o una WebApi... y construir nuestro servicio personalizado de captación de excepciones.

Déjenme saber si desean una tercera entrega sobre esta fascinante disciplina de la trazabilidad. De pronto en próximas publicaciones les presentaré un nuevo proyecto Open Source ya disponible en HitGub. Se trata de una interpretación personal del patrón Command and Query Responsibility Segregation (o CQRS), útil cuando topamos con sistemas de alta exigencia de lecturas y de escrituras. Les aseguro que es un proyecto apasionante en el que pondremos al límite los recursos del sistema.








Comentarios

Entradas populares de este blog

Test 3: ¿Son eficientes los ORMs?

Bienvenidos amigos. Me complace anunciar que por fin estrenamos la categoría " SQL Server Tips ", y lo hacemos por todo lo alto, entrando de lleno en un aspecto altamente polémico entre programadores. ¿Es eficiente un ORM en los accesos a datos? Ya conocen la filosofía de nuestros Tests, no vamos a teorizar demasiado, pero sí una pequeña base va a ser necesaria para conseguir una buena respuesta a nuestra pregunta. He leído un interesante  artículo de nuestros súper amigos de Deloitte ( cuando usar ORM ) argumentando que el uso o no de un ORM hay que decidirlo en relación a la complejidad de nuestro modelo de datos, y al rendimiento que requeriremos en nuestras soluciones, pero, ¿cuándo no deseamos el mejor rendimiento para nuestro software? Lo cierto es que, como ya hemos visto, el ORM facilita mucho las cosas, aporta claridad al código, de eso no cabe duda, pero, ¿es eficiente? He ahí la cuestión. Sobre este asunto vamos a poner a funcionar nuestros apreciados Test. C...

Proyecto GEOW. Implementando el patrón CQRS

Me siento muy feliz de poder ofrecerles esta nueva publicación y este nuevo proyecto Open Source. Naturalmente seguiremos evolucionando el proyecto de tests de c#, pero he querido hacer este paréntesis para hablarles del patrón CQRS , o lo que es lo mismo,  Command Query Responsibility Segregation . Una primera versión plenamente operativa del proyecto GEOW está ya disponible para todos Uds. en  GitHub . Les recomiendo encarecidamente que la clonen y jueguen con ella. No solo tiene un elevado potencial pedagógico , además sus propiedades visuales son altamente hipnóticas, por lo que les pido mucha precaución a la hora de ponerlo a funcionar :)  Por esta misma razón me he decidido a crear un canal en YouTube para irles mostrando videitos con los resultados de los dos proyectos que nos traemos entre manos. Espero lo disfruten. Son muchos los detalles técnicos que se desprenden en esta publicación, además de la propia implementación del patrón...