Dans log4j, est-ce que le contrôle est désactivé avant la journalisation améliore les performances?

j'utilise Log4J dans ma demande d'enregistrement. Auparavant, j'utilisais debug call comme:

Option 1:

logger.debug("some debug text");

mais certains liens suggèrent qu'il est préférable de vérifier isDebugEnabled() d'abord, comme:

Option 2:

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

donc ma question Est " ne option 2 améliorer les performances de toute façon? ".

parce que dans tous les cas Log4J cadre ont le même contrôle pour debugEnabled. Pour l'option 2, cela pourrait être bénéfique si nous utilisons l'instruction de débogage multiple dans une seule méthode ou classe, où le framework n'a pas besoin d'appeler la méthode isDebugEnabled() plusieurs fois (sur chaque appel); dans ce cas, il appelle la méthode isDebugEnabled() une seule fois, et si Log4J est configuré pour déboguer le niveau, alors en fait il appelle la méthode isDebugEnabled() deux fois.:

  1. en cas d'attribution de valeur à la variable débugenabled, et
  2. appelé par logger.méthode debug ().

Je ne pense pas que si nous écrivons plusieurs logger.debug() déclaration dans la méthode ou la classe et appelant debug() méthode selon l'option 1 alors il est au-dessus pour le cadre Log4J par rapport à l'option 2. Puisque isDebugEnabled() est une méthode très petite (en termes de code), il pourrait être bon candidat pour inline.

163
demandé sur Michael Myers 2009-06-08 09:13:54

15 réponses

dans ce cas précis, L'Option 1 est meilleure.

l'instruction de garde (en cochant isDebugEnabled() ) est là pour empêcher le calcul potentiellement coûteux du message de journal quand il implique l'invocation des méthodes toString() de divers objets et la concaténation des résultats.

dans l'exemple donné, le message log est une chaîne constante, donc laisser l'enregistreur s'en débarrasser est tout aussi efficace que de vérifier si l'enregistreur est activé, et cela réduit la complexité du code parce qu'il y a moins de branches.

mieux encore est d'utiliser un cadre de journalisation plus à jour où les instructions de journalisation prennent une spécification de format et une liste d'arguments à remplacer par le logger-mais" paresseusement", seulement si le logger est activé. C'est l'approche adoptée par slf4j .

Voir ma réponse à une question relative à la pour plus d'informations, et un exemple de faire quelque chose comme ça avec log4j.

197
répondu erickson 2017-05-23 11:54:59

puisque dans l'option 1 la chaîne de messages est une constante, il n'y a absolument aucun gain à envelopper la déclaration de journalisation avec une condition, au contraire, si la déclaration de journalisation est activée, vous évaluerez deux fois, une fois dans la méthode isDebugEnabled() et une fois dans la méthode debug() . Le coût d'invoquer isDebugEnabled() est de l'ordre de 5 à 30 nanosecondes, ce qui devrait être négligeable pour la plupart des raisons pratiques. Par conséquent, l'option 2 n'est pas souhaitable parce qu'elle pollue votre code et ne procure aucun autre gain.

28
répondu Ceki 2011-10-10 18:40:23

utilisant le isDebugEnabled() est réservé pour quand vous construisez des messages de log en concaténant des chaînes:

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

cependant, dans votre exemple, il n'y a pas de gain de vitesse car vous enregistrez juste une chaîne et n'effectuez pas des opérations telles que la concaténation. Par conséquent, vous ajoutez simplement bloat à votre code et le rendant plus difficile à lire.

j'utilise personnellement les appels au format Java 1.5 dans la classe String comme ceci:

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

je doute qu'il y ait beaucoup d'optimisation, mais c'est plus facile à lire.

notez cependant que la plupart des API de journalisation offrent un formatage comme celui-ci: slf4j par exemple fournit ce qui suit:

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

qui est encore plus facile à lire.

13
répondu Alex 2015-03-09 10:54:01

version courte: vous pourriez aussi bien faire le booléen isDebugEnabled() check.

motifs:

1-si complexe logique / chaîne concat. est ajouté à votre déclaration de débogage que vous aurez déjà la vérification en place.

2 - vous n'avez pas à inclure sélectivement la déclaration sur les déclarations de débogage "complexes". Toutes les instructions sont incluses.

3 - l'Appel du journal.debug exécute ce qui suit avant exploitation forestière:

if(repository.isDisabled(Level.DEBUG_INT))

return;


c'est essentiellement la même chose que le journal d'appel. ou un chat. isDebugEnabled ().

cependant! C'est ce que les développeurs de log4j pensent (car c'est dans leur javadoc et vous devriez probablement y aller.)

C'est la méthode

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

c'est le javadoc pour ça

/**
*  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.
*   */
7
répondu Andrew Carr 2011-05-25 17:45:33

L'Option 2 est meilleure.

en soi, il n'améliore pas les performances. Mais cela garantit que la performance ne se dégrade pas. Voici comment.

Normalement nous attendons enregistreur.debug (someString);

mais habituellement, comme l'application se développe, change beaucoup de mains, les développeurs novices de l'esp, vous pourriez voir

logger.debug(ch1 + ch2 + str3 + str4);

et similaires.

même si le niveau de log est défini à erreur ou FATAL, la concaténation des chaînes se produit ! Si l'application contient beaucoup de messages de niveau de débogage avec des concaténations de chaîne, alors il prend certainement un coup de performance en particulier avec jdk 1.4 ou inférieur. (Je ne suis pas sûr que les versions ultérieures de JDK internall fassent un stringbuffer.annexer.))(

C'est pourquoi L'Option 2 est sûre. Même les enchaînements ne se produisent pas.

6
répondu Sathya 2009-06-08 05:21:00

comme d'autres l'ont mentionné, l'utilisation de l'instruction guard n'est vraiment utile que si la création de la chaîne est un appel qui prend du temps. Des exemples spécifiques de cela sont lorsque la création de la chaîne de caractères déclenchera un chargement paresseux.

il est intéressant de noter que ce problème peut être évité en utilisant la façade de journalisation simple pour Java ou (SLF4J) - http://www.slf4j.org/manual.html . Cela permet des appels de méthode tels que:

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

cela ne convertira les paramètres passés en chaînes que si le débogage est activé. SLF4J comme son nom l'indique n'est qu'une façade et les appels de journalisation peuvent être passés à log4j.

vous pourriez aussi très facilement" rouler votre propre " version de ceci.

Espérons que cette aide.

6
répondu Pablojim 2009-06-08 21:53:15

en Java 8, Vous n'avez pas à utiliser isDebugEnabled() pour améliorer les performances.

https://logging.apache.org/log4j/2.0/manual/api.html#Java_8_lambda_support_for_lazy_logging

import java.util.logging.Logger;
...
Logger.getLogger("hello").info(() -> "Hello " + name);
6
répondu cybaek 2018-03-23 15:08:26

comme @erickson cela dépend. Si je me souviens, isDebugEnabled est déjà construit dans la méthode debug() de Log4j.

Tant que vous ne faites pas de calculs coûteux dans vos déclarations de débogage, comme loop on objects, effectuer des calculs et concatenate strings, vous êtes très bien à mon avis.

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

serait mieux que

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());
}
3
répondu Michael Myers 2009-06-08 15:49:56

il améliore la vitesse parce qu'il est commun de concaténer des chaînes dans le texte de débogage qui est cher par exemple:

boolean debugEnabled = logger.isDebugEnabled();
if (debugEnabled) {
    logger.debug("some debug text" + someState);
}
2
répondu Tom 2009-06-08 05:18:40

For a single line , j'utilise un ternaire à l'intérieur du message de journalisation, de cette façon je ne fais pas la concaténation:

ej:

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

je n':

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

mais pour lignes multiples du code

ej.

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

je ne:

if(logger.isDebugEnable()) {
    for(Message mess:list) {
         logger.debug("mess:" + mess.getText());
    }
}
2
répondu rbeltrand 2014-10-14 16:22:15

comme beaucoup de gens regardent probablement cette réponse en cherchant log4j2 et que presque toutes les réponses actuelles ne tiennent pas compte de log4j2 ou de changements récents, cela devrait répondre à la question.

log4j2 supporte Supplier s (actuellement leur propre implémentation, mais selon la documentation il est prévu d'utiliser L'interface fournisseur de Java dans la version 3.0). Vous pouvez lire un peu plus à ce sujet dans le manuel . Cela vous permet de mettre la création de message de log coûteux dans un fournisseur qui ne crée le message si elle doit être journalisée:

LogManager.getLogger().debug(() -> createExpensiveLogMessage());
1
répondu Marcono1234 2018-03-23 15:11:36

Si vous utilisez l'option 2 vous faites un Boolean qui est rapide. Dans la première option, vous faites un appel de méthode (poussant des trucs sur la pile) et ensuite faire un contrôle booléen qui est encore rapide. Le problème que je vois est la cohérence. Si certaines de vos instructions de débogage et d'information sont emballées et que d'autres ne le sont pas, ce n'est pas un style de code cohérent. Plus quelqu'un plus tard pourrait changer la déclaration de débogage pour inclure des chaînes concaténées, ce qui est encore assez rapide. J'ai trouvé ça quand nous avons terminé debug. et info déclaration dans une grande application et profilé il nous a sauvé quelques points de pourcentage dans la performance. Pas beaucoup, mais assez pour le rendre intéressant le travail. J'ai maintenant quelques macros configurées dans IntelliJ pour générer automatiquement des instructions de débogage et d'information pour moi.

0
répondu Javamann 2009-06-08 15:35:34

au 2.x, Apache Log4j a cette vérification intégrée, donc avoir isDebugEnabled() n'est plus nécessaire. Il suffit de faire un debug() et les messages seront supprimés s'ils ne sont pas activés.

0
répondu ha9u63ar 2018-03-29 08:41:25

Log4j2 vous permet de formater des paramètres dans un modèle de message, similaire à String.format() , éliminant ainsi la nécessité de faire isDebugEnabled() .

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

échantillon simple log4j2.propriétés:

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
0
répondu Andre 2018-04-15 23:03:51

je recommande d'utiliser L'Option 2 comme de facto pour la plupart car elle n'est pas super chère.

Case 1: journal.debug("une chaîne")

Case2: journal.debug("une chaîne" + "deux cordes" + objet.toString + object2.toString)

au moment où l'un ou l'autre s'appelle, la chaîne de paramètres dans log.le débogage (QU'il s'agisse du cas 1 ou du cas 2) doit être évalué. C'est ce que tout le monde veut dire par " cher."Si vous avez une condition avant il, " isDebugEnabled ()", ceux-ci n'ont pas à être évalués qui est où la performance est sauvegardée.

-1
répondu Jolly1234 2014-07-14 22:39:25