Una guida agli allegati di file a rotazione

1. Panoramica

Sebbene i file di registro spesso trasmettano informazioni utili, crescono naturalmente nel tempo e, se consentito di crescere indefinitamente, le loro dimensioni potrebbero diventare un problema.

Le librerie di registrazione risolvono questo problema utilizzando appendici di file in sequenza, che "eseguono il rollio" o archiviano automaticamente il file di registro corrente e riprendono la registrazione in un nuovo file quando si verificano determinate condizioni predefinite, prevenendo così tempi di inattività indesiderati.

In questo articolo, esploreremo come configurare i file appender in sequenza in alcune delle librerie di registrazione più utilizzate: Log4j, Log4j2 e Slf4j.

Mostreremo come eseguire il roll dei file di registro in base a dimensioni, data / ora e una combinazione di dimensioni e data / ora. Mostreremo anche come configurare ogni libreria per comprimere automaticamente e successivamente eliminare i vecchi file di log, evitandoci di scrivere noiosi codici di manutenzione.

2. La nostra applicazione di esempio

Cominciamo con un'applicazione di esempio che registra alcuni messaggi. Questo codice è basato su Log4j ma può essere facilmente modificato per funzionare con Log4j2 o Slf4j:

import org.apache.log4j.Logger; public class Log4jRollingExample { private static Logger logger = Logger.getLogger(Log4jRollingExample.class); public static void main(String[] args) throws InterruptedException { for(int i = 0; i < 2000; i++) { logger.info("This is the " + i + " time I say 'Hello World'."); Thread.sleep(100); } } }

L'applicazione è piuttosto ingenua: scrive alcuni messaggi in un ciclo, con un breve ritardo tra le iterazioni. Con 2.000 loop da eseguire e una pausa di 100 ms in ogni loop, il completamento dell'applicazione dovrebbe richiedere poco più di tre minuti.

Useremo questo esempio per dimostrare diverse funzionalità di diversi tipi di allegati di file a rotazione.

3. Rolling File Appenders in Log4j

3.1. Dipendenze di Maven

Prima di tutto, per utilizzare Log4j nella tua applicazione, aggiungi questa dipendenza al file pom.xml del tuo progetto :

 log4j log4j 1.2.17  

Per utilizzare gli allegati aggiuntivi forniti da apache-log-extras che useremo nei prossimi esempi, aggiungi la seguente dipendenza, assicurandoti di utilizzare la stessa versione che abbiamo dichiarato per Log4j al fine di garantire la piena compatibilità:

 log4j apache-log4j-extras 1.2.17  

È possibile trovare l'ultima versione di Log4j e Apache Log4j Extras su Maven Central.

3.2. Rolling basato sulla dimensione del file

In Log4j, come nelle altre librerie di registrazione, lo scorrimento dei file è delegato all'appender. Diamo un'occhiata alla configurazione per un appender di file in sequenza in Log4j che rotola in base alla dimensione del file:

Qui, abbiamo configurato Log4j per eseguire il roll del file di registro quando la sua dimensione raggiunge 5 KB, utilizzando il parametro MaxFileSize . Abbiamo anche chiesto a Log4j di conservare un massimo di due file di registro con roll utilizzando il parametro MaxBackupIndex .

Quando abbiamo eseguito la nostra applicazione di esempio, abbiamo ottenuto i seguenti file:

27/11/2016 10:28 138 app.log 27/11/2016 10:28 5.281 app.log.1 27/11/2016 10:28 5.281 app.log.2 

Quello che è successo? Log4j ha iniziato a scrivere nel file app.log . Quando la dimensione del file ha superato il limite di 5 KB, Log4j ha spostato app.log in app.log.1 , ha creato un nuovo app.log vuoto e ha continuato a scrivere nuovi messaggi di registro in app.log .

Quindi, dopo che il nuovo app.log ha superato il limite di 5 KB, questo processo a rotazione è stato ripetuto. Questa volta, app.log.1 è stato spostato in app.log.2, facendo spazio a un altro nuovo app.log vuoto .

Il processo di rollio è stato ripetuto più volte durante l'esecuzione, ma poiché abbiamo configurato il nostro appender per mantenere al massimo due file arrotolati, non c'è alcun file chiamato app.log.3 .

Quindi, abbiamo risolto uno dei problemi originali perché ora siamo in grado di impostare un limite alla dimensione dei file di registro prodotti.

D'altra parte, quando abbiamo controllato la prima riga di app.log.2 , conteneva il messaggio relativo alla 700a iterazione, il che significa che tutti i messaggi di log precedenti erano stati persi:

2016-11-27 10:28:34 INFO This is the 700 time I say 'Hello World'. 

Vediamo se riusciamo a trovare una configurazione più adatta a un ambiente di produzione, in cui la perdita dei messaggi di log non può essere considerata l'approccio migliore.

Per fare ciò utilizzeremo altri appender Log4j più potenti, flessibili e configurabili forniti in un pacchetto dedicato chiamato apache-log4j-extras .

The appenders contained in this artifact offer lots of options to fine tune the log rolling, and they introduce the distinct concepts of triggering policy and rolling policy. The triggering policy describes when a roll should occur, while the rolling policy describes how the rolling should be carried out. These two concepts are key to rolling log files and are used more or less explicitly by other libraries too, as we will soon see.

3.3. Rolling With Automatic Compression

Let's go back to the Log4j example and improve our setup by adding the automatic compression of the rolled files to save space:

With the triggering policy element, we stated that the roll should occur when the log exceeds the size of 5,120 bytes.

Within the rolling policy tag, the ActiveFileName parameter states the path of the main log files containing the latest messages and the FileNamePattern parameter specifies a template describing which should be the path of the rolled files. Let's note that this is indeed a pattern because the special placeholder %i will be replaced with the index of the rolled file.

Let's also note that FileNamePattern ends with a “.gz” extension. Whenever we use an extension associated with a supported compressed format, we will have the old rolled files compressed without any extra effort from our side.

Now when we run the application, we obtain a different set of log files:

03/12/2016 19:24 88 app.1.log.gz ... 03/12/2016 19:26 88 app.2.log.gz 03/12/2016 19:26 88 app.3.log.gz 03/12/2016 19:27 70 app.current.log 

The file app.current.log is where the last logs occurred. Previous logs have been rolled and compressed when their size reached the set limit.

3.4. Rolling Based on Date and Time

In other scenarios, you may want to configure Log4j to roll the files based on the date and time of the log messages instead of the size of the file. In a web application, for instance, you may want to have all the log messages issued in one day in the same log file.

To do that, you can use the TimeBasedRollingPolicy. With this policy, it is mandatory to specify a template for the path of the log file that contains a time-related placeholder. Each time a log message is issued, the appender verifies what the resulting log path would be, and if it differs from the last used path, then a roll will occur. Here's a quick example that configures such an appender:

3.5. Rolling Based on Size and Time

Combining the SizeBasedTriggeringPolicy and the TimeBasedRollingPolicy, you can obtain an appender that rolls based on date/time, and when the size of the file reaches the set limit, it rolls based on size too:

When we ran our application with this setup, we obtained the following log files:

03/12/2016 19:25 234 app.19-25.1481393432120.log.gz 03/12/2016 19:25 234 app.19-25.1481393438939.log.gz 03/12/2016 19:26 244 app.19-26.1481393441940.log.gz 03/12/2016 19:26 240 app.19-26.1481393449152.log.gz 03/12/2016 19:26 3.528 app.19-26.1481393470902.log

The file app.19-26.1481393470902.log is where current logging takes place. As you can see, all the logs in the interval between 19:25 and 19:26 are stored in multiple compressed log files with names starting with “app.19-25″. The “%i” placeholder is replaced by an ever increasing number.

4. Rolling File Appenders in Log4j2

4.1. Maven Dependencies

To use Log4j2 as our preferred logging library, we need to update our project's POM with the following dependency:

 org.apache.logging.log4j log4j-core 2.7 

As usual, you can find the latest version on Maven Central.

4.2. Rolling Based on File Size

Let's change our example application to use the Log4j2 logging libraries and let's explore now how we can set up file rolling based on the size of the log file in the log4j2.xml configuration file:

  %d{yyyy-MM-dd HH:mm:ss} %p %m%n       

In the Policies tag, we specified all the triggering policies we want to apply. OnStartupTriggeringPolicy triggers a roll every time the application starts, which could be useful for stand-alone applications. We then specified a SizeBasedTriggeringPolicy stating that a roll should occur whenever the log file reaches 5KB.

4.3. Rolling Based on Date and Time

Using the policies offered by Log4j2, let's set up an appender to roll and compress the log file based on time:

  %d{yyyy-MM-dd HH:mm:ss} %p %m%n    

Here the key is the use of TimeBasedTriggeringPolicy that allows us to use time-related placeholders in the template of the rolled file names. Note that since we needed only a single triggering policy, we do not have to use the Policies tag as we did in the previous example.

4.4. Rolling Based on Size and Time

As previously described, a more compelling scenario is to roll and compress log files based on both time and size. Here is an example of how we can set up Log4j2 for this task:

  %d{yyyy-MM-dd HH:mm:ss} %p %m%n             

With this configuration, we stated that a roll should occur based on time and size. The appender is able to understand what time interval we're referring to because of the pattern used for the file name, “app.%d{MM-dd-yyyy-HH-mm}.%i.log.gz”, which implicitly sets a roll to occur every minute and compresses the rolled file.

We also added a DefaultRolloverStrategy to delete old rolled files matching certain criteria. We configure ours to delete files that match the given pattern when they are older than 20 days.

4.5. Maven Dependencies

To use Log4j2 as our preferred logging library, we need to update our project's POM with the following dependency:

 org.apache.logging.log4j log4j-core 2.7 

As usual, you can find the latest version on Maven Central.

5. Rolling File Appenders in Slf4j

5.1. Maven Dependencies

When you want to use Slf4j2 with a Logback backend as logging libraries, add this dependency to your pom.xml:

 ch.qos.logback logback-classic 1.1.7 

As usual, you can find the latest version on Maven Central.

5.2. Rolling Based on File Size

Let's see now how to use Slf4j instead, with its default back-end Logback. Let's explore how we can set up file rolling in the configuration file logback.xml, which is placed in the application's classpath:

 target/slf4j/roll-by-size/app.log  target/slf4j/roll-by-size/app.%i.log.zip 1 3 1MB   5KB   %-4relative [%thread] %-5level %logger{35} - %msg%n   

Again we encounter the concept of rolling policy. The basic mechanism is the same as that used by Log4j and Log4j2. The FixedWindowRollingPolicy allows us to use an index placeholder in the name pattern of the rolled file.

When the size of the log file grows over the configured limit, a new file is allocated, and the old content is stored as the first file of the list, shifting the existing ones one place further.

5.3. Rolling Based on Time

In Slf4j, we can roll a log file based on time using the provided TimeBasedRollingPolicy. This policy allows us to specify the template name of the rolling file using time and date related placeholders:

 target/slf4j/roll-by-time/app.log  target/slf4j/roll-by-time/app.%d{yyyy-MM-dd-HH-mm}.log.zip  20 1MB   %d{yyyy-MM-dd HH:mm:ss} %p %m%n  

5.4. Rolling Based on Size and Time

If you need to roll a file both based on both time and size, you can use the provided SizeAndTimeBasedRollingPolicy. When using this policy, you must specify both a time-related placeholder and an index placeholder.

Ogni volta che la dimensione del file di registro per un determinato intervallo di tempo supera il limite di dimensione configurato, viene creato un altro file di registro con lo stesso valore per il segnaposto relativo al tempo ma con un indice incrementato:

 target/slf4j/roll-by-time-and-size/app.log   target/slf4j/roll-by-time-and-size/app.%d{yyyy-MM-dd-mm}.%i.log.zip  5KB 20 1MB   %d{yyyy-MM-dd HH:mm:ss} %p %m%n  

6. Conclusione

Come abbiamo visto, sfruttare una libreria di log per eseguire il roll dei file ti evita l'onere di gestire manualmente i file di log, permettendoti di concentrarti sullo sviluppo della tua logica aziendale. Gli allegati di file a rotazione sono uno strumento prezioso che dovrebbe essere nella cassetta degli attrezzi di ogni sviluppatore.

Come al solito, troverai i sorgenti su GitHub, dove le applicazioni di esempio presentate in questo articolo sono configurate per accedere utilizzando diverse configurazioni di rotazione diverse per consentirti di trovare una buona configurazione di base da modificare ulteriormente in base alle tue esigenze.