viernes, 8 de mayo de 2009

Banco de experiencias (II): Logback, la evolución de log4j

Log4j se ha convertido en el estandar de facto para la información de trazado de cualquier proyecto Java. Es una de esas librerías que se añaden a un proyecto prácticamente en el propio proceso de creación del mismo, antes de añadir ninguna clase. Pertenece a ese pequeño y selecto grupo de librerías/frameworks imprescindibles (me lo apunto para una próxima entrada) en cualquier proyecto. Y cuando digo cualquier proyecto, no sólo me refiero a Java. El diseño de la librería y de su estructura es tan bueno, que ha sido portada a multitud de plataformas: el porting de .NET es excelente, y tiene otros muchos más a diversas plataformas.

Sin embargo, a pesar de parecer perfecta y casi inmejorable, tiene un sucesor muy superior: logback. Lo primero que uno percibe al examinar logback es que su diseño y realización está basado en la experiencia con log4j, mejorando algunos pequeños inconvenientes que habían surgido durante su evolución y, sobre todo, respondiendo a las necesidades que han ido surgiendo durante estos casi 10 años de vida, como demuestra Ceki Gülcü, su diseñador, que fue también el fundador de log4j.

Simple Logging Facade for Java
Logback es una implementación de SLF4J (Simple Logging Facade for Java): una capa de abstracción (un façade, como su propio nombre indica) para varios frameworks distintos de logging. SLF4J es el sucesor de Jakarta Commons Logging (JCL), pero mejorado en muchos aspectos. Sin entrar en demasiados detalles, para cualquiera que realice una migración a SLF4J disfrutará, de entrada con 3 mejoras inmediatas:
  • Se acabaron los problemas con los class loaders, dada su vinculación (binding) estática con la implementación subyacente (con JCL es dinámica en tiempo de ejecución).
  • Trazado con parámetros mucho más sencillo y eficiente.
  • Independencia, dado que puedes usar múltiples vinculaciones con sólo añadir otro ".jar" (p.e.: desde "slf4j-simple-x.x.x.jar", para pequeñas aplicaciones que usen System.err hasta "slf4j-log4j12-x.x.x.jar", para servir de puente a log4j.)
Logback
Logback, al ser una implementación sofisticada de SLF4J, disfruta de todas las ventajas de éste y, también sin entrar en sofisticaciones y sólo tocando temas comunes que cualquier usuario habitual de log4j podrá valorar, yo destacaría las siguientes:

Migrando desde log4j
Los impacientes que quieran empezar a usarlo migrando un proyecto existente, pueden considerar usar el SLF4J Migrator, muy útil para hacer los cambios en pocos minutos.

Los que hayan usado log4j sin seguir las normas de estilo, como trazar sin mensaje (p.e. log.trace(a), siendo "a" un int, boolean, Exception o cualquier otro objeto) deberán resolver los errores de compilación, ya que SLF4J no soporta esto: deberán poner un mensaje siempre (al fin y al cabo, si no se pone, la traza queda poco legible).

En todo caso, por experiencia, os garantizo que la migración es bastante suave y se puede cambiar un proyecto en pocos minutos.


Fichero de configuración
En log4j me había realizado un fichero de configuración más o menos estándar para entornos de producción que me generaba 3 ficheros:
  • Uno de nivel INFO. Uno por día, sin borrado automático (lamentablemente no era posible con el DailyRollingFileAppender)
  • Uno de nivel DEBUG. Fijo por tamaño y con máximo de ficheros
  • Uno de nivel TRACE. Fijo por tamaño y con máximo de ficheros.
Esta configuración me resultaba muy útil, ya que en caso de incidencia reciente, tenía logs de niveles TRACE y DEBUG de las últimas horas del sistema. El problema es que tienes que ser muy prudente con los tamaños y había que navegar entre varios ficheros para encontrar el momento que buscabas.

He migrado el fichero a logback pero pudiendo disfrutar de las características nuevas: excepciones más cortas en INFO, uno por día en todos los niveles (aunque con menos historia en los niveles más verbosos).

Os dejo el fichero a continuación para que podáis echar un vistazo y adaptarlo a vuestras necesidades.

logback.xml
1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 <configuration>
 4   <jmxConfigurator contextName="tkuf2" />
 5   <!-- Se puede establecer el directorio "a mano" o usar el del usuario  -->
 6   <!-- <property name="USER_HOME" value="/home/szarza" />  -->
 7   <property name="USER_HOME" value="${user.home}" />
 8   <property name="appName" value="tk.uf" /> 
9   <property name="logPath" value="${USER_HOME}/tk2/logs" />
10   <!--
11     1 por día. Nivel INFO. 300 días de historia 
12    -->
13   <appender name="INFO" class="ch.qos.logback.core.rolling.RollingFileAppender">
14     <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
15       <level>INFO</level>
16     </filter>
17     <File>${logPath}/${appName}.log</File>
18     
19     <!-- 5 líneas de stacktrace para las excepciones -->
20     <layout class="ch.qos.logback.classic.PatternLayout">
21       <Pattern>%date %-5level %logger{20} - %message%n %exception{5}</Pattern>
22     </layout>
23     
24     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
25       <FileNamePattern>${logPath}/${appName}.%d{yyyy-MM-dd}.log</FileNamePattern>  
26       <!-- mantener 300 días de historia -->  
27       <MaxHistory>300</MaxHistory> 
28     </rollingPolicy>
29   </appender>
30   
31   <appender name="DEBUG" class="ch.qos.logback.core.rolling.RollingFileAppender">
32     <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
33       <level>DEBUG</level>
34     </filter>
35     
36     <File>${logPath}/${appName}.d.log</File>
37     
38     <!-- 10 líneas de stacktrace para las excepciones -->
39     <layout class="ch.qos.logback.classic.PatternLayout">
40       <Pattern>%date %-5level %logger{20} - %message%n %exception{10}</Pattern>
41     </layout>
42     
43     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
44       <FileNamePattern>${logPath}/${appName}.d.%d{yyyy-MM-dd}.log</FileNamePattern>
45       <!-- mantener 10 días de historia -->  
46       <MaxHistory>10</MaxHistory> 
47     </rollingPolicy>
48   </appender>
49 
50   <appender name="TRACE" class="ch.qos.logback.core.rolling.RollingFileAppender">
51     <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
52       <level>TRACE</level>
53     </filter>
54     <File>${logPath}/${appName}.t.log</File>
55     
56     <!-- full stacktrace para las excepciones -->
57     <layout class="ch.qos.logback.classic.PatternLayout">
58       <Pattern>%date %-5level %logger{20} - %message%n</Pattern>
59     </layout>
60     
61     <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
62       <FileNamePattern>${logPath}/${appName}.t.%d{yyyy-MM-dd}.log</FileNamePattern>  
63       <!-- mantener 5 días de historia -->  
64       <MaxHistory>5</MaxHistory> 
65     </rollingPolicy>
66   </appender>
67 
68   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
69    <layout class="ch.qos.logback.classic.PatternLayout">
70      <Pattern>
71         %date{HH:mm:ss.SSS} %-5level %logger{10} - %message%n
72       </Pattern>
73     </layout>
74   </appender>
75   
76   
77   <logger name="cestel.tk.uf" level="TRACE">
78     <appender-ref ref="INFO"/>
79     <appender-ref ref="DEBUG"/>
80     <appender-ref ref="TRACE"/>
81   </logger>
82   
83   <root level="OFF">
84     <!-- 
85     <appender-ref ref="STDOUT" />
86      -->
87   </root>
88   
89 </configuration>

3 comentarios :

  1. Thank you for a great article. If you like reloading config files via JMX, you should have a look at auto-scan: http://logback.qos.ch/manual/configuration.html#autoScan

    Cheers,

    ResponderEliminar
  2. Hola Samuel,

    Gracias por el comentario que pusiste en mi blog, aunque lo borré sin querer al ir a moderarlo...

    Sin embargo, me apunto tu recomendación sobre Logback y le echaré un vistazo.

    Un saludo.

    ResponderEliminar
  3. Gran articulo, me ha servido para dar el paso de migrar mis proyectos de log4j a slf4j.

    En mi blog he creado una entrada sobre SLF4J Migrator en el cual te he hago referencia, si te apetece echarle un vistazo es este: http://fuenteperez.es/blog/slf4j-migrator-migra-tus-proyectos-de-log4j-a-slf4j-especial-impacientes

    Muchas Gracias.

    Salu2. Héctor.

    ResponderEliminar

Related Posts Plugin for WordPress, Blogger...
cookieassistant.com