Log4net: trazando nuestras aplicaciones

En ocasiones es importante almacenar un registro con información sobre los procesos realizados, principalmente en el entorno de desarrollo. Otra de las necesidades comunes puede ser recibir un correo cuando una acción finaliza correcta y/o incorrectamente o simplemente mantener un registro de un determinado nivel de información. Log4net cubre todas estas necesidades por nosotros de una forma altamente configurable :D

Esta librería es fruto de su antecesora log4j (log for Java) la cual ha derivado para diferentes lenguajes como C++, PHP y por supuesto .NET.

Configuración

Toda la configuración de la librería puede estar incluida en el archivo de configuración o programáticamente. Personalmente pienso que la configuración debe estar contenida en los archivos que tienen ese fin :)

<configSections>
   <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
</configSections>

Una vez que tenemos definida la sección en configSections, personalizamos un apartado con la configuración para nuestras trazas. En este post mostraré una configuración para mostrar las mismas a través de la consola y por email.

<log4net>
    <logger name="Program">
      <level value="INFO" />
      <appender-ref ref="ConsoleAppender" />
    </logger>
    <logger name="ProductosRepository">
      <level value="WARN" />
      <appender-ref ref="SmtpAppender" />
    </logger>
    <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender" >
      <layout type="log4net.Layout.PatternLayout">
        <conversionPattern value="%date [%thread] %-5level %logger - %message%newline" />
      </layout>
    </appender>
    <appender name="SmtpAppender" type="log4net.Appender.SmtpAppender,log4net">
      <to value="destinatario@returngis.net" />
      <from value="remitente@returngis.net" />
      <subject value="Asunto del correo" />
      <smtpHost value="smtp.returngis.net" />
      <bufferSize value="512" />
      <lossy value="true" />
      <evaluator type="log4net.Core.LevelEvaluator,log4net">
        <threshold value="ERROR" />
      </evaluator>
      <layout type="log4net.Layout.PatternLayout,log4net">
        <conversionPattern value="%property{log4net:HostName} :: %level :: %message %newlineLogger: %logger%newlineThread: %thread%newlineDate: %date%newlineNDC: %newline%newline" />
      </layout>
    </appender>
</log4net>

Si nos fijamos en la configuración expuesta, vemos que tenemos en realidad dos apartados repetidos: logger y appender.

Elemento logger

Este elemento define la configuración para ser utilizada en un apartado específico de nuestro código. Me explico: Supongamos que queremos mostrar información por pantalla de los pasos que se van completando en una capa de nuestra aplicación, para saber qué parte de nuestro código se está ejecutando. Por otro lado, necesitamos recibir un email cada vez que en la lógica relacionada con la base de datos o los servicios se produzca un error. Gracias a este apartado, podemos definir diferentes configuraciones para poder usarlas conjuntamente en una misma aplicación. Como parámetros tenemos el nivel de información que queremos registrar y el tipo de salida (appender).

 El nivel de error es acumulativo, es decir, si nuestro nivel de error es de tipo INFO abarcará los niveles información, warnings, errores y errores fatales. Si por el contrario el nivel establecido es ERROR, este sólo cubrirá los errores y los errores fatales. Por lo tanto, el modo que habilita todos los niveles sería el modo DEBUG.

Elemento appender

Por otro lado, los appenders son los tipos de salida que podemos configurar. En este post voy a mostrar solamente la salida por consola y por SMTP para el envío de correos. Para más ejemplos sobre otros tipos podéis echar un vistazo a este enlace.

Como valores significativos podemos mencionar:

 Pattern.Layout para definir información a mostrar a través de patrones. En el caso del ConsoleAppender que tenemos definido en el ejemplo la información sería mostrada de la siguiente forma:

Lossy se utiliza de forma conjunta con el elemento evaluator para evitar el consumo excesivo de recursos en producción cuando la ejecución de nuestro programa es normal. Sin embargo, si la aplicación registra un error registrará esta información con un pequeño batch de lo ocurrido momentos antes de la excepción :)

Los appenders que soportan esta opción son los siguientes:

  • log4net.Appender.AdoNetAppender
  • log4net.Appender.RemotingAppender
  • log4net.Appender.SmtpAppender
  • log4net.Appender.SmtpPickupDirAppender
  • log4net.Appender.BufferingForwardingAppender

Recuperar la configuración

Como comenté en el apartado anterior, dependiendo del cuál queramos que sea el nivel y el tipo de salida, debemos solicitar una configuración u otra a la hora de la creación de nuestro objeto del tipo ILog. A través del mismo podremos registrar las trazas necesarias. En este caso, he utilizado el nombre de la clase en la que me encuentro para dar nombre a los distintos apartados, pero podríamos utilizar, por ejemplo, el nombre del proyecto o cualquier otro nombre significativo.

private static readonly ILog Logger = LogManager.GetLogger(typeof(Program).Name);

El siguiente paso sería cargar la configuración desde el archivo de configuración, a través del siguiente método:

XmlConfigurator.Configure();

A partir de este momento estamos listos para comenzar a trazar nuestro código :D Para ello, basta con utilizar el objeto logger creado anteriormente de manera bastante similar a Trace.

Logger.Info("Retrieving files...");

Del mismo modo, podemos formatear strings:

Logger.ErrorFormat("{0}:{1}", ex.InnerException, ex.StackTrace);

Espero que sea de utilidad :)

¡Saludos!