SLF4J Migrator: Migra tus Proyectos de log4j a slf4j (Especial impacientes)
Muchas son las bondades de SFL (Simple Logging Facade) y sus implementaciones para Java (slf4j y logback) frente a sus predecesores pero aun mayoritariamente utilizados JCL (Jakarta Commons Logging) y log4j. De forma resumida podríamos nombrar:
- 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.)
Si queréis conocer más sobre ello, os invito a que echéis un vistazo al articulo de Balteus donde enumera algunas de las mejoras que ofrece logback.
En este caso yo os presento a SLF4J Migrator que es es una herramienta Java para migrar tus fuentes Java de Jakarta Commons Logging(JCL) a SLF4J. También puede migrar de la API log4j a SLF4J, o de java.util.logging a SLF4J.
Para poder utilizarlo, lo primero que debemos hacer es descargarnos la distribución de slf4j que incluye el slf4j-migrator-version.jar (en mi caso 1.6.4). Una vez lo tenemos ejecutamos lo siguiente:
java -jar slf4j-migrator-1.6.4.jar
Si esta todo correcto, nos tiene que aparecer la siguiente pantalla:
Lo primero que llama la atención es el WARNING en color rojo y que dice: Cuidado, si me utilizas voy a cambiar tus fuentes y no voy hacer ningún tipo de copia de seguridad, ¿eres consciente? Vamos que no se hace responsable de la que te puede liar (por eso lo llamo especial para impacientes).
A continuación seleccionamos la migración, en mi caso de log4j a sfl4j y marcamos el check diciendo que sabemos lo que estamos haciendo y …
En este caso solamente tenía una clase Java. Como veréis a continuación, esta herramienta hace las tareas más básicas, como modificar los imports y la declaración del logger. Esta era mi clase que utiliza log4j antes de la migración:
package es.fuenteperez;
import org.apache.log4j.Logger;
public class Main {
private static Logger log = Logger.getLogger(Main.class);
public static void main(String[] args) {
try {
logger.info("Hola Mundo INFO!!");
if(logger.isDebugEnabled()){
logger.debug("Hola mundo DEBUG!");
}
} catch (Exception e) {
logger.error("Se ha producido un error: ", e);
}
}
}
}
y esta es la nueva clase que utiliza sfl4j
package es.fuenteperez;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static Logger logger = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
try {
logger.info("Hola Mundo INFO!!");
if (logger.isDebugEnabled()) {
logger.debug("Hola mundo DEBUG!");
}
} catch (Exception e) {
logger.error("Se ha producido un error: ", e);
}
}
}
Limitaciones Generales
No todo iba a ser maravilloso, a continuación enumero algunas limitaciones generales en los 3 tipos de migraciones.
- Solo modifica ficheros Java, por tanto tendras que modificar todos tus scripts (Ant/Maven/Ivy) manualmente.
- Únicamente esta soportados los mensajes de tipo String. Por ejemplo:
logger.debug(new Object()); –> logger.debug(new Object().toString());
- El nivel FATAL no está soportado. ¿Quien utiliza FATAL?
- Si un método declara varios logger la transformación no funciona correctamente ya que únicamente modifica el primero, p.e:
public void someMethod(Log l1, Log l2) {
...
}
lo convierte a
public void someMethod(Log l1, Logger l2) {
...
}
Limitaciones cuando migramos desde log4j
- Las declaraciones NDC (Nested Diagnostic Context) no estan soportadas y se quedan como están y deben ser migradas manualmente a MDC (Mapped Diagnostic Context). Un NDC es un instrumento para distinguir salidas de log intercaladas que provienen de distintas fuentes. Las salidas de log suelen ser intercaladas cuando un servidor maneja varios clientes al mismo tiempo. El MDC es lo mismo que el NDC solo que usando un Map como implementación. Más información sobre el tema.
- Llamadas a PropertyConfigurator o DomConfigurator no se pueden migar porque no estan soportadas por sfl4j.
Limitaciones cuando migramos desde JUL
- No se modifican las llamadas a los métodos finest(), finer() o finest() de java.logging.Logger. Esto es debido a que estas llamadas se pueden corresponder con los métodos trace() o debug(), por tanto será tarea del desarrollador decidir porque método deseas sustituirlos.
- Todas las cadenas de caracteres que correspondas con “.severe(“ serán sustituidas por “.error(“, así como todas las cadenas “.warning(“ serán sustituidas por “.warn(” sin realizar ningún análisis contextual. Dado que la operación de comprobación/sustitución no es contextual, si nuestro código contiene métodos llamados “severe” o “warning” (p.e. servicioEjemplo.warning(String cadena) ) se generaran errores de compilación. Yo nunca he creado en alguna de mis clases un método con este nombre pero si alguno de vosotros lo hace que sepáis que con la migración va a fallar.
- Las llamadas a los siguientes métodos de la clase java.util.logging.Logger deben migrarse manualmente: log, logp, logrb, entering y exiting.
Ya veis que existen una serie de limitaciones que pueden echaros un poco para atrás a la hora de hacer la migración con SFL4J Migrator, sin embargo creo que son casos muy concreto, y en mi caso probablemente el 95% de mis proyectos se migrarían sin problemas, eso si no os olvidéis de quitar los antiguos jars y añadir los nuevos que eso tampoco lo hace la herramienta.
Salu2. Héctor.





Buen artículo. La verdad es que migras un proyecto bastante rápido con SLF4J Migrator. Además, eso te fuerza a cambiar esos “log.trace(ref)” que tanto daño hacen a los logs, porque trazas un el valor de un objeto sin comentario alguno. Yo los cambio a “log.trace(“ref={}”,ref)” que es más claro.
Por cierto, no tengo claro eso que dices sobre que no está soportado el NDC. Logback es una implementación completa de SLF4J (http://www.slf4j.org/api/org/slf4j/NDC.html). De hecho, yo lo he usado- ¿Hablas de algún caso concreto?
Saludos.