Modifica dinamica del livello di registro log4j


127

Quali sono i diversi approcci per modificare dinamicamente il livello di log log4j, in modo che non dovrò ridistribuire l'applicazione. Le modifiche saranno permanenti in questi casi?




3
Domanda aggiornato per log4j2: stackoverflow.com/questions/23434252/...
slaadvak

1
NOTA che (quasi) tutto in questa pagina riguarda log4j, non log4j2. Tutta questa pagina è così piena di confusione e di cattiva direzione che è INUTILE. Vai a stackoverflow.com/questions/23434252/... come @slaadvak raccomanda.
Lambart,

Risposte:


86

La modifica del livello di registro è semplice; la modifica di altre parti della configurazione pone un approccio più approfondito.

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

I cambiamenti sono permanenti attraverso lo stile di vita del Logger . Alla reinizializzazione, la configurazione verrà letta e utilizzata in quanto l'impostazione del livello in fase di esecuzione non persiste la modifica del livello.

AGGIORNAMENTO: Se si utilizza Log4j 2, è necessario rimuovere le chiamate in setLevelbase alla documentazione poiché ciò può essere ottenuto tramite le classi di implementazione.

Le chiamate a logger.setLevel () o metodi simili non sono supportate nell'API. Le applicazioni dovrebbero rimuovere questi. Funzionalità equivalenti sono fornite nelle classi di implementazione di Log4j 2 ma possono lasciare l'applicazione suscettibile alle modifiche interne a Log4j 2.


5
Solo per dipendenze di runtimeLogManager.getLogger(Class.forName("org.hibernate.util.JDBCExceptionReporter")).setLevel(Level.FATAL);
CelinHC,

8
Nota che l'API log4j 2 non fornisce un metodo "setLevel".
ChrisCantrell,

5
Ma questo imposta solo il logger di root, non è vero? Se i livelli individuali sono impostati per i logger in root, l'impostazione del logger root non avrà alcun effetto su quei LOGGER. Non dovremmo fare qualcosa come root.getLoggerRepository (). GetCurrentCategories (), iterare su ogni istanza del logger e impostare LEVEL per ciascun logger? @AaronMcIver
TheMonkWhoSoldHisCode

8
@ChrisCantrell Log4j 2 fornisce un modo per farlo , anche se non è così semplice.
Coray:

2
Log4j2 può essere configurato per aggiornare la sua configurazione eseguendo la scansione del file log4j2.xml (o equivalente) a determinati intervalli. Ad esempio, <Configuration status = "warn" monitorInterval = "5" name = "tryItApp" pacchetti = "">
Kimball Robinson

89

File Watchdog

Log4j è in grado di guardare il log4j.xmlfile per le modifiche alla configurazione. Se si modifica il file log4j, log4j aggiornerà automaticamente i livelli di registro in base alle modifiche. Vedi la documentazione diorg.apache.log4j.xml.DOMConfigurator.configureAndWatch(String,long ) per i dettagli. Il tempo di attesa predefinito tra i controlli è di 60 secondi. Queste modifiche sarebbero persistenti, poiché si modifica direttamente il file di configurazione sul filesystem. Tutto quello che devi fare è invocare DOMConfigurator.configureAndWatch () una volta.

Attenzione: il metodo configureAndWatch non è sicuro per l'uso in ambienti J2EE a causa di una perdita di thread

JMX

Un altro modo per impostare il livello di log (o riconfigurare in generale) log4j è usando JMX. Log4j registra i suoi logger come MBM JMX. Utilizzando le console MBeanServer dei server applicazioni (o jconsole.exe di JDK) è possibile riconfigurare ogni singolo logger. Queste modifiche non sono persistenti e verrebbero ripristinate sulla configurazione come impostato nel file di configurazione dopo il riavvio dell'applicazione (server).

Fai da te

Come descritto da Aaron, è possibile impostare il livello di registro a livello di codice. È possibile implementarlo nell'applicazione nel modo desiderato. Ad esempio, è possibile disporre di una GUI in cui l'utente o l'amministratore modifica il livello di registro e quindi chiama i setLevel()metodi nel logger. A prescindere dal fatto che tu mantenga le impostazioni da qualche parte o meno, dipende da te.


8
Un avvertimento riguardo all'approccio watchdog di log4j: "Poiché configureAndWatch avvia un thread watchdog separato e poiché non è possibile arrestare questo thread in log4j 1.2, il metodo configureAndWatch non è sicuro per l'uso in ambienti J2EE in cui le applicazioni vengono riciclate". Riferimento: FAQ Log4J
Somu,

Se dovessi usare la funzionalità configureAndWatch di Log4j, potrei interrompere quel thread del watchdog nel metodo @PostDestroy di un EJB (è un indicatore abbastanza buono di quando il container si sta spegnendo) Tutto qui? O c'è dell'altro che mi manca ..!
Robin Bajaj,

scusa volevo dire metodo @PreDestroy
robin bajaj,

" Log4j registra i suoi logger come JMX MBeans. ". Il mio servlet utilizza log4j 1.2 Non vedo alcun logeanj MBeans.
Abdull

Tutto quello che devi fare è invocare DOMConfigurator.configureAndWatch () una volta. Come posso raggiungere questo obiettivo ?
gstackoverflow,

5

Log4j2 può essere configurato per aggiornare la sua configurazione eseguendo la scansione di log4j 2 file .xml (o equivalente) a determinati intervalli. Aggiungi semplicemente il parametro " monitorInterval " al tuo tag di configurazione. Vedere la riga 2 del file di esempio log4j 2 .xml, che indica a log4j di ripetere la scansione della sua configurazione se sono trascorsi più di 5 secondi dall'ultimo evento di registro.

<?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>

Esistono ulteriori passaggi per farlo funzionare se si sta eseguendo la distribuzione in un'istanza Tomcat, all'interno di un IDE o quando si utilizza l'avvio a molla. Sembra un po 'fuori portata qui e probabilmente merita una domanda separata.


@vsingh, stai implementando uno stivale a molla, un tomcat o un container o con un IDE? A volte ci possono essere passaggi aggiuntivi in ​​questi casi (non per colpa di log4j2) - in pratica l'app non può vedere il file cambiare perché è stato copiato in un'altra posizione da un framework o uno strumento.
Kimball Robinson,

Ciao, l'ho provato su Jboss6.4 e ho aggiornato il file di configurazione log4j2 nella posizione (all'interno del file .war) dove l'app può vedere il file. Tuttavia non ha ancora funzionato. Qualche suggerimento?
MidTierDeveloper

3

Questa risposta non ti aiuterà a cambiare dinamicamente il livello di registrazione, devi riavviare il servizio, se stai bene riavviando il servizio, usa la soluzione qui sotto

Ho fatto questo per cambiare il livello di log log4j e ha funzionato per me, non ho fatto riferimento a nessun documento. Ho usato questo valore della proprietà di sistema per impostare il nome del mio file di registro. Ho usato la stessa tecnica anche per impostare il livello di registrazione, e ha funzionato

passato questo come parametro JVM (utilizzo Java 1.7)

Siamo spiacenti, questo non cambierà dinamicamente il livello di registrazione, richiede un riavvio del servizio

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

nel file log4j.properties, ho aggiunto questa voce

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

Provai

 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

Tutto ha funzionato. spero che questo ti aiuti!

Ho queste seguenti dipendenze nel mio 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>

2
Qualunque cosa tu abbia menzionato sembra che vada bene, ma la domanda riguarda la modifica dinamica del livello di registrazione.
Azim,

Per fare ciò, è necessario riavviare il servizio. Ciò non modifica dinamicamente i livelli di registrazione.
kk.

2

Con log4j 1.x trovo che il modo migliore sia usare un DOMConfigurator per inviare una di una serie predefinita di configurazioni di log XML (diciamo, una per uso normale e una per il debug).

Fare uso di questi può essere fatto con qualcosa del genere:

  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");
    }
  }

Basta chiamarlo con il nome di configurazione appropriato e assicurarsi di inserire i modelli nel percorso di classe.


qual è il punto di partenza di questo metodo? come fa a sapere che questo metodo deve essere invocato ogni volta che c'è una modifica nella configurazione di log4j?
ASG

Non capisco ancora cosa intendi con "on demand". Puoi per favore mostrare uno snippet dove colleghi questo metodo?
chiede il

2
Ecco qua: questo è uno snippet del controller in cui lo utilizziamo. Abbiamo una pagina di amministrazione con alcuni collegamenti per riconfigurare dinamicamente la registrazione, che quindi fa OTTENERE il collegamento / admin / setLogLevel? Level = Error e quindi la rileviamo nel controller come questo @RequestMapping (value = "setLogLevel", method = RequestMethod.GET) pubblico ModelAndView setLogLevel (@RequestParam (value = "level", richiesto = true) String level) {Log4jReconfigurator.reconfigureExisting (level);
ISparkes,

Quindi, "su richiesta" significa "quando l'utente fa clic sul pulsante" nel mio caso
ISparkes

Ah, ti ho preso. Quindi la tua console di amministrazione deve fare una richiesta per invocare questo metodo.
data

0

Ho usato questo metodo con successo per ridurre la verbosità dei registri "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);

0

Per l'API log4j 2, è possibile utilizzare

Logger logger = LogManager.getRootLogger();
Configurator.setAllLevels(logger.getName(), Level.getLevel(level));

-1

Se si desidera modificare il livello di registrazione di tutti i logger, utilizzare il metodo seguente. Ciò enumererà tutti i logger e cambierà il livello di registrazione a un determinato livello. Assicurati di NON avere log4j.appender.loggerName.Threshold=DEBUGproprietà impostate nel tuo log4j.propertiesfile.

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

-3

Puoi utilizzare il seguente frammento di codice

((ch.qos.logback.classic.Logger)LoggerFactory.getLogger(packageName)).setLevel(ch.qos.logback.classic.Level.toLevel(logLevel));

Devo provarlo.
user2045474,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.