Modification dynamique du niveau de journalisation log4j

127

Quelles sont les différentes approches pour modifier dynamiquement le niveau de journalisation log4j, de sorte que je n'aurai pas à redéployer l'application. Les changements seront-ils permanents dans ces cas?

Ravi
la source
Très similaire à stackoverflow.com/questions/2115900/…
vsingh
3
Question mise à jour pour log4j2: stackoverflow.com/questions/23434252/…
slaadvak
1
Notez que (presque) tout sur cette page concerne log4j, pas log4j2. Toute cette page est tellement pleine de confusion et de mauvaise direction qu'elle est inutile. Accédez à stackoverflow.com/questions/23434252/… comme le recommande @slaadvak.
Lambart le

Réponses:

86

La modification du niveau de journalisation est simple; la modification d'autres parties de la configuration posera une approche plus approfondie.

LogManager.getRootLogger().setLevel(Level.DEBUG);

Les changements sont permanents à travers le cycle de vie du Logger. Lors de la réinitialisation, la configuration sera lue et utilisée car le réglage du niveau au moment de l'exécution ne persiste pas le changement de niveau.

MISE À JOUR: Si vous utilisez Log4j 2, vous devez supprimer les appels à setLevelselon la documentation car cela peut être réalisé via des classes d'implémentation.

Les appels à logger.setLevel () ou à des méthodes similaires ne sont pas pris en charge dans l'API. Les applications doivent les supprimer. Des fonctionnalités équivalentes sont fournies dans les classes d'implémentation de Log4j 2 mais peuvent laisser l'application vulnérable aux modifications internes de Log4j 2.

Aaron McIver
la source
5
Pour uniquement les dépendances d'exécutionLogManager.getLogger(Class.forName("org.hibernate.util.JDBCExceptionReporter")).setLevel(Level.FATAL);
CelinHC
8
Notez que l'API log4j 2 ne fournit pas de méthode "setLevel".
ChrisCantrell
5
Mais cela ne fait que définir l'enregistreur racine, n'est-ce pas? Si des niveaux individuels sont définis pour les enregistreurs sous racine, le paramétrage de l'enregistreur racine n'aura aucun effet sur ces enregistreurs. Ne devrions-nous pas faire quelque chose comme root.getLoggerRepository (). GetCurrentCategories (), itérer sur chaque instance de l'enregistreur et définir des NIVEAUX pour chaque enregistreur? @AaronMcIver
TheMonkWhoSoldHisCode
8
@ChrisCantrell Log4j 2 fournit un moyen de le faire , même si ce n'est pas aussi simple.
CorayJu
2
Log4j2 peut être configuré pour actualiser sa configuration en analysant le fichier log4j2.xml (ou équivalent) à des intervalles donnés. Par exemple, <Configuration status = "warn" monitorInterval = "5" name = "tryItApp" packages = "">
Kimball Robinson
89

Chien de garde des fichiers

Log4j est capable de surveiller le log4j.xmlfichier pour les changements de configuration. Si vous modifiez le fichier log4j, log4j actualisera automatiquement les niveaux de journal en fonction de vos modifications. Voir la documentation de org.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long) pour plus de détails. Le temps d'attente par défaut entre les vérifications est de 60 secondes. Ces modifications seraient persistantes, car vous modifiez directement le fichier de configuration sur le système de fichiers. Tout ce que vous avez à faire est d'appeler DOMConfigurator.configureAndWatch () une fois.

Attention: la méthode configureAndWatch n'est pas sûre pour une utilisation dans les environnements J2EE en raison d'une fuite de thread

JMX

Une autre façon de définir le niveau de journalisation (ou de reconfigurer en général) log4j consiste à utiliser JMX. Log4j enregistre ses enregistreurs en tant que MBeans JMX. En utilisant les consoles MBeanServer des serveurs d'applications (ou jconsole.exe de JDK), vous pouvez reconfigurer chaque enregistreur individuel. Ces modifications ne sont pas persistantes et seraient réinitialisées dans la configuration définie dans le fichier de configuration après le redémarrage de votre application (serveur).

Fait maison

Comme décrit par Aaron, vous pouvez définir le niveau de journalisation par programme. Vous pouvez l'implémenter dans votre application comme vous le souhaitez. Par exemple, vous pouvez avoir une interface graphique dans laquelle l'utilisateur ou l'administrateur modifie le niveau de journalisation, puis appelle les setLevel()méthodes sur l'enregistreur. Que vous conserviez les paramètres quelque part ou non, cela dépend de vous.

mhaller
la source
8
Un mot d'avertissement concernant l'approche du chien de garde log4j: "Étant donné que configureAndWatch lance un thread de surveillance séparé et qu'il n'y a aucun moyen d'arrêter ce thread dans log4j 1.2, la méthode configureAndWatch n'est pas sûre pour une utilisation dans les environnements J2EE où les applications sont recyclées". Référence: FAQ Log4J
Somu
Si je devais utiliser la fonctionnalité configureAndWatch de Log4j, je pourrais arrêter ce thread de surveillance dans la méthode @PostDestroy d'un EJB (c'est un assez bon indicateur du moment où le conteneur s'arrête) C'est tout? Ou y a-t-il autre chose qui me manque ..!
robin bajaj le
désolé je voulais dire méthode @PreDestroy
robin bajaj
" Log4j enregistre ses enregistreurs en tant que MBeans JMX. ". Mon servlet utilise log4j 1.2 Je ne vois aucun MBeans log4j.
Abdull
Tout ce que vous avez à faire est d'appeler DOMConfigurator.configureAndWatch () une fois. Comment puis-je atteindre cet objectif ?
gstackoverflow
5

Log4j2 peut être configuré pour actualiser sa configuration en analysant le fichier .xml log4j 2 (ou équivalent) à des intervalles donnés. Ajoutez simplement le paramètre " monitorInterval " à votre balise de configuration. Consultez la ligne 2 de l'exemple de fichier .xml log4j 2 , qui indique à log4j de réexaminer sa configuration si plus de 5 secondes se sont écoulées depuis le dernier événement de journal.

<?xml version="1.0" encoding="UTF-8" ?>
<Configuration status="warn" monitorInterval="5" name="tryItApp" packages="">

    <Appenders>
        <RollingFile name="MY_TRY_IT"
                     fileName="/var/log/tryIt.log"
                     filePattern="/var/log/tryIt-%i.log.gz">
            <Policies>
                <SizeBasedTriggeringPolicy size="25 MB"/>
            </Policies>
            ...
        </RollingFile>
    </Appenders>


    <Loggers>
        <Root level="error">
            <AppenderRef ref="MY_TRY_IT"/>
        </Root>
    </Loggers>

</Configuration>

Il existe des étapes supplémentaires pour que cela fonctionne si vous déployez sur une instance Tomcat, dans un IDE ou lorsque vous utilisez Spring Boot. Cela semble quelque peu hors de portée ici et mérite probablement une question distincte.

Kimball Robinson
la source
@vsingh, déployez-vous dans Spring Boot, Tomcat, ou dans un conteneur ou avec un IDE? Parfois, il peut y avoir des étapes supplémentaires dans ces cas (pas la faute de log4j2) - en gros, l'application ne peut pas voir le fichier changer car il a été copié vers un autre emplacement par un framework ou un outil.
Kimball Robinson
Salut, j'ai testé cela sur Jboss6.4 et j'ai mis à jour le fichier de configuration log4j2 sous l'emplacement (à l'intérieur du fichier .war) où l'application peut voir le fichier. Cependant, cela ne fonctionnait toujours pas. Toute suggestion?
MidTierDeveloper
3

Cette réponse ne vous aidera pas à changer le niveau de journalisation de manière dynamique, vous devez redémarrer le service, si vous redémarrez correctement le service, veuillez utiliser la solution ci-dessous

J'ai fait cela pour changer le niveau de journalisation de log4j et cela a fonctionné pour moi, je n'ai fait référence à aucun document. J'ai utilisé cette valeur de propriété système pour définir le nom de mon fichier journal. J'ai également utilisé la même technique pour définir le niveau de journalisation, et cela a fonctionné

passé ceci en tant que paramètre JVM (j'utilise Java 1.7)

Désolé, cela ne changera pas dynamiquement le niveau de journalisation, cela nécessite un redémarrage du service

java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java

dans le fichier log4j.properties, j'ai ajouté cette entrée

log4j.rootLogger=${logging.level},file,stdout

j'ai essayé

 java -Dlogging.level=DEBUG -cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=INFO-cp xxxxxx.jar  xxxxx.java
 java -Dlogging.level=OFF -cp xxxxxx.jar  xxxxx.java

Tout a fonctionné. J'espère que cela t'aides!

J'ai ces dépendances suivantes dans mon pom.xml

<dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
</dependency>

<dependency>
    <groupId>log4j</groupId>
    <artifactId>apache-log4j-extras</artifactId>
    <version>1.2.17</version>
</dependency>
Anandkumar
la source
2
Tout ce que vous avez mentionné semble bien, mais la question est de changer dynamiquement le niveau de journalisation.
Azim
Pour ce faire, vous devez redémarrer le service. Cela ne modifie pas les niveaux de journalisation de manière dynamique.
kk.
2

Avec log4j 1.x, je trouve que le meilleur moyen est d'utiliser un DOMConfigurator pour soumettre l'une d'un ensemble prédéfini de configurations de journaux XML (par exemple, une pour une utilisation normale et une pour le débogage).

Les utiliser peut être fait avec quelque chose comme ceci:

  public static void reconfigurePredefined(String newLoggerConfigName) {
    String name = newLoggerConfigName.toLowerCase();
    if ("default".equals(name)) {
      name = "log4j.xml";
    } else {
      name = "log4j-" + name + ".xml";
    }

    if (Log4jReconfigurator.class.getResource("/" + name) != null) {
      String logConfigPath = Log4jReconfigurator.class.getResource("/" + name).getPath();
      logger.warn("Using log4j configuration: " + logConfigPath);
      try (InputStream defaultIs = Log4jReconfigurator.class.getResourceAsStream("/" + name)) {
        new DOMConfigurator().doConfigure(defaultIs, LogManager.getLoggerRepository());
      } catch (IOException e) {
        logger.error("Failed to reconfigure log4j configuration, could not find file " + logConfigPath + " on the classpath", e);
      } catch (FactoryConfigurationError e) {
        logger.error("Failed to reconfigure log4j configuration, could not load file " + logConfigPath, e);
      }
    } else {
      logger.error("Could not find log4j configuration file " + name + ".xml on classpath");
    }
  }

Appelez-le simplement avec le nom de configuration approprié et assurez-vous de placer les modèles sur le chemin de classe.

ISparkes
la source
quel est le point de déclenchement de cette méthode? comment sait-il que cette méthode doit être invoquée chaque fois qu'il y a un changement dans la configuration de log4j?
asgs
Je n'obtiens toujours pas ce que vous entendez par «à la demande». Pouvez-vous s'il vous plaît montrer un extrait où vous connectez cette méthode?
asgs
2
Voilà: il s'agit d'un extrait du contrôleur où nous l'utilisons. Nous avons une page d'administration avec des liens pour reconfigurer dynamiquement la journalisation, qui effectue ensuite un GET vers le lien / admin / setLogLevel? Level = Error puis nous attrapons
ISparkes le
Donc, "à la demande" signifie "lorsque l'utilisateur clique sur le bouton" dans mon cas
ISparkes
Ah, je vous ai. Votre console d'administration doit donc faire une demande pour appeler cette méthode.
asgs
0

J'ai utilisé cette méthode avec succès pour réduire la verbosité des logs "org.apache.http":

ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger("org.apache.http");
logger.setLevel(Level.TRACE);
logger.setAdditive(false);
Thomas Bernardin
la source
0

Pour l'API log4j 2, vous pouvez utiliser

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));
mohamed stitane
la source
-1

Si vous souhaitez modifier le niveau de journalisation de tous les enregistreurs, utilisez la méthode ci-dessous. Cela énumérera tous les enregistreurs et changera le niveau de journalisation au niveau donné. Veuillez vous assurer que vous n'avez PAS delog4j.appender.loggerName.Threshold=DEBUG propriété définie dans votre log4j.propertiesfichier.

public static void changeLogLevel(Level level) {
    Enumeration<?> loggers = LogManager.getCurrentLoggers();
    while(loggers.hasMoreElements()) {
        Logger logger = (Logger) loggers.nextElement();
        logger.setLevel(level);
    }
}
kk.
la source
-3

Vous pouvez utiliser l'extrait de code suivant

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));
user2606570
la source
Je dois essayer.
user2045474