Guida all’esempio di Log4j2 – Configurazione, Livelli, Appenders

Benvenuti al Tutorial di Esempio di Apache Log4j2. Se chiedi a uno sviluppatore esperto quale sia la cosa più fastidiosa di un’applicazione, la risposta potrebbe essere legata al logging. Se non c’è un logging adeguato in un’applicazione, la manutenzione diventerà un incubo. La maggior parte delle applicazioni passa attraverso test di sviluppo, test di unità, test di integrazione. Ma quando si tratta di produzione, ti troverai sempre di fronte a scenari e eccezioni uniche. Quindi l’unico modo per capire cosa è successo in un caso specifico è fare il debug attraverso i log. Molti framework forniscono in qualche modo un logging predefinito, ma è sempre meglio seguire il meccanismo di logging standard del settore. Apache Log4j è uno dei framework di logging più ampiamente utilizzati. Apache Log4j 2 è la versione successiva, che è molto migliore di Log4j.

Esempio di Log4j

In questo Tutorial di Esempio di Log4j2, imparerai come iniziare con Apache Log4j2. Esploreremo anche l’architettura di Log4j2, la configurazione di log4j2, i livelli di logging di log4j2, gli appenders, i filtri e molto altro ancora.

  1. Panoramica di Log4j2
  2. Architettura di Log4j2
  3. Configurazione di Log4j2
  4. Livelli di Log4j2
  5. Ricerche di Log4j2
  6. Appenders di Log4j2
  7. Filtri di Log4j2
  8. Layout di Log4j2
  9. Quale livello di Log4j2 dovresti usare
  10. Sommario del Tutorial di Log4j2

Panoramica di Log4j2

Utilizzare l’API di logging nell’applicazione non è un lusso, ma è un must. Log4j è una libreria open source pubblicata e concessa in licenza sotto Apache Software. È possibile eseguire il debug di un’applicazione utilizzando il debug di Eclipse o altri strumenti, ma ciò non è sufficiente e fattibile in un ambiente di produzione. Il meccanismo di logging fornirà diversi vantaggi che non troverai nel normale debugging.

Category / Operation (Debugging, Logging) Debugging Logging
Human Intervention There’s a need for human intervention No need for human intervention
Persistent Medium Can’t be integrated with persistent storage Can be integrated with persistent storage (Files, Database, NoSQL database, etc.)
May used for Auditing Can’t be used for achieving auditing Can be used for achieving auditing if it’s used efficiently
Sufficient for complicated structure and flow Not sufficient; you may get lost with flow. Sufficient
Productivity Less productive More productive

Come puoi vedere sopra, l’utilizzo del meccanismo di logging sarà più efficiente con minor costo di manutenzione. Apache Log4j è lo strumento leader per il logging nelle applicazioni Java, quindi dovresti utilizzarlo.

Architettura di Log4j2

Prima di procedere con il tutorial sull’esempio di Log4j, è utile dare un’occhiata all’architettura di Log4j2. Nell’immagine sottostante sono mostrate le classi importanti nell’API di Log4j2. Ecco la spiegazione dettagliata dell’architettura mostrata sopra:

  • Le applicazioni chiederanno a LogManager un Logger con un nome specifico.

  • LogManager troverà il LoggerContext appropriato e quindi otterrà il Logger da esso.

  • Se il Logger non è ancora stato creato, verrà creato e associato a LoggerConfig secondo tre scelte di seguito:

    1. L’istanza del Logger verrà creata e associata al LoggerConfig che ha lo stesso nome. Ad esempio, App.class in getLogger(App.class) sarà valutato come una stringa com.journaldev.App. Il nome di LoggerConfig è identico al nome della classe completamente qualificato (componente software).
    2. L’istanza del Logger verrà creata e associata al LoggerConfig che ha lo stesso pacchetto genitore dei Loggers. Ad esempio, com.journaldev in getLogger("com.journaldev")
    3. L’istanza del Logger verrà creata e associata al Root LoggerConfig. Il Root LoggerConfig verrà utilizzato quando non c’è un file di configurazione o quando si sta ottenendo un logger con un nome non definito nelle dichiarazioni dei logger.
  • Gli oggetti LoggerConfig vengono creati dalla dichiarazione del Logger nel file di configurazione. LoggerConfig viene anche utilizzato per gestire gli LogEvents e delegarli ai loro Log4j2 Appenders definiti.

  • Il logger Root è un caso eccezionale, per quanto riguarda la sua esistenza. Esiste sempre e si trova in cima a qualsiasi gerarchia di logger.

  • Puoi ottenere il logger root utilizzando le seguenti istruzioni:

    Logger logger = LogManager.getLogger(LogManager.ROOT_LOGGER_NAME);
    Logger logger = LogManager.getRootLogger();
    
  • Il nome dei logger di log4j2 è sensibile alle maiuscole e minuscole.

  • Eccetto il logger root, tutti i logger possono essere ottenuti passando il loro nome a LogManager.getLogger().

  • LoggerContext è un punto focale per il sistema di logging poiché è possibile avere più LoggerContext all’interno dell’applicazione. Per ciascun LoggerContext deve essere impostata una configurazione attiva.

  • La configurazione di Log4j2 contiene tutti gli asset del sistema di logging; LoggerConfig(s), Appender(s), Filter(s) e molti altri.

  • Chiamare LogManager.getLogger() passando lo stesso nome restituirà sempre il riferimento per la stessa istanza di logger esatta.

  • La configurazione del sistema di logging viene tipicamente eseguita durante l’inizializzazione dell’applicazione. Questo può avvenire in forme diverse; in modo programmato o leggendo un file di configurazione log4j2.

Ogni logger è associato a un oggetto LoggerConfig, insieme di oggetti LoggerConfig costituiscono una gerarchia di logger. Questo concetto è noto come Gerarchia dei Logger. Gerarchia dei Logger è costituita da un insieme di oggetti LoggerConfig con una relazione genitore-figlio. L’elemento più alto in ogni Gerarchia dei Logger è il Logger Radice. Se Log4j2 non trova il file di configurazione, verrà utilizzato solo il Logger Radice per la registrazione con il livello di registrazione impostato su ERROR. Nell’immagine seguente viene mostrato il messaggio di avviso che verrà visualizzato in questo caso. Errore StatusLogger Nessun file di configurazione log4j2 trovato. Utilizzo della configurazione predefinita: registrazione solo degli errori sulla console. La tabella seguente mostra la relazione genitore-figlio nella Gerarchia dei Logger.

LoggerConfig (Is A) Root com com.journaldev com.journaldev.logging
Root X Child descendant descendant
com Parent X Child descendant
com.journaldev Ancestor Parent X Child
com.journaldev.logging Ancestor Ancestor Parent X

Per chiarire la relazione genitore-figlio, la tabella sopra va letta nel seguente modo:

  • Root è un genitore per com.
  • Root è un antenato per com.journaldev.
  • Root è un antenato per com.journaldev.logging.
  • com è un figlio per Root.
  • com è un genitore per com.journaldev.
  • com è un antenato per com.journaldev.logging.
  • com.journaldev.logging è un figlio per com.journaldev e così via.

Un’istanza di LoggerConfig è considerata un antenato di un altro LoggerConfig; se il suo nome seguito da un punto è un prefisso del nome del discendente. Un’istanza di LoggerConfig è considerata un genitore di un altro LoggerConfig; se non ci sono nomi interposti tra entrambi.

Configurazione Log4j2

Ci sono molti modi per utilizzare la configurazione di Log4j2 nella tua applicazione.

  1. Utilizzando un file di configurazione scritto in XML, JSON, YAML o file di proprietà.
  2. Programmaticamente, creando una fabbrica di configurazione e implementazione della configurazione.
  3. Programmaticamente, chiamando le API esposte nell’interfaccia di configurazione.
  4. Programmaticamente, chiamando metodi sulla classe logger interna.

Ci concentreremo principalmente sul file di configurazione. Tuttavia, è bene conoscere anche l’approccio di programmazione, nel caso in cui si desideri configurare una strategia di registrazione specifica per alcuni Logger specifici. Prima di tutto, consideriamo il caso in cui non hai fornito un file di configurazione. L’implementazione di Log4j2 assume che ci sia una variabile di sistema chiamata log4j.configurationFile per indicare la posizione del file di configurazione di log4j2.

package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class App
{
    public static void main( String[] args ) {
    	Logger logger = LogManager.getRootLogger();
    	logger.trace("Configuration File Defined To Be :: "+System.getProperty("log4j.configurationFile"));
    }
}

A simple log4j2 configuration file will look like below. configuration.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="trace">
      <AppenderRef ref="Console"/>
    </Root>
  </Loggers>
</Configuration>

Ecco la spiegazione dettagliata per il codice elencato sopra:

  • L’applicazione ha referenziato il logger radice chiamando il metodo getRootLogger di LogManager.
  • Il riferimento al logger da parte di LogManager ha avviato il sistema Log4j.
  • Log4j controllerà ispezionare la proprietà di sistema log4j.configurationFile per determinare il file di configurazione di log4j2. La configurazione di Log4j può essere scritta in JSON, YAML e XML.
  • È possibile impostare la proprietà di sistema log4j.configurationFile tramite System.setProperties("log4j.configurationFile","PERCORSO_FILE") o passandola come parametro JVM come si vede nella figura qui sotto. Notare anche il prefisso del protocollo File.

  • Nel caso in cui non sia definita nessuna proprietà di sistema, l’ordine di configurazione segue la seguente precedenza:
    • La ConfigurationFactory delle proprietà cercherà log4j2-test.properties nel classpath.
    • La ConfigurationFactory YAML cercherà log4j2-test.yamllog4j2-test.yml nel classpath.
    • La ConfigurationFactory JSON cercherà log4j2-test.jsn o log4j2-test.json nel classpath.
    • La ConfigurationFactory XML cercherà log4j2-test.xml nel classpath.
    • La ConfigurationFactory delle proprietà cercherà log4j2.properties nel classpath.
    • La ConfigurationFactory YAML cercherà log4j2.yml o log4j2.yaml nel classpath.
    • La ConfigurationFactory JSON cercherà log4j2.jsn o log4j2.json nel classpath.
    • La ConfigurationFactory XML cercherà log4j2.xml nel classpath.
    • Se non è stato fornito alcun file di configurazione, verrà utilizzata la DefaultConfiguration e ciò comporterà un insieme di comportamenti predefiniti:
      • Verrà utilizzato il logger radice.
      • Il livello del logger radice sarà impostato su ERROR.
      • Il logger radice propagherà i messaggi di log sulla console.
      • PatternLayout sarà impostato su %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n

L’utilizzo del file di configurazione log4j2 rende la configurazione log4j2 così semplice, ma vediamo come è possibile configurarla programmatically. Questo riguarda tutto l’uso di ConfigurationFactory.

package com.journaldev;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.Logger;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.LoggerConfig;
import org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory;
import org.apache.logging.log4j.core.layout.PatternLayout;
public class App
{
    public static void main( String[] args ) throws FileNotFoundException, IOException {
 
    	// Ottieni un'istanza della factory di configurazione; le opzioni disponibili sono ConfigurationFactory predefinita, XMLConfigurationFactory,
    	// YamlConfigurationFactory & JsonConfigurationFactory
    	ConfigurationFactory factory =  XmlConfigurationFactory.getInstance();
 
    	// Individua la fonte di questa configurazione, questo file individuato è un file fittizio contenente solo un tag di configurazione vuoto
    	ConfigurationSource configurationSource = new ConfigurationSource(new FileInputStream(new File("C:/dummyConfiguration.xml")));
 
    	// Ottieni un riferimento dalla configurazione
    	Configuration configuration = factory.getConfiguration(configurationSource);
 
    	// Crea un'appender console predefinito
    	ConsoleAppender appender = ConsoleAppender.createDefaultAppenderForLayout(PatternLayout.createDefaultLayout());
 
    	// Aggiungi l'appender console alla configurazione
    	configuration.addAppender(appender);
 
    	// Crea LoggerConfig
    	LoggerConfig loggerConfig = new LoggerConfig("com",Level.FATAL,false);
 
    	// Aggiungi appender
    	loggerConfig.addAppender(appender,null,null);
 
    	// Aggiungi il logger e associarlo all'istanza di LoggerConfig
    	configuration.addLogger("com", loggerConfig);
 
    	// Ottieni un'istanza del contesto
    	LoggerContext context = new LoggerContext("JournalDevLoggerContext");
 
    	// Avvia il sistema di logging
    	context.start(configuration);
 
    	// Ottieni un riferimento per il logger
    	Logger logger = context.getLogger("com");
 
    	// Log dell'evento di messaggio DEBUG
    	logger.log(Level.FATAL, "Logger Name :: "+logger.getName()+" :: Passed Message ::");
 
    	// Log dell'evento di messaggio di errore per il logger configurato come FATAL
    	logger.log(Level.ERROR, "Logger Name :: "+logger.getName()+" :: Not Passed Message ::");
 
    	// Log dell'evento di messaggio di ERRORE che sarà gestito da Root
    	logger.getParent().log(Level.ERROR, "Root Logger :: Passed Message As Root Is Configured For ERROR Level messages");
    }
}
  • Puoi utilizzare qualsiasi ConfigurationFactory fornita da Log4j2 o utilizzare quella predefinita. Abbiamo utilizzato XMLConfigurationFactory per ottenere un’istanza di ConfigurationFactory.
  • La factory ti fornirà un’istanza del riferimento di configurazione richiesta passando il file di configurazione corrispondente.
  • Un’istanza di configurazione verrà utilizzata insieme a LoggerContext per avviare il sistema di logging.
  • A console Appender has been configured and added into configuration instance with default layout. This Appender would print out messages into your console.
  • È stata creata un’istanza di LoggerConfig con il nome, il LIVELLO fornito e senza filtro utilizzato. L’appender creato verrà assegnato a questa istanza di LoggerConfig.
  • L’istanza di LoggerConfig è stata aggiunta all’istanza di configurazione.
  • A new instance of LoggerContext is created with defined name.
  • L’istanza di configurazione è stata passata per l’istanza LoggerContext e invocata start su quest’ultima.
  • A logger instance has been acquired from LoggerContext. This logger instance will be used to fire set of Log events.
  • L’istanza Logger ha generato tre eventi che verranno spiegati nella sezione Livelli di Log4j2.
  • Il logger com è configurato per stampare i messaggi il cui livello è FATAL.
  • Per default, il logger Root è configurato per stampare i messaggi il cui livello è ERROR.
  • I messaggi di ERROR non verranno registrati dal logger ‘com’ perché il suo livello è FATAL.

La stessa configurazione può essere fatta utilizzando YAML, JSON o un file di proprietà. Tuttavia la configurazione del file di proprietà di log4j2 è diversa da quella del file di proprietà di log4j, quindi assicurati di non provare a utilizzare la configurazione del file di proprietà di log4j con log4j2. Verrà generato l’errore seguente;

ERROR StatusLogger No log4j2 configuration file found. Using default configuration: logging only errors to the console.

Mentre si elabora il codice sopra, verrà generata l’output seguente:

Logger Name :: com :: Passed Message ::
00:01:27.705 [main] ERROR - Root Logger:: Passed Message As Root Is Configured For ERROR Level messages

La prima riga dei log è dal logger com e la seconda è dal Root Logger. Il messaggio di errore del logger com non viene stampato perché il suo livello è FATAL.

Livelli di Log4j2

È possibile vedere negli esempi di codice sopra che ogni volta che definiamo un LoggerConfig, forniamo anche il livello di registrazione. Per impostazione predefinita, la registrazione di log4j2 è additiva. Ciò significa che tutti i log superiori verranno utilizzati anche quando viene utilizzato un logger specifico. L’immagine seguente chiarisce questa situazione. E qui punti di chiarimento per questo:

  • Come abbiamo già detto, ogni logger è associato a un’istanza di LoggerConfig. Questo LoggerConfig è stato definito a livello di configurazione.
  • Il livello di registrazione può essere determinato a livello di LoggerConfig.
  • Puoi ottenere il logger dal suo nome, dal package genitore o puntando direttamente al Root Logger stesso.
  • Il Root Logger è il nodo di livello superiore per ogni gerarchia di LoggerConfig.
  • Una volta ottenuto il logger com.journaldev e iniziato un logEvent per la registrazione, il loggerConfig (net.journaldev) registrerà il messaggio e il messaggio sarà propagato anche nella gerarchia senza alcun rispetto per i livelli di registrazione dei genitori. Quindi l’evento di log verrà propagato ai logger com e Root e registreranno anche il messaggio rispettivamente secondo i livelli definiti.
  • Una volta ottenuto il logger com e iniziato un logEvent per la registrazione, il loggerConfig(com) registrerà il messaggio e il messaggio sarà propagato anche nella gerarchia senza alcun rispetto per i livelli di registrazione dei genitori. Cioè, il Root logger verrà propagato l’evento di log e registrerà anche il messaggio.
  • Lo stesso vale per la gerarchia net.journaldev.
  • Le prossime sezioni aggiungeranno ulteriori chiarimenti per il concetto additivo.
  • C’è la possibilità che il genitore ignori il messaggio utilizzando il concetto di filtro o impostando l’indicatore additivo su falso, quindi gli eventi di log non verranno propagati ai genitori.
  • C’è la possibilità che il logger ignori il messaggio se il livello della rispettiva configurazione del logger è MAGGIORE DEL livello degli eventi di log.

Ora, vediamo l’esempio associato al concetto di additività spiegato sopra:

import net.NetApp;
import net.journaldev.NetJournalDevApp;
import com.ComApp;
import com.journaldev.ComJournalDevApp;
public class Main {
	public static void main(String [] args){
		new ComApp();
		new ComJournalDevApp();
		new NetApp();
		new NetJournalDevApp();
	}
}
package com.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class ComJournalDevApp {
	public ComJournalDevApp(){
		Logger logger = LogManager.getLogger(ComJournalDevApp.class);
		logger.trace("COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::");
	}
}
package net;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetApp {
	public NetApp(){
		Logger logger = LogManager.getLogger(NetApp.class);
		logger.error("NET :: LEVEL :: NetApp ERROR Message ::");
	}
}
package net.journaldev;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class NetJournalDevApp {
	public NetJournalDevApp(){
		Logger logger = LogManager.getLogger(NetJournalDevApp.class);
		logger.error("NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::");
	}
}

Mentre il file di configurazione di log4j2 appare come segue:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Se viene eseguita la classe Main, troveresti i seguenti risultati:

10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.168 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.170 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
10:34:47.171 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Ecco una spiegazione dettagliata del codice elencato sopra:

  • Il file di configurazione contiene cinque istanze di loggerConfig definite e sono Root, com, com.journaldev, net & net.journaldev. Proprio come la gerarchia dei logger mostrata sopra.
  • Il livello di Root è configurato per essere ERRORE e questo è effettivamente il valore predefinito.
  • I livelli di com & com.journaldev sono configurati per essere TRACCIA.
  • I livelli di net & net.journaldev sono configurati per essere ERRORE.
  • Potresti aver notato che i messaggi dei logger ComAPP e ComJournalDevApp sono stati mostrati due e tre volte rispettivamente. Questi messaggi vengono mostrati in base alla gerarchia dei logger per ComApp & ComJournalDevApp dove si trovano rispettivamente nei pacchetti com & com.journalDev. Abbiamo un caso simile con le classi NetApp & NetJournalDevApp.
  • I genitori vengono propagati poiché l’indicatore additivo è impostato su vero per impostazione predefinita.

Lo spazio di registrazione tiene conto dei livelli degli eventi di log e del livello di loggerConfig oltre alla gerarchia del logger.

Quindi, cosa succederebbe se cambiamo il LoggerConfig per com in INFO e lasciamo il programma così com’è:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="INFO">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Il risultato sarebbe come segue:

11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.305 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.307 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
11:08:10.308 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
  • Sicuramente noterai che l’evento di log di ComAPP viene ignorato e ciò è dovuto al livello definito di loggerConfig per il pacchetto com. Il livello INFO (400) è inferiore al livello dell’evento di log che qui è TRACE (600). Quindi, il messaggio di ComApp non verrà più mostrato e per farlo apparire, è necessario modificare il livello di LoggerConfig per com in TRACE (600) o ALL (Integer.MAX_VALUE).

Per garantire che gli eventi di log siano stati visualizzati, il livello di LoggerConfig dovrebbe essere maggiore o uguale al livello dell’evento di log.

La tabella qui sotto ti mostra i livelli di log4j2 e il peso per ciascuno di essi:

LEVEL Weight
OFF 0
FATAL 100
ERROR 200
WARN 300
INFO 400
DEBUG 500
TRACE 600
ALL Integer.MAX_VALUE

Certo, la tabella sopra chiarisce molto più delle parole e ti fornisce la causa principale per cui l’evento di log TRACE non viene visualizzato mentre il livello di LoggerConfig è INFO.

Nota che la propagazione degli eventi di log nella gerarchia del logger va oltre questo calcolo e ignora i livelli.

Ma cosa succede se rimuoviamo il LoggerConfig di com.journaldev dalla configurazione e ne aggiungiamo uno nuovo per com.journaldev.logging per fare in modo che il file di configurazione appaia come segue:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

Potresti trovare più conveniente la figura qui sotto per capire cosa è successo nella configurazione log4j2 sopra. Ecco alcune delucidazioni per la figura mostrata sopra e come potrebbe influenzare il comportamento degli eventi di logging:

  • Quando gli eventi di log sono stati generati da un Logger chiamato com.journaldev.logging, il LoggerConfig associato a quel nome (cioè com.journaldev.logging) è stato usato per gestirlo e stampare il messaggio.
  • Essendo l’attributo additivo di LoggerConfig com.journaldev.logging impostato per impostazione predefinita su true, l’evento di log è stato propagato al genitore che in questo caso si riferisce a com.journaldev.
  • Essendo com.journaldev LoggerConfig non definito nella configurazione, non succede nulla e l’evento di log verrà propagato fino a com e quindi alle istanze Root LoggerConfig.
  • Com & Root riceveranno l’evento di log e lo stamperanno indipendentemente dal livello con cui è stato inviato.

Come risultato dei punti menzionati, vedresti le seguenti uscite:

14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.634 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.636 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.637 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.638 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:08:37.640 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

E potresti notare quanto segue:

  • L’evento di log nel pacchetto com viene mostrato due volte. Una per com mentre la seconda per Root.
  • Evento di registro presso com.journaldev è stato mostrato due volte. Uno per com e il secondo per Root. Anche se era tre volte prima, ma per ora il LoggerConfig di com.journaldev è assente e quindi potrebbe non esserci stato alcun registro di logging nel pacchetto com.journaldev e l’evento sarebbe stato propagato per com e Root.
  • L’evento di registro presso com.journaldev.logging è stato mostrato tre volte, una per il pacchetto com.journaldev.logging e la seconda per com e la terza per Root. Secondo la propagazione della gerarchia dei logger, dovrebbe essere visualizzato quattro volte, ma a causa dell’assenza di LoggerConfig di com.journaldev, viene visualizzato tre volte.

Nel caso in cui tu abbia definito un’istanza LoggerConfig di com.journaldev senza specificare il livello, erediterà il livello dal suo genitore.

Ma cosa succede se hai definito un LoggerConfig di com.journaldev nel tuo file di configurazione e hai tralasciato di specificare il livello del LoggerConfig. Fortunatamente, il concetto di gerarchia dei logger ti salverà qui e com.journaldev erediterà il valore del livello dal suo genitore. Di seguito è riportato un file di configurazione di esempio seguito dalla tabella per il livello di registrazione di ciascuna configurazione del logger.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>
Logger Name Assigned LoggerConfig LoggerConfig Level Logger Level
Root Root ERROR ERROR
com com TRACE TRACE
com.journaldev com TRACE TRACE
com.journaldev.logging com.journaldev.logging TRACE TRACE
  • Il pacchetto com.journaldev.logging è già associato a un LoggerConfig con livello di registrazione TRACE.
  • Il pacchetto com.journaldev è già associato a un LoggerConfig senza livello di registrazione specificato, quindi erediterà il livello di registrazione del genitore e sicuramente il valore sarà TRACE per il pacchetto com.
  • Il pacchetto com è già associato a un LoggerConfig con livello di registrazione TRACE.
  • Per default, Root ha ERROR come livello di registrazione.
  • Nel caso in cui il pacchetto com non sia dichiarato, LoggerConfig di com.journaldev erediterà il livello di registrazione di Root.

Di seguito è il risultato dell’esecuzione mentre com.journaldev eredita il livello di log di com:

14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.419 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.421 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.422 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:41:37.423 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

E di seguito il risultato se rimuovi la dichiarazione di LoggerConfig per il pacchetto com:

14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.809 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.811 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::
14:43:28.812 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Potresti notare che non sono stati registrati messaggi per com e com.journaldev, di seguito le ragioni.

  • La cancellazione di LoggerConfig associato al pacchetto com farà sì che tutti gli eventi di log menzionati in quel pacchetto vengano ignorati.
  • Dato che non è definito LoggerConfig per il pacchetto com nella configurazione, LoggerConfig associato a com.journaldev erediterà il livello di log dal suo genitore. Com non è definito e la gerarchia dei logger raggiunge il Top e si riferisce ora a Root. Il livello di log radice è ERRORE (200) e il livello di log dell’evento in com.journaldev è TRACCIA (600) – Vedi ComJournalDevApp – e secondo l’equazione definita in precedenza, il livello di LoggerConfig dovrebbe essere maggiore o uguale al Livello di Evento di Log e questo non è vero, quindi non verranno visualizzati messaggi qui per com.journaldev.

Ultimo ma non meno importante, seguendo la Tabella qui sotto ti mostra tutti gli scenari di logging possibili che potresti affrontare quando utilizzi il sistema di Logging:

X (N/A) LoggerConfig Level OFF(0) FATAL(100) ERROR(200) WARN(300) INFO(400) DEBUG(500) TRACE(600) ALL(MAX)
Event Level X X X X X X X X X
OFF(0) X YES NO NO NO NO NO NO NO
FATAL(100) X NO YES YES YES YES YES YES YES
ERROR(200) X NO NO YES YES YES YES YES YES
WARN(300) X NO NO NO YES YES YES YES YES
INFO(400) X NO NO NO NO YES YES YES YES
DEBUG(500) X NO NO NO NO NO YES YES YES
TRACE(600) X NO NO NO NO NO NO YES YES
ALL(MAX) X NO NO NO NO NO NO NO YES
  • Non c’è un metodo diretto che può essere utilizzato per lanciare eventi di log OFF/ALL.
  • Principalmente, per lanciare eventi di log OFF/ALL potresti utilizzare logger.log(Level.OFF, “Msg”) o logger.log(LEVEL.ALL, “Msg”), rispettivamente.
  • Il metodo di log è responsabile di gestire l’evento di log in base all’equazione menzionata.

Il metodo di gestione dice: se il Livello di LoggerConfig è maggiore o uguale al livello dell’evento di log, l’evento verrà accettato per ulteriore elaborazione.

L’evento di registro sarebbe accettato per ulteriore elaborazione – questo è così importante perché hai la possibilità di impedire che un evento venga gestito anche se è accettato utilizzando i Filtri Log4j2. Puoi impostare la proprietà additive su false per evitare la propagazione degli eventi di registro ai log parent. Segue di seguito lo stesso esempio che hai visto prima ma questa volta con un attributo di additività, quindi potresti notare la differenza.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
    </Console>
  </Appenders>
  <Loggers>
    <Root level="ERROR">
      <AppenderRef ref="Console"/>
    </Root>
  	<logger name="com" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="com.journaldev.logging" level="TRACE" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  	<logger name="net.journaldev" level="ERROR" additivity="false">
  		<AppenderRef ref="Console"/>
  	</logger>
  </Loggers>
</Configuration>

E il risultato dell’esecuzione sarebbe come segue:

17:55:30.558 [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
17:55:30.560 [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
17:55:30.561 [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
17:55:30.561 [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
17:55:30.562 [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

E potresti notare che non c’è propagazione degli eventi di registro ai log parent.

Log4j2 Ricerche

Idealemente, è possibile definire le ricerche come un modo in cui è possibile passare valori per il file di configurazione del Registro. Log4j2 fornisce un diverso insieme di Ricerche che possono essere utilizzate indipendentemente per impostare valori da contesti diversi:

  • Ricerca della mappa di contesto
  • Ricerca della data
  • Ricerca dell’ambiente
  • Ricerca Java
  • Ricerca JNDI
  • Ricerca degli argomenti di input JVM (JMX)
  • Ricerca degli argomenti principali
  • Ricerca della mappa
  • Ricerca dei dati strutturati
  • Ricerca delle proprietà di sistema
  • Ricerca web

Puoi fare riferimento alla documentazione di Log4j2 per ulteriori dettagli su ogni tipo di lookup, ma vediamo alcuni esempi qui per coprire i fondamenti del Lookup di Log4j2. Lookup dell’Ambiente rappresenta il modo in cui puoi passare un valore dell’ambiente (sia tramite Linux etc/profile, variabili di ambiente di sistema Windows o script di avvio per l’applicazione). Come molti di noi sanno, abbiamo la possibilità di definire un insieme di valori ambientali per l’uso dell’applicazione. Vediamo i modi più famosi per definire le variabili ambientali.

  1. Definisci la variabile d’ambiente utilizzando la funzionalità dell’ambiente Windows:
    • Fai clic destro sull’icona del tuo computer e seleziona proprietà. Dovrebbe essere visualizzata la home del pannello di controllo.
    • Fai clic su Impostazioni di sistema avanzate e poi apri la finestra delle Variabili d’ambiente.
    • Nella sezione Variabili di sistema, definisci la variabile JournalDevVar con valore JournalDev.
    • Aggiorna il PatternLayout all’interno del tuo log4j2.xml per includere la variabile appena aggiunta.

  1. Definisci le tue variabili ambientali utilizzando la struttura di avvio dello script.
    • Invece di utilizzare lo script predefinito normale, puoi utilizzare la struttura di esecuzione dello script di Eclipse IDE, fare clic sul menu Esegui e scegliere Configurazione esecuzione.
    • Naviga nella scheda Ambiente & definisci la tua variabile lì.

Osserva ora il file log4j2.xml modificato e nota l’uso delle variabili ambientali.

<Console name="Console" target="SYSTEM_OUT">
    <PatternLayout pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n"/>
</Console>

E il risultato dell’esecuzione assomiglierebbe a quanto segue:

23:57:02.511 JournalDev www.journaldev.com [main] TRACE com.ComApp - COM :: LEVEL :: ComApp TRACE Message ::
23:57:02.517 JournalDev www.journaldev.com [main] TRACE com.journaldev.ComJournalDevApp - COM :: JournalDev :: LEVEL :: ComJournalDevApp TRACE Message ::
23:57:02.520 JournalDev www.journaldev.com [main] TRACE com.journaldev.logging.ComJounralDevLoggingApp - COM :: JournalDev :: LOGGING :: LEVEL :: ComJounralDevLoggingApp TRACE Message ::
23:57:02.523 JournalDev www.journaldev.com [main] ERROR net.NetApp - NET :: LEVEL :: NetApp ERROR Message ::
23:57:02.527 JournalDev www.journaldev.com [main] ERROR net.journaldev.NetJournalDevApp - NET :: JournalDev :: LEVEL :: NetJournalDevApp ERROR Message ::

Ma potresti incontrare un piccolo problema qui e soprattutto quando stai definendo le variabili d’ambiente di un sistema operativo e si tratta della Cache di Eclipse. Idealmente, Eclipse ha memorizzato tutte le variabili di sistema quando è stato avviato e puoi trovarle tutte sotto Esegui – Configurazione di esecuzione – Scheda Ambiente – Clicca sul pulsante Seleziona. Quindi, potresti confonderti quando le hai definite ma l’Applicazione non le riconosce. Anche se riavvii il tuo Eclipse, non otterrai la soluzione e per risolverlo devi eseguire eclipse.exe -clean sulla tua installazione di Eclipse. Per assicurarti che le tue variabili d’ambiente siano definite correttamente e che il tuo sistema le trovi volentieri, puoi usare il tipo di plugin corrispondente fornito dall’API di Log4j2. Crea un’istanza di EnvironmentLookup e chiedigli di cercare una certa variabile e, se è definita, potrai trovarla facilmente.

EnvironmentLookup lookup = new EnvironmentLookup();
LogManager.getRootLogger().error(lookup.lookup("JournalDevSecondVar"));

Log4j2 Appenders

Hai visto in precedenza come utilizzare i Lookups per inserire variabili nel tuo file di configurazione. Tuttavia, potresti voler modificare il mezzo attraverso il quale passano i tuoi messaggi. Invece di utilizzare direttamente la console, potresti voler utilizzare un file o un repository di database per assicurarti che i tuoi messaggi siano conservati permanentemente. Log4j2 ha fornito molti Appenders, e potresti fare riferimento alla documentazione di Log4j2 per ottenere ulteriori dettagli sugli Appender. In modo breve, di seguito è riportato l’elenco di tutti gli Appender di Log4j2.

  1. ConsoleAppender
  2. AsyncAppender
  3. FailoverAppender
  4. FileAppender
  5. FlumeAppender
  6. JDBCAppender
  7. JMSAppender
  8. JPAAppender
  9. MemoryMappedFileAppender
  10. NoSQLAppender
  11. OutputStreamAppender
  12. RandomAccessFileAppender
  13. RewriteAppender
  14. RollingFileAppender
  15. RollingRandomAccessFileAppender
  16. RoutingAppender
  17. SMTPAppender
  18. SocketAppender
  19. SyslogAppender

I mezzi più famosi utilizzati per registrare gli eventi sono la console, il file e il database. Poiché il file salvarebbe i tuoi messaggi, il database potrebbe essere utilizzato per auditarli. A questo scopo, questa sezione si concentrerà su come JDBCAppender possa essere utilizzato efficientemente.

JDBCAppender

Il principale obiettivo di JDBCAppender è scrivere eventi di log in una tabella relazionale tramite connessioni JDBC. Non ci dilungheremo molto nell’illustrare come ottimizzare i pool di connessioni poiché questo tutorial non è destinato a tale scopo. Tuttavia, otterrai sicuramente un esempio completamente funzionale che aiuta a scrivere i tuoi eventi di log nel database. Prima di procedere, vediamo tutti i parametri necessari e una descrizione di ciascuno per configurare correttamente JDBCAppender.

Parameter Name Type Description
Name String Required, The name of the Appender
ignoreExceptions boolean Default value is set to true, making exceptions thrown to be logged also and then ignored. False value means the exception will be propagated for the caller.
filter Filter The filter that should be used to make a decision whether the log events are going to be handled by this Appender or not.
bufferSize int Default value is zero, indicating there’s no buffering have been done upon log events. Value greater than 0 would lead the Appender to buffer log events and then flush them once the buffer reaches the limit specified.
connectionSource ConnectionSource Required, the connections source from which the database connections should be retrieved.
tableName String Required, the name of the Table on which your log events should be persisted.
columnConfigs ColumnConfig[] Required, additional information may be set upon those used columns and how the data should be persisted on each of them. This can be handled with multiple <Column> elements.
Parameter Name Type Description
jndiName String Required, full prefixed JNDI name that the javax.sql.Datasource is bound to.
Parameter Name Type Description
class String Requird, The fully qualified name for a class containg a static factory method for obtaining JDBC connections.
method boolean Required, The name of the static factory method for obtaining JDBC connections.
Parameter Name Type Description
name String Required, the name of the database column
pattern String Ability to specify any legal pattern that Log event would be formatted with
literal String Ability to specify literal value in this column (i.e. SEQ.NEXTVAL)
isEventTimestamp boolean Indicating whether the event would consider Timestamp
isUnicode boolean For unicode purpose as you may refer for Log4j2 documentation for further details
isClob boolean For storing character large object, you may refer for Log4j2 documentation for further details.

Dato che sei obbligato a utilizzare JNDI, il nostro esempio configurerebbe una sorgente dati di connessione per il database Oracle e Apache Tomcat 7.

  • Se non hai installato il database Oracle nel tuo ambiente, è apprezzato se puoi farlo. Se non sei molto familiare con Oracle, ti consiglio di installare la sua Express Edition.
  • Installa Apache Tomcat 7 nel tuo ambiente.
  • Crea un progetto Maven WebApp nel tuo Eclipse.

  • Assicurati che il tuo progetto sia stato creato con successo e se noti eventuali errori nel file pom, assicurati di correggerli.
  • Aggiungi le dipendenze di Log4j2.
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-api</artifactId>
   <version>2.2</version>
</dependency>
<dependency>
   <groupId>org.apache.logging.log4j</groupId>
   <artifactId>log4j-core</artifactId>
   <version>2.2</version>
</dependency>
  • Configura il tuo contesto per includere una dichiarazione della sorgente dati MySQL. Secondo la documentazione di Apache, questo file dovrebbe trovarsi all’interno della cartella META-INF della tua applicazione Web.

<Context path="/JournalDevWebLogging"
	privileged="true" antiResourceLocking="false" antiJARLocking="false">
	<Resource name="jdbc/JournalDevDB" auth="Container"
			factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
			type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000"
			username="root" password="root" driverClassName="com.mysql.jdbc.Driver"
			url="jdbc:mysql://localhost:3306/journaldev" />
</Context>
  • Configura il tuo database e crea la tua tabella di registrazione.

CREATE TABLE `logging` (
  `EVENT_ID` int(11) NOT NULL AUTO_INCREMENT,
  `EVENT_DATE` datetime DEFAULT NULL,
  `LEVEL` varchar(45) DEFAULT NULL,
  `LOGGER` varchar(45) DEFAULT NULL,
  `MSG` varchar(45) DEFAULT NULL,
  `THROWABLE` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`EVENT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  • Configurare il tuo file log4j2.xml in modo che assomigli al seguente:
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} $${env:JournalDevVar} $${env:JournalDevSecondVar} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • Crea una risorsa Web che ti consenta di ottenere un riferimento a un logger e quindi di registrare un evento.
package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
			Logger logger = LogManager.getLogger(JournalDevServlet.class);
			logger.trace("JournalDev Database Logging Message !");
	}
}
  • Puoi opzionalmente configurare un ServletContextListener che garantisca che l’inizializzazione del data source venga eseguita correttamente.
package com.journaldev;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.logging.log4j.LogManager;
public class JournalDevServletContextListener implements ServletContextListener{
	private InitialContext context = null;
	public void contextDestroyed(ServletContextEvent event) {
	}
	public void contextInitialized(ServletContextEvent event) {
		try {
			// Ottenere il contesto iniziale
			context = new InitialContext();
			// Ottenere un riferimento al sotto-contesto env
			Context envContext = (Context)context.lookup("java:comp/env");
			// Ottenere un riferimento al sotto-contesto jdbc e quindi individuare il data source definito
			LogManager.getRootLogger().error(((Context)envContext.lookup("jdbc")).lookup("JournalDevDB"));
		} catch (NamingException e) {
			LogManager.getRootLogger().error(e);
		}
	}
}
  • Definisci il tuo Servlet all’interno del file web.xml.
  • Esegui l’applicazione e accedi al Servlet definito sopra. Vedrai i seguenti log.
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jdk1.6.0_26\bin;C:\Windows\Sun\Java\bin;C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk1.6.0_26\jre\bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin/server;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/bin;C:/Program Files/Java/jdk1.6.0_26/bin/../jre/lib/amd64;D:\OracleWebCenter\OracleWC\Oracle11g\app\oracle\product\11.2.0\server\bin;;C:\Program Files\Common Files\Microsoft Shared\Windows Live;C:\Program Files (x86)\Common Files\Microsoft Shared\Windows Live;D:\OracleDB\app\product\11.2.0\dbhome_1\bin;org.C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;D:\SpringRoo\spring-roo-1.2.5.RELEASE\bin;D:\Ant\apache-ant-1.9.2\bin;C:\Python27;C:\Program Files\Java\jdk1.6.0_26\bin;D:\Maven\apache-maven-3.2.1/bin;D:\bower-master\bin;C:\Program Files (x86)\Git\cmd;C:\Program Files\nodejs\;C:\Program Files\Microsoft Windows Performance Toolkit\;D:\Grails\grails-2.4.0\bin;D:\Gradle\gradle-2.0\bin;C:\Program Files (x86)\Windows Live\Shared;C:\Program Files\TortoiseSVN\bin;D:\Strawberry\perl\bin;D:\Strawberry\perl\site\bin;D:\Strawberry\c\bin;C:\Users\mohammad.amr\AppData\Roaming\npm;D:\JournalDev\eclipse;;.
Mar 15, 2015 2:31:41 PM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:JournalDevWebLogging' did not find a matching property.
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:41 PM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:41 PM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1020 ms
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Mar 15, 2015 2:31:41 PM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.35
14:31:43.847 [localhost-startStop-1] ERROR  - org.apache.tomcat.jdbc.pool.DataSource@10fd0a62{ConnectionPool[defaultAutoCommit=null; defaultReadOnly=null; defaultTransactionIsolation=-1; defaultCatalog=null; driverClassName=com.mysql.jdbc.Driver; maxActive=100; maxIdle=30; minIdle=10; initialSize=10; maxWait=10000; testOnBorrow=false; testOnReturn=false; timeBetweenEvictionRunsMillis=5000; numTestsPerEvictionRun=0; minEvictableIdleTimeMillis=60000; testWhileIdle=false; testOnConnect=false; password=root; url=jdbc:mysql://localhost:3306/journaldev; username=root; validationQuery=null; validatorClassName=null; validationInterval=30000; accessToUnderlyingConnectionAllowed=true; removeAbandoned=false; removeAbandonedTimeout=60; logAbandoned=false; connectionProperties=null; initSQL=null; jdbcInterceptors=null; jmxEnabled=true; fairQueue=true; useEquals=true; abandonWhenPercentageFull=0; maxAge=0; useLock=false; dataSource=null; dataSourceJNDI=null; suspectTimeout=0; alternateUsernameAllowed=false; commitOnReturn=false; rollbackOnReturn=false; useDisposableConnectionFacade=true; logValidationErrors=false; propagateInterruptState=false; }
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Mar 15, 2015 2:31:43 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Mar 15, 2015 2:31:43 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 1909 ms

Filtri Log4j2

Anche se c’è un candidato LoggerConfig per gestire l’evento Log, puoi configurarlo per negare il passaggio degli eventi Log nei back end Appenders. Ciò può essere fatto tramite un filtro log4j2. Questa sezione non è intesa a fornirti un tutorial invasivo, massiccio e enorme sull’uso dei filtri in Log4j2, poiché ne servirebbero molti per coprirne ognuno. Ma qui vedrai come utilizzare il filtro più semplice per apprendere il concetto. Uno dei filtri più semplici che puoi usare è BurstFilter che ti fornisce un meccanismo per controllare il tasso a cui vengono elaborati gli eventi Log, eliminando silenziosamente gli eventi dopo che è stato raggiunto il limite massimo. Per ora, puoi vedere qui sotto tutti i dettagli necessari per utilizzare BurstFilter.

Parameter Name Type Description
level String Level of messages to be filtered
rate float The average number of events per second to allow
maxBurst integer The maximum number of events that can occur before events are filtered for exceeding the average rate. The default is 10 times the rate.
onMatch String Action to take when filter matches. May be Accept, DENY or NEUTRAL. The default is NEUTRAL
onMismatch String Action to tale when filter doesn’t match. May be Accept, DENY or NEUTRAL. The default is NEUTRAL

Ora, guarda la posizione di BurstFilter all’interno del tuo Appender del database.

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
	<Appenders>
		<Console name="Console" target="SYSTEM_OUT">
			<PatternLayout
				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
		</Console>
		<JDBC name="databaseAppender" tableName="journaldev.logging">
			<DataSource jndiName="java:/comp/env/jdbc/JournalDevDB" />
			<BurstFilter level="TRACE" rate="20" maxBurst="2"/>
			<Column name="EVENT_DATE" isEventTimestamp="true" />
			<Column name="LEVEL" pattern="%level" />
			<Column name="LOGGER" pattern="%logger" />
			<Column name="MSG" pattern="%message" />
			<Column name="THROWABLE" pattern="%ex{full}" />
		</JDBC>
	</Appenders>
	<Loggers>
		<Root level="ERROR">
			<AppenderRef ref="Console" />
		</Root>
		<logger name="com" level="TRACE" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
		<logger name="com.journaldev" additivity="false">
			<AppenderRef ref="databaseAppender" />
		</logger>
	</Loggers>
</Configuration>
  • L’Appender del database considera il BurstFilter mentre l’Appender della console no.
  • Utilizzando il logger della console, tutti gli eventi di log verrebbero registrati, mentre l’Appender del database non lo farebbe poiché il BurstFilter ne negherebbe la registrazione.
  • Questo rifiuto degli eventi di log è ottenuto anche quando i logger utilizzati sono idonei per gestirli. Questo è molto ragionevole, come mostrato nel JournalDevServlet di seguito.

package com.journaldev;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class JournalDevServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
		Logger logger = LogManager.getLogger(JournalDevServlet.class);
		for(int i = 0 ; i < 1000 ; i++){
			logger.trace("Index :: "+i+" :: JournalDev Database Logging Message !");
			LogManager.getRootLogger().error("Index :: "+i+" :: JournalDev Database Logging Message !");
		}
	}
}

Anche se queste LoggerConfigs sono idonee per gestire gli eventi di log inviati, il filtro ha impedito che alcuni di essi venissero gestiti e quindi registrati. Puoi aggiungere questo per il concetto di Spazio di Registro per comprendere appieno il concetto di registrazione.

Layout di Log4j2

A causa dei diversi Appenders che consumano gli eventi di Log e della natura di ciascun appender, i layout sono realizzati per formare il LogEvent nel formato che soddisfa le esigenze di chiunque consumi l’evento di log. Nelle API Log4j 1.x e Logback, la trasformazione del layout degli eventi di log avveniva in una stringa, mentre i layout Log4j2 hanno considerato un modo diverso di trasformazione; e cioè trasformando il LogEvent in un array di byte. Questo nuovo tipo di trasformazione richiederebbe di configurare il Charset per garantire che l’array di byte contenga i valori corretti. È altamente consigliabile tornare al sito ufficiale di Apache Log4j2 e approfondire i Layout e i diversi tipi che Log4j2 fornisce. In questa sezione, considereremo il layout più famoso che viene sempre utilizzato dalla maggior parte dei nostri sviluppatori e di cui probabilmente avrai sentito parlare; è il PatternLayout.

Log4j2 PatternLayout

Il layout del modello è un modello stringa configurabile e flessibile mirato a formattare il LogEvent. Questo tipo di formattazione dipende dal concetto di modello di conversione. Questa sezione ti illustrerà le caratteristiche più importanti che il layout del modello fornisce. Il modello di conversione è correlato al modello di conversione che printf nel linguaggio C fornisce. Generalmente, il modello di conversione è composto da testo letterale ed espressioni di controllo del formato chiamate specificatori di conversione. La figura qui sotto ti mostra di quali parti è composto il modello di conversione: Questa figura sopra è un tentativo di semplificare il Modello di Conversione, ma è sicuramente meglio fare riferimento alla documentazione di Apache Log4j2 per ulteriori dettagli su Layout e Layout del Modello in particolare. Inoltre, puoi fare riferimento sopra agli eventi di log e vedere ogni volta quale Modello di Conversione viene utilizzato per formattare i messaggi.

Quale livello Log4j2 dovresti usare

La domanda più grande che potresti farti è quando dovrebbe essere utilizzato uno specifico livello di evento di log. Nel campo dello sviluppo, è normale utilizzare l’evento di log DEBUG mentre in produzione dovremmo utilizzare il livello INFO o WARN. La tabella qui sotto dovrebbe guidarti su quale livello di log4j2 dovrebbe essere utilizzato in quale caso.

Log Event Level When It Should Be Used
OFF When no events will be logged
FATAL When a severe error will prevent the application from continuing
ERROR When an error in the application, possibly recoverable
WARN When an event that might possible lead to an error
INFO When an event for informational purposes
DEBUG When a general debugging event required
TRACE When a fine grained debug message, typically capturing the flow through the application
ALL When all events should be logged

Riepilogo del Tutorial su Log4j2

Log4j2 è la versione rinnovata del framework di registrazione di Apache. Log4j2 ha fornito un insieme di nuove funzionalità e miglioramenti delle prestazioni rispetto a Log4j1.x. Questo tutorial su log4j2 è destinato ad aiutarti a ottenere tutto in un’unica posizione. Poiché alcuni di questi concetti non sono così facili da coprire tutti in una volta, abbiamo deciso di concentrare i nostri sforzi nell’esplicare il concetto e nell’utilizzare alcuni esempi per una maggiore chiarezza. Gli appender, i filtri, i layout e le ricerche sono soggetti a questa regola. Alcuni punti importanti Per assicurarti di essere in grado di far funzionare l’applicazione sottostante e di evitare eventuali ostacoli, verifica quanto segue:

  • Il tuo IDE Eclipse è abilitato a Maven.
  • Il tuo Apache Tomcat ha un file JAR mysql-connector all’interno della cartella lib della tua Home di Apache.
  • Sei a conoscenza di come utilizzare Maven.

Scarica il Progetto di Esempio di Apache Log4j 2

Questo è tutto per il tutorial su log4j2, spero che la maggior parte dei punti importanti siano stati coperti per farti iniziare ad utilizzare Log4j2 nella tua applicazione.

Source:
https://www.digitalocean.com/community/tutorials/log4j2-example-tutorial-configuration-levels-appenders