¿Por qué no usar java.util.logging?

351

Por primera vez en mi vida me encuentro en una posición en la que escribo una API de Java que será de código abierto. Con suerte para ser incluido en muchos otros proyectos.

Para iniciar sesión, yo (y de hecho las personas con las que trabajo) siempre he usado JUL (java.util.logging) y nunca he tenido ningún problema. Sin embargo, ahora necesito entender con más detalle lo que debo hacer para mi desarrollo de API. He investigado un poco sobre esto y con la información que tengo me confundo más. De ahí esta publicación.

Desde que vengo de JUL, soy parcial en eso. Mi conocimiento del resto no es tan grande.

De la investigación que he hecho, he llegado a estas razones por las cuales a la gente no le gusta JUL:

  1. "Comencé a desarrollar en Java mucho antes de que Sun lanzara JUL y fue más fácil para mí continuar con logging-framework-X en lugar de aprender algo nuevo" . Hmm No estoy bromeando, esto es realmente lo que dice la gente. Con este argumento todos podríamos estar haciendo COBOL. (Sin embargo, ciertamente puedo relacionarme con esto siendo un tipo perezoso)

  2. "No me gustan los nombres de los niveles de registro en JUL" . Ok, en serio, esta no es razón suficiente para introducir una nueva dependencia.

  3. "No me gusta el formato estándar de la salida de JUL" . Hmm Esto es solo configuración. Ni siquiera tiene que hacer nada en cuanto a código. (Es cierto, en los viejos tiempos es posible que haya tenido que crear su propia clase de formateador para hacerlo bien).

  4. "Uso otras bibliotecas que también usan logging-framework-X, así que pensé que era más fácil usar esa" . Este es un argumento circular, ¿no? ¿Por qué "todos" usan logging-framework-X y no JUL?

  5. "Todos los demás están usando logging-framework-X" . Esto para mí es solo un caso especial de lo anterior. La mayoría no siempre tiene la razón.

Entonces, la verdadera gran pregunta es ¿por qué no JUL? . ¿Qué es lo que me he perdido? La razón de ser para las fachadas de registro (SLF4J, JCL) es que las implementaciones de registro múltiples han existido históricamente y la razón de eso realmente se remonta a la era anterior a JUL tal como lo veo. Si JUL fuera perfecto, entonces las fachadas de registro no existirían, ¿o qué? Para hacer las cosas más confusas, JUL es, en cierta medida, una fachada en sí misma, permitiendo intercambiar manipuladores, formateadores e incluso el LogManager.

En lugar de adoptar múltiples formas de hacer lo mismo (iniciar sesión), ¿no deberíamos preguntarnos por qué fueron necesarias en primer lugar? (y ver si esas razones aún existen)

Ok, mi investigación hasta ahora ha llevado a un par de cosas que puedo ver que pueden ser problemas reales con JUL:

  1. Rendimiento . Algunos dicen que el rendimiento en SLF4J es superior al resto. Esto me parece un caso de optimización prematura. Si necesita registrar cientos de megabytes por segundo, no estoy seguro de que esté en el camino correcto de todos modos. JUL también ha evolucionado y las pruebas que realizó en Java 1.4 pueden no ser ciertas. Puede leer sobre esto aquí y esta solución ha llegado a Java 7. Muchos también hablan sobre la sobrecarga de la concatenación de cadenas en los métodos de registro. Sin embargo, el registro basado en plantillas evita este costo y existe también en JUL. Personalmente, nunca escribo un registro basado en plantillas. Demasiado perezoso para eso. Por ejemplo, si hago esto con JUL:

    log.finest("Lookup request from username=" + username 
       + ", valueX=" + valueX
       + ", valueY=" + valueY));

    mi IDE me avisará y solicitará permiso para que lo cambie a:

    log.log(Level.FINEST, "Lookup request from username={0}, valueX={1}, valueY={2}", 
       new Object[]{username, valueX, valueY});

    .. que por supuesto aceptaré. Permiso concedido ! Gracias por tu ayuda.

    Entonces, en realidad no escribo tales declaraciones, eso lo hace el IDE.

    En conclusión sobre el tema del rendimiento, no he encontrado nada que sugiera que el rendimiento de JUL no está bien en comparación con la competencia.

  2. Configuración desde classpath . El JUL listo para usar no puede cargar un archivo de configuración desde el classpath. Son unas pocas líneas de código para hacerlo. Puedo ver por qué esto puede ser molesto, pero la solución es breve y simple.

  3. Disponibilidad de manejadores de salida . JUL viene con 5 controladores de salida listos para usar: consola, flujo de archivos, socket y memoria. Estos se pueden ampliar o se pueden escribir otros nuevos. Esto puede, por ejemplo, estar escribiendo en UNIX / Linux Syslog y Windows Event Log. Personalmente nunca he tenido este requisito ni lo he visto utilizado, pero ciertamente puedo relacionarme por qué puede ser una característica útil. Logback viene con un apéndice para Syslog, por ejemplo. Aún así argumentaría que

    1. El 99.5% de las necesidades de destinos de salida están cubiertos por lo que está en JUL listo para usar.
    2. Las necesidades especiales podrían ser atendidas por manejadores personalizados en la parte superior de JUL en lugar de otra cosa. No hay nada para mí que sugiera que se necesita más tiempo para escribir un controlador de salida de Syslog para JUL que para otro marco de registro.

Me preocupa mucho que haya algo que he pasado por alto. El uso de fachadas de registro e implementaciones de registro que no sean JUL está tan extendido que tengo que llegar a la conclusión de que soy yo quien simplemente no comprende. Esa no sería la primera vez, me temo. :-)

Entonces, ¿qué debo hacer con mi API? Quiero que tenga éxito. Por supuesto, puedo simplemente "seguir la corriente" e implementar SLF4J (que parece ser el más popular en estos días), pero por mi propio bien, todavía necesito entender exactamente qué está mal con el JUL de hoy que justifica toda la confusión. ¿Me sabotearé eligiendo JUL para mi biblioteca?

Prueba de rendimiento

(sección agregada por nolan600 el 07-JUL-2012)

Hay una referencia a continuación de Ceki acerca de que la parametrización de SLF4J es 10 veces o más rápida que la de JUL. Así que comencé a hacer algunas pruebas simples. A primera vista, la afirmación es ciertamente correcta. Aquí están los resultados preliminares (¡pero sigue leyendo!):

  • Tiempo de ejecución SLF4J, back-end Logback: 1515
  • Tiempo de ejecución SLF4J, backend JUL: 12938
  • Tiempo de ejecución JUL: 16911

Los números anteriores son ms, por lo que menos es mejor. Entonces, la diferencia de rendimiento 10 veces es realmente bastante cercana. Mi reacción inicial: ¡eso es mucho!

Aquí está el núcleo de la prueba. Como se puede ver, un entero y una cadena se construyen en un bucle que luego se usa en la declaración de registro:

    for (int i = 0; i < noOfExecutions; i++) {
        for (char x=32; x<88; x++) {
            String someString = Character.toString(x);
            // here we log 
        }
    }

(Quería que la instrucción de registro tuviera un tipo de datos primitivo (en este caso, un int) y un tipo de datos más complejo (en este caso, una Cadena). No estoy seguro de que sea importante, pero ahí lo tiene.

La declaración de registro para SLF4J:

logger.info("Logging {} and {} ", i, someString);

La declaración de registro para JUL:

logger.log(Level.INFO, "Logging {0} and {1}", new Object[]{i, someString});

La JVM se 'calentó' con la misma prueba ejecutada una vez antes de que se realizara la medición real. Se utilizó Java 1.7.03 en Windows 7. Se utilizaron las últimas versiones de SLF4J (v1.6.6) y Logback (v1.0.6). Stdout y stderr se redirigieron a un dispositivo nulo.

Sin embargo, con cuidado ahora, resulta que JUL pasa la mayor parte de su tiempo getSourceClassName()porque JUL imprime de manera predeterminada el nombre de la clase de origen en la salida, mientras que Logback no lo hace. Entonces estamos comparando manzanas y naranjas. Tengo que volver a hacer la prueba y configurar las implementaciones de registro de manera similar para que realmente produzcan lo mismo. Sin embargo, sospecho que SLF4J + Logback seguirá apareciendo en la parte superior, pero lejos de los números iniciales como se indicó anteriormente. Manténganse al tanto.

Por cierto: la prueba fue la primera vez que realmente trabajé con SLF4J o Logback. Una experiencia placentera. JUL es ciertamente mucho menos acogedor cuando estás comenzando.

Prueba de rendimiento (parte 2)

(sección agregada por nolan600 el 08-JUL-2012)

Como resultado, realmente no importa para el rendimiento cómo configura su patrón en JUL, es decir, si incluye o no el nombre de la fuente. Lo intenté con un patrón muy simple:

java.util.logging.SimpleFormatter.format="%4$s: %5$s [%1$tc]%n"

y eso no cambió en absoluto los tiempos anteriores. Mi generador de perfiles reveló que el registrador aún pasaba mucho tiempo en llamadas, getSourceClassName()incluso si esto no era parte de mi patrón. El patrón no importa.

Por lo tanto, estoy concluyendo sobre el tema del rendimiento que, al menos para la declaración de registro basada en la plantilla probada, parece haber aproximadamente un factor de 10 en la diferencia de rendimiento real entre JUL (lento) y SLF4J + Logback (rápido). Justo como dijo Ceki.

También puedo ver otra cosa, a saber, que la getLogger()llamada de SLF4J es mucho más cara que el ídem de JUL. (95 ms frente a 0,3 ms si mi generador de perfiles es preciso). Esto tiene sentido. SLF4J tiene que dedicar un tiempo a la vinculación de la implementación de registro subyacente. Esto no me asusta. Estas llamadas deberían ser algo raras en la vida útil de una aplicación. La solidez debe estar en las llamadas de registro reales.

Conclusión final

(sección agregada por nolan600 el 08-JUL-2012)

Gracias por todas tus respuestas. Al contrario de lo que inicialmente pensé, terminé decidiendo usar SLF4J para mi API. Esto se basa en una serie de cosas y su aporte:

  1. Ofrece flexibilidad para elegir la implementación del registro en el momento de la implementación.

  2. Problemas con la falta de flexibilidad de la configuración de JUL cuando se ejecuta dentro de un servidor de aplicaciones.

  3. SLF4J es ciertamente mucho más rápido como se detalla anteriormente en particular si lo combina con Logback. Incluso si esto fuera solo una prueba aproximada, tengo razones para creer que se ha dedicado mucho más esfuerzo a la optimización en SLF4J + Logback que en JUL.

  4. Documentación. La documentación para SLF4J es simplemente mucho más completa y precisa.

  5. Patrón de flexibilidad. Cuando hice las pruebas, me propuse que JUL imitara el patrón predeterminado de Logback. Este patrón incluye el nombre del hilo. Resulta que JUL no puede hacer esto fuera de la caja. Ok, no me lo he perdido hasta ahora, pero no creo que sea algo que deba faltar en un marco de registro. ¡Período!

  6. La mayoría (o muchos) proyectos de Java hoy en día usan Maven, por lo que agregar una dependencia no es tan importante, especialmente si esa dependencia es bastante estable, es decir, no cambia constantemente su API. Esto parece ser cierto para SLF4J. Además, el frasco SLF4J y sus amigos son de tamaño pequeño.

Entonces, lo extraño que sucedió fue que realmente me molesté bastante con JUL después de haber trabajado un poco con SLF4J. Todavía lamento que tenga que ser así con JUL. JUL está lejos de ser perfecto, pero hace el trabajo. Simplemente no lo suficientemente bien. Se puede decir lo mismo Propertiescomo un ejemplo, pero no pensamos en abstraerlo para que las personas puedan conectar su propia biblioteca de configuración y lo que tengan. Creo que la razón es que Propertiesviene justo por encima de la barra, mientras que lo contrario es cierto para JUL de hoy ... y en el pasado llegó a cero porque no existía.

Peter
fuente
8
No haré un cierre, ya que esta pregunta bien presentada es interesante, pero es dudosa si lees las preguntas frecuentes: será difícil encontrar una respuesta única definitiva que no esté basada en opiniones.
Denys Séguret
Lo que puede haber pasado por alto es que muchos autores de marcos dejaron de intentar usar JUL y, por lo tanto, a menudo es más difícil usarlo si no solo hace vainilla java.
Denys Séguret
3
Es engañoso usar el término genérico "logging-framework-X" al referirse a los marcos de registro populares anteriores a julio. Debería usar "log4j" en este caso. Otros marcos populares como SLF4J y logback llegaron mucho después de que se lanzara julio.
Ceki el
1
@Acuariano. El proyecto Netty simplemente está usando Reflection para probar qué marco de registro está disponible en classpath. Ver aquí para la fuente. Ver InternalLoggerFactory.java.
Peter
1
@xenoterracide aún más importante sería una actualización de Java 9, como se introdujo java.lang.System.Logger, que es una interfaz , que se puede redirigir a cualquier marco de registro real que desee, siempre que ese marco se ponga al día y proporcione una implementación de esa interfaz. En combinación con la modularización, incluso podría implementar una aplicación con un JRE incluido que no contenga java.util.logging, si prefiere un marco diferente.
Holger

Respuestas:

207

Descargo de responsabilidad : soy el fundador de los proyectos log4j, SLF4J y logback.

Hay razones objetivas para preferir SLF4J. Por un lado, SLF4J permite al usuario final la libertad de elegir el marco de registro subyacente . Además, los usuarios más inteligentes tienden a preferir el inicio de sesión que ofrece capacidades más allá de log4j , con julio muy por detrás. Julio de funciones puede ser suficiente para algunos usuarios, pero para muchos otros simplemente no lo es. En pocas palabras, si el registro es importante para usted, querrá usar SLF4J con logback como la implementación subyacente. Si el registro no es importante, julio está bien.

Sin embargo, como desarrollador de oss, debe tener en cuenta las preferencias de sus usuarios y no solo las suyas. Se deduce que debe adoptar SLF4J no porque esté convencido de que SLF4J es mejor que julio, sino porque la mayoría de los desarrolladores de Java actualmente (julio de 2012) prefieren SLF4J como su API de registro. Si finalmente decide no preocuparse por la opinión popular, considere los siguientes hechos:

  1. aquellos que prefieren julio lo hacen por conveniencia porque julio está incluido en el JDK. Que yo sepa, no hay otros argumentos objetivos a favor de julio
  2. su propia preferencia por julio es solo eso, una preferencia .

Por lo tanto, mantener "hechos concretos" por encima de la opinión pública, aunque aparentemente valiente, es una falacia lógica en este caso.

Si aún no está convencido, JB Nizet hace un argumento adicional y potente:

Excepto que el usuario final podría haber hecho esta personalización para su propio código u otra biblioteca que use log4j o logback. jul es extensible, pero tener que extender logback, jul, log4j y solo Dios sabe qué otro marco de registro porque usa cuatro bibliotecas que usan cuatro marcos de registro diferentes es engorroso. Al usar SLF4J, le permite configurar los marcos de registro que desea, no el que ha elegido. Recuerde que un proyecto típico utiliza miles de bibliotecas, y no solo la suya .

Si por alguna razón odias la API SLF4J y usarla te quitará la diversión de tu trabajo, entonces ve por julio Después de todo, hay medios para redirigir julio a SLF4J .

Por cierto, la parametrización de julio es al menos 10 veces más lenta que la SLF4J, lo que termina marcando una diferencia notable.

Ceki
fuente
2
@Ceki, es posible que desee elaborar un poco su descargo de responsabilidad para que mencione su rol actual en los proyectos log4j, slf4j y logback. La razón es, naturalmente, explicar su sesgo.
Thorbjørn Ravn Andersen
2
¿Existe algún soporte para la afirmación de que la mayoría de los desarrolladores de Java prefieren SLF4J como su API de registro?
Olivier Cailloux
3
La esencia de mi publicación es que diferentes desarrolladores tienen diferentes preferencias, lo que parece indiscutible. ¿Si?
Ceki
1
Sinceramente, me encantaría ver los puntos de referencia de 2018 en Java 11 (o lo que sea que termine siendo), y contra log4j2 en modo asíncrono.
xenoterracide
55
Aquí estoy, usando SLF4J, y todavía tengo que lidiar con todos los otros marcos de registro que usan otras bibliotecas. El uso de SLF4J no resuelve el problema de los registradores heterogéneos, solo lo empeora. xkcd.com/927
Charlie
34
  1. java.util.loggingfue introducido en Java 1.4. Hubo usos para el registro antes de eso, es por eso que existen muchas otras API de registro. Esas API se usaron mucho antes de Java 1.4 y, por lo tanto, tenían una gran cuota de mercado que no solo cayó a 0 cuando se lanzó 1.4.

  2. JUL no comenzó tan bien, muchas de las cosas que mencionaste fueron mucho peores en 1.4 y solo mejoraron en 1.5 (y supongo que también en 6, pero no estoy muy seguro).

  3. JUL no es adecuado para múltiples aplicaciones con diferentes configuraciones en la misma JVM (piense en múltiples aplicaciones web que no deberían interactuar). Tomcat necesita saltar a través de algunos aros para que funcione (volver a implementar efectivamente JUL si lo entendí correctamente).

  4. No siempre puede influir en el marco de registro que usan sus bibliotecas. Por lo tanto, el uso de SLF4J (que en realidad es solo una capa API muy delgada por encima de otras bibliotecas) ayuda a mantener una imagen algo coherente de todo el mundo de registro (para que pueda decidir el marco de registro subyacente mientras todavía tiene registro de biblioteca en el mismo sistema).

  5. Las bibliotecas no pueden cambiar fácilmente. Si una versión anterior de una biblioteca solía usar logging-library-X, no puede cambiar fácilmente a logging-library-Y (por ejemplo, JUL), incluso si esta última es claramente soberbia: cualquier usuario de esa biblioteca necesitaría aprender el nuevo marco de registro y (al menos) reconfigurar su registro. Eso es un gran no-no, especialmente cuando no trae ganancias aparentes para la mayoría de las personas.

Dicho todo esto, creo que JUL es al menos una alternativa válida a otros marcos de registro en estos días.

Joachim Sauer
fuente
1
Gracias Joachim, agradezco tu publicación. Sus (1) y (2) son para mí solo historia. Hace mucho tiempo. Su (4) es una consecuencia de eso y luego se convierte en lo que yo llamo un argumento cíclico. Sin embargo, su (3) es realmente interesante. Tal vez estás en algo? Pero esto solo afectaría a aquellos que están creando contenedores de aplicaciones que al final del día son muy pocas personas. ¿O que?
peterh
3
Bueno, quien ignora la historia está condenada a repetirla ;-) La historia es muy relevante en el desarrollo de software. Las personas no se mueven demasiado rápido y reemplazar las bibliotecas de terceros existentes con API estándar solo funciona bien si las API estándar funcionan al menos tan bien como las bibliotecas de terceros. Y no lo hicieron inicialmente (y posiblemente todavía no lo hacen en algunos casos).
Joachim Sauer
Joachim, estoy interesado en aquellos "posiblemente todavía no en algunos casos" que mencionas. Ahí es donde la carne tiene que ser. Reemplazar una biblioteca de registrador en su código existente es bastante trivial y puede automatizarse en estos días. SLF4J tiene una herramienta para eso que prueba mi punto. Por lo tanto, creo que una biblioteca masiva escrita en 2002 con log4j podría convertirse a JUL en cuestión de minutos con una herramienta automatizada. (Sin embargo, no sé si existe). Entonces, ¿por qué no sucede?
peterh
3
@ nolan6000: No sé lo suficiente sobre los detalles para entrar en detalles sobre esa frase, y no es realmente lo que quiero decir. Incluso si JUL ahora está a la par con los marcos de terceros, la inercia y la infraestructura existente siguen siendo una razón sólida para no cambiar. Por ejemplo, si la biblioteca X usó slf4j en la Versión 1.1, cambiar a JUL en 1.2 (o incluso 2.0) sería un problema importante para muchos usuarios (que ya configuraron correctamente el sistema anterior y tendrían que volver a hacerlo sin ganancia aparente) .
Joachim Sauer el
@ nolan6000 incluso si usted no se preocupan por la historia, las bibliotecas que utiliza en sus aplicaciones más ciertamente lo hacen. No es divertido tener que descartar una biblioteca simplemente porque usa un marco de registro diferente al tuyo.
Thorbjørn Ravn Andersen
29

En mi humilde opinión, la principal ventaja de utilizar una fachada de registro como slf4j es que permite que el usuario final de la biblioteca elija qué implementación concreta de registro desea, en lugar de imponer su elección al usuario final.

Tal vez ha invertido tiempo y dinero en Log4j o LogBack (formateadores especiales, apéndices, etc.) y prefiere continuar usando Log4j o LogBack, en lugar de configurar jul. No hay problema: slf4j lo permite. ¿Es una buena elección usar Log4j en julio? Tal vez tal vez no. Pero no te importa. Deje que el usuario final elija lo que prefiera.

JB Nizet
fuente
Gracias JB Mi pregunta es si realmente estoy imponiendo tanto al usuario / implementador de mi biblioteca al forzar a JUL sobre él. Si no está satisfecho con, por ejemplo, los manejadores de salida estándar de JUL, puede cambiarlos por los suyos en el momento de la implementación, tal como lo veo. Realmente no veo a JUL como una camisa de fuerza. Me parece ser tan flexible y extensible como el resto de ellos.
peterh
12
Excepto que el usuario final ya podría haber hecho esta personalización para su propio código u otra biblioteca que use log4j o LogBack. jul es extensible, pero tener que extender LogBack, jul, log4j y solo Dios sabe qué otro marco de registro porque usa 4 bibliotecas que usan 4 marcos de registro diferentes es engorroso. Al usar slf4j, le permite configurar los marcos de registro que desea. no el que has elegido. Recuerde que los proyectos típicos usan miles de bibliotecas, y no solo la suya.
JB Nizet
6

Comencé, como usted sospecho, a usar JUL porque era el más fácil de poner en marcha de inmediato. Con los años, sin embargo, he llegado a desear haber pasado un poco más de tiempo eligiendo.

Mi principal problema ahora es que tenemos una cantidad sustancial de código de 'biblioteca' que se usa en muchas aplicaciones y todas usan JUL. Cada vez que uso estas herramientas en una aplicación de tipo de servicio web, el registro simplemente desaparece o va a un lugar impredecible o extraño.

Nuestra solución fue agregar una fachada al código de la biblioteca que significara que las llamadas de registro de la biblioteca no cambiaron sino que se redirigieron dinámicamente a cualquier mecanismo de registro disponible. Cuando se incluyen en una herramienta POJO, se dirigen a JUL, pero cuando se implementan como una aplicación web, se redirigen a LogBack.

Lamentamos, por supuesto, es que el código de la biblioteca no utilice el registro parametrizado, pero ahora se puede adaptar cuando sea necesario.

Utilizamos slf4j para construir la fachada.

OldCurmudgeon
fuente
1
¿Alguna razón por la que no utilizó el paquete "redirect java.util.logging to slf4j" en la distribución slf4j?
Thorbjørn Ravn Andersen
2
Lo hicimos, pero de poco valor porque el beneficio principal de pasar a slf4j es un registro parametrizado eficiente. Si lo hubiéramos usado desde el principio, no habríamos tenido ningún trabajo que hacer ahora.
OldCurmudgeon
1
Estoy de acuerdo en que esta es la fruta de slf4j.
Thorbjørn Ravn Andersen
3

Ejecuté jul contra slf4j-1.7.21 sobre logback-1.1.7, salida a un SSD, Java 1.8, Win64

jul ejecutó 48449 ms, inicio de sesión 27185 ms para un bucle de 1M.

Aún así, un poco más de velocidad y una API un poco más agradable no valen 3 bibliotecas y 800K para mí.

package log;

import java.util.logging.Level;
import java.util.logging.Logger;

public class LogJUL
{
    final static Logger logger = Logger.getLogger(LogJUL.class.getSimpleName());

    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            Object[] o = { lc };

            logger.log(Level.INFO,"Epoch time {0}", o);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }
}

y

package log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LogSLF
{
    static Logger logger = LoggerFactory.getLogger(LogSLF.class);


    public static void main(String[] args) 
    {
        int N = 1024*1024;

        long l = System.currentTimeMillis();

        for (int i = 0; i < N; i++)
        {
            Long lc = System.currentTimeMillis();

            logger.info("Epoch time {}", lc);
        }

        l = System.currentTimeMillis() - l;

        System.out.printf("time (ms) %d%n", l);
    }

}
weberjn
fuente
3
No estás comparando igual por igual. ¿Por qué estás creando explícitamente una matriz para julio? Supongo que es porque slf4j carece de una sobrecarga de un argumento de logger.info(). Por lo tanto, está paralizando deliberadamente el rendimiento de julio para compensar una deficiencia en la interfaz de slf4j. En su lugar, debe codificar ambos métodos de la forma en que están codificados idiomáticamente.
Klitos Kyriacou
2
Lo malinterpretaste. No tiene que usar 800K adicionales. El consenso es que vale la pena usar la API SLF4J muy delgada porque entonces usted (¡u otros que quizás reutilicen su código algún día!) Puede cambiar libremente entre JUL, Logback, Log4j, etc. SLF4J es solo ~ 28K. El puente SLF4J a JUL (slf4j-jdk ... jar) es solo ~ 9K.
riskop