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, 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:
- Cambios en caliente vía JMX (una maravilla esperada desde hace tiempo). Cuando lo probé casi se me saltan las lágrimas.
- Autorecarga en caliente del fichero de configuración. ([ACTUALIZACIÓN 25/08/09]: Apunte realizado por el mismísimo Ceki. Thank you, Ceki. Your visit and comment was an honour).
- Uso de variables sustituíbles. Adiós rutas absolutas de ficheros.
- Filtros. Aunque lo parezca, no es una funcionalidad sofisticada, se le saca mucha ventaja cuando tienes una aplicación grande y modularizada.
- RollingFileAppender tal y como siempre lo hemos querido, con una configuración flexible usando RollingPolicy. ¿No estabas deseando tener un "MaxBackup" en el DailyRollingFileAppender de log4j? Pues ahora tienes MaxHistory en el TimeBasedRollingPolicy... impresionante (¡¡por fin!!)
- Layout mejorados, como por ejemplo, que te permiten limitar el tamaño del stack trace en las excepciones de INFO.
- De momento no hay un Chainsaw equivalente, pero hay un plugin para eclipse fantástico.
- Rendimiento
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.
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>
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
ResponderEliminarCheers,
Hola Samuel,
ResponderEliminarGracias 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.
Gran articulo, me ha servido para dar el paso de migrar mis proyectos de log4j a slf4j.
ResponderEliminarEn 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.