Como manejar las trazas de una aplicación .Net Core con Seq y Serilog

Tiempo de lectura: 8 minutos
Imagen ornamental para la entrada "Como manejar las trazas de una aplicación .Net Core con Seq y Serilog"

Esta semana he estado preparando una entrada para CampusMVP hablando de Serilog y lo útil que es instrumentar el código utilizando Serilog como herramienta para este fin.

En esa entrada se plantea la importancia de añadir un buen sistema de trazas que sea fácilmente configurable según las necesidades de cada momento. Precisamente de esa entrada y de un proyecto en el que estuve hace unos meses viene la idea de esta entrada.

¿Cómo poder crear trazas estructuradas y consultarlas en vivo?

Una de las principales necesidades cuando estamos revisando las trazas de una aplicación, es aporten suficiente información y que sean fáciles de consultar. Para esto es vital que definamos unas buenas trazas a lo largo del código y que sus niveles estén bien definidos.

Por poner un caso concreto, si estas trazando una excepción utilizar el nivel ‘Debug’ seguramente no sea la mejor opción.

Por otro lado, el hecho de utilizar trazas estructuradas nos facilita enormemente el poder ver que datos se estaban utilizando en el momento concreto y el poder analizar los datos de una manera más eficiente.

Si has leído mi entrada en CampusMVP, ya sabes que entre los múltiples Sinks que ofrece Serilog hay varios que nos permiten tener información en tiempo real. Abrir y cerrar un fichero para ver los cambios no es una manera muy eficiente de revisar logs en tiempo real…

Aquí es donde entra en juego Seq.

¿Qué es Seq?

Seq es un sistema de ingesta de logs que permite hacer analítica de manera muy sencilla. Simplemente va a exponer un endpoint donde las aplicaciones van a publicar sus trazas. Además, ofrece de serie una interfaz donde vamos a poder ver todas las trazas y hacer consultas sobre ellas:

La imagen muestra la interfaz de Seq con una consulta cualquiera. Las trazas que se muestran son las que cumplen la consulta.

Aunque es una herramienta de pago, tiene un nivel gratuito que se puede utilizar incluso de manera comercial en producción (y esa es la razón de hablar en esta entrada).

Para poder utilizarlo hay que crear un servidor Seq ya sea instalando el software en un equipo o mediante Docker.

Si acostumbras a utilizar Docker en tus desarrollos y tienes dudas sobre donde o cómo hacer las pruebas, no te pierdas sobre cómo ejecutar pruebas de código dentro de contendores Docker.

Utilizando Seq en una aplicación .Net Core con Serilog

Vale, ahora que ya tenemos Seq en nuestro equipo, sea utilizando el instalador o mediante Docker, es hora de configurar Serilog en una aplicación .Net Core para enviar las trazas a Seq.

Importante: En este punto se asume que has leído la entrada sobre como instrumentar el código utilizando Serilog y sabes cómo funciona Serilog. Si tienes dudas sobre como funciona échale un ojo a esa entrada primero.

Para poder enviar las trazas de Serilog a Seq, basta con añadir el Sink de Seq utilizando el paquete NuGet ‘Serilog.Sinks.Seq‘. Una vez hecho eso, simplemente vamos a configurar el Sink para que funcione correctamente. La única configuración obligatoria que necesitamos de momento es el endpoint de ingesta de Seq, que por defecto es ‘http://localhost:5341’

var logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .WriteTo.Seq("http://localhost:5341")
                .CreateLogger();

Si sobre ese logger que hemos creado, escribimos mensajes como por ejemplo:

logger.Verbose("Mensaje Verbose");
logger.Debug("Mensaje Debug");
logger.Information("Mensaje Information");
logger.Warning("Mensaje Warning");
logger.Error("Mensaje Error");
logger.Fatal("Mensaje Fatal");

Vamos a poder ir a la web de administración built-in de Seq y encontrarnos algo como esto:

La imagen muestra el panel de eventos de Seq donde se pueden ver las trazas: Mensaje Fatal, Mensaje Error, Mensaje Warning, Mensaje Information y Mensaje Debug

Como era de esperar ‘Mensaje Verbose’ no aparece ya que el nivel mínimo que debe tener una traza para enviarla a Seq según la configuración que hemos dado al logger es ‘Debug’

Al igual que ocurría con el resto de sinks y enrichers de Serilog, el sink de Seq puede utilizar el fichero de appsettings.json de .Net Core o app.congif/web.config de .Net para configurarse:

{
  "Serilog": {
    "WriteTo": [
      { "Name": "Seq", "Args": { "serverUrl": "http://localhost:5341" } }
    ]
  }
}

¿Cómo gestiona Seq las trazas estructuradas desde Serilog en .Net Core?

Una de las grandes ventajas de utilizar Serilog en .Net Core y enviar las trazas a Seq, es que estas no se limitan a mensajes de texto, sino que pueden contener información mucho más compleja.

Imaginemos que tenemos una clase como pudiera ser:

public class Pedido
{
    public int IdPedido { get; set; }
    public string Dirección { get; set; }
}

Si no utilizásemos trazas estructuradas y quisiésemos registrar en el log la información del pedido que ha producido un error, tendríamos que hacer algo como este:

logger.Error($"Se ha producido un error registrando el pedido. Id: {pedido.IdPedido}, Direccion: {pedido.Dirección}");

Si además añadiésemos un nuevo campo a la clase, tendríamos que revisar todas las trazas donde se usa para añadirlo, o no estaríamos registrando ese nuevo campo.

En cambio, utilizando trazas estructuradas podemos hacer algo como esto:

logger.Error("Se ha producido un error registrando el {@Pedido}.",pedido);

De este modo además de que queda todo mucho más claro y legible, todas las propiedades se van a registrar independientemente de que la clase cambie.

Para que Seq añada el contenido del objeto a la traza, hay que colocar una arroba (@) delante del objeto entre paréntesis

A este punto, es importante señalas que quien está creando las trazas estructuradas de nuestra aplicación .Net Core es Serilog y no Seq. Es por esto que si comprobamos la salida de consola o de fichero podemos encontrar algo como esto:

[20:52:52 ERR] Se ha producido un error registrando el pedido. Id: 2134, Direccion: www.fixedbuffer.com
[20:52:52 ERR] Se ha producido un error registrando el {"IdPedido": 2134, "Dirección": "www.fixedbuffer.com", "$type": "Pedido"}.

¿Y qué ventaja nos aporta Seq entonces? Pues que es muy cómodo poder consultar esos datos:

La imagen muestra desplegada una traza generada desde .Net Core con Serilog  y enviada a Seq, donde se lee:
"Se ha producido un error registrando el Pedido", y junto al mensaje un json con los datos del pedido.

Securizando la ingesta de trazas enviadas a Seq desde .Net Core con Serilog

Si bien es cierto que con lo que hemos hecho hasta ahora ya tenemos listo Serilog para enviar trazas a Seq desde una aplicación .Net Core, el escenario es un tanto inseguro… Cualquiera que conozca el endpoint de ingesta puede mandar datos.

Para poder solucionar esta situación, Seq nos ofrece la posibilidad de crear tokens que deberán utilizar las aplicaciones para enviar las trazas, ya sea desde Serilog o desde cualquier otro logger de .Net Core que soporte trabajar con Seq.

Para conseguir ello basta con ir al menú ‘settings’ de la parte superior derecha y después pulsar sobre ‘Add API Key’

La imagen señala los botones "settings" de la parte superior derecha y "ADD API KEY" de la parte inferior izquierda

Eso nos lanzará una nueva ventana donde vamos a poder configurar diferentes aspectos de la key como su nombre, sus permisos, el nivel mínimo de trazas que va a registrar o diferentes filtros y propiedades.

La imagen muestra la interfaz de creación de una key para una aplicación .Net Core con Serilog y Seq

Una vez configurado, basta con pulsar sobre ‘Save Changes’ para guardar los datos y crear una key que se nos mostrará por pantalla.

Importante: La key solo se mostrará una vez y no será posible recuperarla después, asi que toma nota de ella y ponla a buen recaudo

Una vez tenemos la key, basta dársela a Serilog a través del parámetro ‘apiKey’, ya sea utilizando código o un fichero de configuración.

Visualización mediante paneles

Una de las cosas que más me gusta de Seq es la posibilidad que ofrece de monitorizar el estado de las aplicaciones sin ningún esfuerzo. Creas tu aplicación .Net Core, añades Serilog, configuras el sink de Seq, y a partir de ese momento puedes crear diferentes paneles donde visualizar la información relevante.

La imagen muestra el panel de gráficas por defecto que ofrece Seq

Para esto Seq ofrece una ventana de paneles donde es posible crear paneles propios aplicando consultas sobre la información que se registra.

Extensión de la funcionalidad

Aunque no quiero entrar muy a fondo en lo extensible que es Seq, si es muy útil conocer que se puede extender a través de más de 500 paquetes NuGet que añaden diferentes funcionalidades como por ejemplo el envío de alertas por correo electrónico, o incluso por Slack o Microsoft Teams.

Para poder añadir estos paquetes que dotan de funcionalidad extra a Seq, bastan con ir al menú de ‘settings’, pero esta vez al submenú ‘Apps’.

La imagen señala el botón "settings" de la parte superior derecha y el submenu APPS de la parte izquierda

Desde esta ventana vamos a poder buscar los diferentes paquetes y podremos instalarlos con un simple click.

Evidentemente luego hay que configurarlos, y que sea sencillo o no dependerá de cómo y para qué sea el paquete.

Conclusión

Para no extender mucho la entrada y que se haga eterna, hemos revisado por encima la principal funcionalidad que ofrece enviar las trazas de .Net Core a Seq con Serilog. La funcionalidad que he planteado es la que a mí me parece más interesante, pero eso no significa que sea la única.

Seq ofrece una gran funcionalidad extra que facilitan mucho la vida a la hora de encontrar problemas sobre sistemas en producción, pero nada es gratis.

Primero, el software, aunque ofrece un modo gratuito que se puede utilizar en producción, si necesitas una gestión de usuarios o un soporte avanzado, no te queda otra que pasar por caja…

Después, está el coste computacional extra de enviar las trazas por una conexión de red, que, aunque es muy bajo, no es despreciable y hay que tenerlo en cuenta.

Por último, el hecho de que ante un fallo catastrófico pueden quedarse trazas pendientes de enviar y no registrarse en Seq. Si que es cierto que Serilog y otros sistemas de logging ofrecen mecanismos para guardar las trazas temporalmente en un fichero de modo que evitemos esos casos, es trabaja extra por nuestra parte el configurarlos. Además, el sistema que tiene que gestionar ese trabajo extra así que hay que plantearse si es necesario cuando escribes código de alto rendimiento en .Net Core.

Con todo, personalmente creo que Seq es una gran herramienta a tener en el cinturón, aunque solo sea durante la fase de desarrollo. Al fin y al cabo, se puede poner en marcha Seq desde un Docker y poner y quitar el sink son un par de líneas de código.

¿Y tú? ¿Crees que Seq puede ayudarte en tu día a día?

Deja un comentario