En este post vamos a ver como crear logs dentro de nuestras aplicaciones C#
En lo que me quiero centrar en este post es en su funcionamiento interno, en el por qué utilziar una interfaz u otra, ya que qué son los logs lo vimos en otro post.
Si no sabes lo que es un log, o como configurar tu aplicación para utilizar logs te recomiendo que leas ese post primero.
1 - Las interfaces de logs en .NET
Dentro de C# tenemos 3 interfaces diferentes que tienen que ver con los logs.
ILogger
: Interfaz responsable de escribir el log, ya bien sea en un fichero, en la terminal o en la nube, donde lo hayas configurado.ILoggerProvider
: Interfaz responsable de crear una instancia deILogger
. En circustancias normales, no tienes que utilizar esta interfaz.ILoggerFactory
: Interfaz que registra y almacena todos losILogerProviders
.
Y esto como se aplica al mundo real?
En el post anterior vimos que utilizando la librería de serilog escribimos logs tanto en la consola como en graylog.
loggerConfiguration.WriteTo.Console(consoleLoggerConfiguration.MinimumLevel)
loggerConfiguration.WriteTo.Graylog(graylogLoggerConfiguration.Host, graylogLoggerConfiguration.Port, TransportType.Udp, graylogLoggerConfiguration.MinimumLevel)
Lo que estamos haciendo por detrás es crear dos providers y uno apuntará a la consola y otro a graylog. Lo hacemos a través de serilog, porque por defecto .net no nos proporciona una interfaz capaz de loguear en graylog, o incluso en el sistema de ficheros, si lo hace a la consola.
Finalmente, cuando llamamos a la interfaz ILogger
, vamos a recibir todos los providers con sus respectivas implementaciones y el mensaje será escrito en todas ellas.
2 - Inyectar el logging en los servicios
Actualmente si creas un proyecto con .net6 te viene en la plantilla el WeatherForecastController
, este controlador viene con un loger, inyectado ILogger<WeatherForecastController>
lo cual ya nos da una pista de lo que debemos hacer.
A la hora de la verdad tenemos dos opciones, inyectar el logger generico ILogger<T>
o inyectar el factory ILoggerFactory
.
La diferencia radica en el proceso de la creación de la interfaz ILogger
que será la que escriba el mensaje.
Si inyectamos ILogger<T>
por detrás nos crea un ILogger con la categoría “ProjectName.Controllers.WeatherForecastController”
Mientras qué, si inyectamos la interfaz ILoggerFactory
somos nosotros los que debemos especificar la categoría.
loggerFactory.CreateLogger("ProjectName.Controllers.WeatherForecastController");
Hay que tener una cosa en cuenta, y es que por defecto esta opción nos crear un ILogger
, no un ILogger<T>
; Para ello deberiamos hacer .CreateLogger<T>(..)
Si inyectamos esta segunda opción estaremos violando el principio de responsabilidad única así que esa opción no es la mejor.
La primera, inyectar ILogger<T>
parece más acorde. Pero a su vez incluir T
parece un poco redundante, no siempre nos va a hacer falta.
Por lo tanto, inyectar únicamente ILogger
en la mayoría de sitios sería lo ideal, pero por defecto la librería de Microsoft no nos va a dejar.
Bajo mi punto de vista personal, esta situación es un poco “hay que pasar por el aro” pero bueno, siendo sinceros, tampoco es el fin del mundo tener un decorador.
Conclusión
Finalmente quiero hacer una mención especial a los nombres de las interfaces, tanto Factory
, como Provider
. Y he de decir que estos nombres me encantan y los he usado continuamente a lo largo de mi carrera profesional cuando he tenido que implementar código con una estructura similar.
En este post he indicado la situación actual del logger en .NET y mi opinión al respecto.