warn mkyong logger found for example ejemplo could appenders java logging log4j

java - mkyong - log4j:warn no appenders could be found for logger



En log4j, ¿la comprobación es DebugEnabled antes de iniciar sesión mejora el rendimiento? (15)

Estoy usando Log4J en mi aplicación para el registro. Anteriormente estaba usando la llamada de depuración como:

Opción 1:

logger.debug("some debug text");

pero algunos enlaces sugieren que es mejor verificar isDebugEnabled() primero, como:

Opcion 2:

boolean debugEnabled = logger.isDebugEnabled(); if (debugEnabled) { logger.debug("some debug text"); }

Entonces mi pregunta es " ¿La opción 2 mejora el rendimiento de alguna manera? ".

Porque en cualquier caso Log4J framework tiene la misma comprobación para debugEnabled. Para la opción 2, podría ser beneficioso si utilizamos una instrucción de depuración múltiple en un único método o clase, donde el marco no necesita llamar al método isDebugEnabled() varias veces (en cada llamada); en este caso, llama isDebugEnabled() método isDebugEnabled() solo una vez, y si Log4J está configurado para depurar el nivel, en realidad llama isDebugEnabled() método isDebugEnabled() dos veces:

  1. En caso de asignar valor a la variable debugEnabled, y
  2. Realmente llamado por el método logger.debug ().

No creo que si escribimos múltiples logger.debug() en método o clase y llamando al método debug() acuerdo con la opción 1, entonces es sobrecarga para Log4J framework en comparación con la opción 2. Dado que isDebugEnabled() es una muy método pequeño (en términos de código), podría ser un buen candidato para la creación de líneas.


A partir de 2.x, Apache Log4j tiene esta comprobación incorporada, por lo que isDebugEnabled() ya no es necesario. Simplemente haga una debug() y los mensajes serán suprimidos si no están habilitados.


Como @erickson, depende. Si recuerdo, isDebugEnabled ya está isDebugEnabled en el método debug() de Log4j.
Siempre que no esté haciendo cálculos costosos en sus declaraciones de depuración, como bucle en objetos, realice cálculos y concatene cadenas, está bien en mi opinión.

StringBuilder buffer = new StringBuilder(); for(Object o : myHugeCollection){ buffer.append(o.getName()).append(":"); buffer.append(o.getResultFromExpensiveComputation()).append(","); } log.debug(buffer.toString());

sería mejor como

if (log.isDebugEnabled(){ StringBuilder buffer = new StringBuilder(); for(Object o : myHugeCollection){ buffer.append(o.getName()).append(":"); buffer.append(o.getResultFromExpensiveComputation()).append(","); } log.debug(buffer.toString()); }


Como en la opción 1 la cadena del mensaje es una constante, no hay absolutamente ninguna ganancia al envolver la declaración de registro con una condición; por el contrario, si la declaración de registro está habilitada para la depuración, se evaluará dos veces, una en el método isDebugEnabled() y una vez en el método debug() El costo de invocar isDebugEnabled() es del orden de 5 a 30 nanosegundos, lo que debería ser insignificante para la mayoría de los fines prácticos. Por lo tanto, la opción 2 no es deseable porque contamina su código y no proporciona ninguna otra ganancia.


Como otros han mencionado, usar el enunciado de guardia solo es realmente útil si la creación de la cadena es una llamada que consume mucho tiempo. Ejemplos específicos de esto son cuando la creación de la cadena provocará una carga diferida.

Vale la pena señalar que se puede evitar este problema utilizando Simple Logging Facade para Java o (SLF4J) - http://www.slf4j.org/manual.html . Esto permite llamadas a métodos tales como:

logger.debug("Temperature set to {}. Old temperature was {}.", t, oldT);

Esto solo convertirá los parámetros pasados ​​en cadenas si la depuración está habilitada. SLF4J como su nombre lo indica es solo una fachada y las llamadas de registro se pueden pasar a log4j.

También podría muy fácilmente "hacer su propia versión" de esto.

Espero que esto ayude.


Dado que muchas personas probablemente estén viendo esta respuesta al buscar log4j2 y casi todas las respuestas actuales no consideran log4j2 o cambios recientes en ella, es de esperar que responda la pregunta.

log4j2 es compatible con Supplier s (actualmente su propia implementación, pero de acuerdo con la documentación, se planea usar la interfaz de Proveedor de Java en la versión 3.0). Puede leer un poco más sobre esto en el https://logging.apache.org/log4j/2.0/manual/api.html#Java_8_lambda_support_for_lazy_logging . Esto le permite colocar costosas creaciones de mensajes de registro en un proveedor que solo crea el mensaje si se va a registrar:

LogManager.getLogger().debug(() -> createExpensiveLogMessage());


El uso de isDebugEnabled() está reservado para cuando está creando mensajes de registro concatenando cadenas:

Var myVar = new MyVar(); log.debug("My var is " + myVar + ", value:" + myVar.someCall());

Sin embargo, en su ejemplo no hay ganancia de velocidad ya que solo está registrando una Cadena y no realizando operaciones como la concatenación. Por lo tanto, solo está agregando relleno a su código y haciendo que sea más difícil de leer.

Yo personalmente uso las llamadas al formato Java 1.5 en la clase String de esta manera:

Var myVar = new MyVar(); log.debug(String.format("My var is ''%s'', value: ''%s''", myVar, myVar.someCall()));

Dudo que haya mucha optimización, pero es más fácil de leer.

Sin embargo, tenga en cuenta que la mayoría de las API de registro ofrecen un formato como este al instante: slf4j, por ejemplo, proporciona lo siguiente:

logger.debug("My var is {}", myVar);

que es aún más fácil de leer.



En este caso particular, la Opción 1 es mejor.

El enunciado guard (comprobando isDebugEnabled() ) está ahí para prevenir el cálculo potencialmente costoso del mensaje de registro cuando involucra la invocación de los métodos toString() de varios objetos y la concatenación de los resultados.

En el ejemplo dado, el mensaje de registro es una cadena constante, por lo que dejar que el registrador lo descarte es tan eficiente como verificar si el registrador está habilitado, y reduce la complejidad del código porque hay menos ramas.

Mejor aún es usar un marco de registro más actualizado donde las instrucciones de registro tomen una especificación de formato y una lista de argumentos para ser sustituidos por el registrador, pero "de forma perezosa", solo si el registrador está habilitado. Este es el enfoque adoptado por slf4j .

Consulte mi respuesta a una pregunta relacionada para obtener más información y un ejemplo de cómo hacer algo como esto con log4j.


La opción 2 es mejor.

Per se no mejora el rendimiento. Pero asegura que el rendimiento no se degrada. Así es cómo.

Normalmente esperamos logger.debug (someString);

Pero generalmente, a medida que la aplicación crece, cambia muchas manos, especialmente los desarrolladores novatos, se puede ver

logger.debug (str1 + str2 + str3 + str4);

y similares.

Incluso si el nivel de registro está configurado en ERROR o FATAL, ¡la concatenación de cadenas ocurre! Si la aplicación contiene muchos mensajes de nivel de DEPURACIÓN con concatenaciones de cadenas, entonces ciertamente requiere un golpe de rendimiento especialmente con jdk 1.4 o menos. (No estoy seguro si las versiones posteriores de jdk internall hacen cualquier stringbuffer.append ()).

Es por eso que la Opción 2 es segura. Incluso las concatenaciones de cadenas no ocurren.


Log4j2 le permite formatear parámetros en una plantilla de mensaje, similar a String.format() , eliminando así la necesidad de hacer isDebugEnabled() .

Logger log = LogManager.getFormatterLogger(getClass()); log.debug("Some message [myField=%s]", myField);

Muestra simple log4j2.properties:

filter.threshold.type = ThresholdFilter filter.threshold.level = debug appender.console.type = Console appender.console.name = STDOUT appender.console.layout.type = PatternLayout appender.console.layout.pattern = %d %-5p: %c - %m%n appender.console.filter.threshold.type = ThresholdFilter appender.console.filter.threshold.level = debug rootLogger.level = info rootLogger.appenderRef.stdout.ref = STDOUT


Mejora la velocidad porque es común concatenar cadenas en el texto de depuración que es caro, por ejemplo:

boolean debugEnabled = logger.isDebugEnabled(); if (debugEnabled) { logger.debug("some debug text" + someState); }


Para una sola línea , uso un ternario dentro del mensaje de registro, de esta forma no hago la concatenación:

ej:

logger.debug(str1 + str2 + str3 + str4);

Hago:

logger.debug(logger.isDebugEnable()?str1 + str2 + str3 + str4:null);

Pero para múltiples líneas de código

ej.

for(Message mess:list) { logger.debug("mess:" + mess.getText()); }

Hago:

if(logger.isDebugEnable()) { for(Message mess:list) { logger.debug("mess:" + mess.getText()); } }


Recomendaría usar la Opción 2 de facto para la mayoría ya que no es muy caro.

Caso 1: log.debug ("una cadena")

Case2: log.debug ("una cadena" + "dos cadenas" + object.toString + object2.toString)

En el momento en que se llama a cualquiera de estos, se debe evaluar la cadena de parámetros dentro de log.debug (ya sea CASO 1 o Caso2). Eso es lo que todos quieren decir con "caro". Si tiene una condición antes, ''isDebugEnabled ()'', no es necesario evaluarlos, que es donde se guarda el rendimiento.


Si usa la opción 2, está haciendo una verificación booleana que es rápida. En la opción uno estás haciendo una llamada a método (empujando cosas en la pila) y luego haciendo una verificación booleana que todavía es rápida. El problema que veo es consistencia. Si algunas de sus declaraciones de depuración e información están incluidas y otras no, no es un estilo de código consistente. Además, alguien más adelante podría cambiar la declaración de depuración para incluir cadenas de concatenación, lo cual es aún bastante rápido. Descubrí que cuando completamos la declaración de depuración y de información en una aplicación grande y la perfilamos, ahorramos un par de puntos porcentuales en el rendimiento. No mucho, pero suficiente para que valga la pena el trabajo. Ahora tengo un par de configuraciones de macros en IntelliJ para generar automáticamente las declaraciones envueltas de depuración e información para mí.


Versión corta: también podría hacer la comprobación boolean isDebugEnabled ().

Razones:
1- Si la lógica complicada / string concat. se agrega a su declaración de depuración ya tendrá el cheque en su lugar.
2- No tiene que incluir selectivamente la declaración en declaraciones de depuración "complejas". Todas las declaraciones están incluidas de esa manera.
3- Llamar a log.debug ejecuta lo siguiente antes de iniciar sesión:

if(repository.isDisabled(Level.DEBUG_INT))
return;

Esto es básicamente lo mismo que llamar al registro. o gato isDebugEnabled ().

¡SIN EMBARGO! Esto es lo que piensan los desarrolladores de log4j (como lo es en su javadoc y probablemente deberías seguirlo).

Este es el método

public boolean isDebugEnabled() { if(repository.isDisabled( Level.DEBUG_INT)) return false; return Level.DEBUG.isGreaterOrEqual(this.getEffectiveLevel()); }

Este es el javadoc para él

/** * Check whether this category is enabled for the <code>DEBUG</code> * Level. * * <p> This function is intended to lessen the computational cost of * disabled log debug statements. * * <p> For some <code>cat</code> Category object, when you write, * <pre> * cat.debug("This is entry number: " + i ); * </pre> * * <p>You incur the cost constructing the message, concatenatiion in * this case, regardless of whether the message is logged or not. * * <p>If you are worried about speed, then you should write * <pre> * if(cat.isDebugEnabled()) { * cat.debug("This is entry number: " + i ); * } * </pre> * * <p>This way you will not incur the cost of parameter * construction if debugging is disabled for <code>cat</code>. On * the other hand, if the <code>cat</code> is debug enabled, you * will incur the cost of evaluating whether the category is debug * enabled twice. Once in <code>isDebugEnabled</code> and once in * the <code>debug</code>. This is an insignificant overhead * since evaluating a category takes about 1%% of the time it * takes to actually log. * * @return boolean - <code>true</code> if this category is debug * enabled, <code>false</code> otherwise. * */