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. 2ª parte

En el anterior post ( Proyecto GEOW. Implementando el patrón CQRS ) nos adentramos en el funcionamiento del proyecto GEOW que nos va a servir de base para implementar un patrón arquitectónico, CQRS , pensado para dar respuesta a sistemas con alta exigencia de lecturas y escrituras simultáneas. Para ello hemos creado una interfaz gráfica con una serie de figuras geométricas en movimiento. Ahora vamos a ir a la parte de EL DATO. Cada vez que uno de estos cuadrados cambia de posición envía una trama con sus propias características, y sus nuevas coordenadas. Cada uno de los cuadrados realiza un movimiento cada 300 milisegundos, y he llegado a probar con hasta unas 700 figuras. En estos niveles el software empieza a sufrir, pero más la parte gráfica. Aparentemente el sistema de grabación de coordenadas se mantiene en buena forma. Vamos a ver, precisamente, este sistema de grabación: Grabando lotes de coordenadas en BBDD En el objeto PointObj que representa cada una de las figuras, en el

Primeros pasos en Enigma Software Labs

En pocas palabras: vamos a probar y estresar distintas soluciones de software para un mismo problema, en busca de realidades matemáticas. Para ello, lo primero que necesitamos en averiguar el modo de publicar código aquí en Blogger . Para ello voy a usar un sistema súper sencillo y eficiente. Ahí va un ejemplo de código C# private void frmMonitor_Load ( object sender, EventArgs e) { TreeNode _tr = new TreeNode( "SQL Server Tips" ); TreeNode _tr2 = new TreeNode( "C# Code" ); treeCatalogo.Nodes.Add(_tr); treeCatalogo.Nodes.Add(_tr2); //splitContainer.Panel1.Focus(); //lstMonitor.Focus(); } Hilarante ¿verdad?   hilite.me  lo hace posible. Bien, paso 2, fácil y sencillo: vamos a crear una plataforma de testeo para C# en una bonita solución que compartiré en el repositorio GIT, para disfrute de todos. Enigma Software - ZM LABS Como posteriormente me dive