How to customize log4j2 RollingFileAppender?
An alternative to using the built-in lookups is to create a custom lookup. This can be accomplished in a few lines of code with a log4j2 plugin. Your custom lookup then provides the exact value you want to show in the file header at each roll over.
The plugin code would look something like this:
package com.mycompany;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.config.plugins.Plugin;
import org.apache.logging.log4j.core.lookup.AbstractLookup;
import org.apache.logging.log4j.core.lookup.StrLookup;
/**
* Looks up keys from a class SomeClass which has access to all
* information you want to provide in the log file header at rollover.
*/
@Plugin(name = "setu", category = StrLookup.CATEGORY)
public class SetuLookup extends AbstractLookup {
/**
* Looks up the value of the specified key by invoking a
* static method on SomeClass.
*
* @param event The current LogEvent (ignored by this StrLookup).
* @param key the key to be looked up, may be null
* @return The value of the specified key.
*/
@Override
public String lookup(final LogEvent event, final String key) {
return com.mycompany.SomeClass.getValue(key);
}
}
Then, in your configuration you can use the header of the pattern layout to output this at every rollover:
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz">
<!-- use custom lookups to access arbitrary internal system info -->
<PatternLayout header="${setu:key1} ${setu:key2}">
<Pattern>%d %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
The log4j2 manual has details on building/deploying custom plugins. Brief summary:
The easiest way is to build your jar with Maven; this will cause the log4j2 annotation processor to produce a binary index file in the jar so your plugin can be found quickly by log4j2.
The alternative is to specify the package name of your plugin class in your log4j2.xml configuration's packages
attribute:
<Configuration status="warn" packages="com.mycompany">
...
UPDATE: Note that in your lookup implementation you can get as creative as necessary. For example:
package com.mycompany;
public class SomeClass {
private static AtomicLong count = new AtomicLong(0);
public static String getValue(final String key) {
if (count.getAndIncrement() == 0) { // is this the first call?
return ""; // don't output a value at system startup
}
if ("FULL".equals(key)) {
// returns info to shown on rollover, nicely formatted
return fullyFormattedHeader();
}
return singleValue(key);
}
....
}
This can be accomplished with configuration. You can use the header of the pattern layout to output information. This will be included at every rollover.
<RollingFile name="RollingFile" fileName="logs/app.log"
filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}.log.gz">
<!-- use built-in lookups for system info or system properties -->
<PatternLayout header="${java:runtime} - ${java:vm} - ${java:os}">
<Pattern>%d %m%n</Pattern>
</PatternLayout>
<Policies>
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>