Configuring Log4J2
This page is dedicated to pax-logging-log4j2 backend which provides support for Log4J2 library.
Log4J2 may be configured either using properties or XML file. In theory, JSON and YAML formats are supported, but it’s not well tested.
properties file syntax to configure Log4J2 is the weirdest one in entire world.
As with Log4j1 we can configure org.ops4j.pax.logging PID using properties syntax or as with Logback we can configure it using XML syntax.
Configuration using XML
org.ops4j.pax.logging PID just needs single property:
org.ops4j.pax.logging.log4j2.config.file = /path/to/log4j2.xmlAnd then /path/to/log4j2.xml can use normal Log4J2 syntax, like this:
<Configuration id="builtin.rolling">
<Appenders>
<Console name="console">
<PatternLayout pattern="%logger/%class [%level] %message%n" />
</Console>
<RollingFile name="file" append="true">
<fileName>logs/service.log</fileName>
<filePattern>logs/service.log.%d{yyyy-MM}</filePattern>
<PatternLayout pattern="%logger/%class [%level] %mdc %message%n" />
<Policies>
<TimeBasedTriggeringPolicy />
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Logger name="my.logger" level="info" additivity="false">
<AppenderRef ref="file" />
</Logger>
<Root level="debug">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>Configuration using properties file
Source: http://logging.apache.org/log4j/2.x/manual/configuration.html#Properties
This syntax is the source of big confusion - especially if someone tries to migrate properties file from Log4J1 configuration. Apache Karaf provides template configuration file, but here’s another example. All properties must be prefixed with log4j2.
log4j2.appender.console.type = Console
log4j2.appender.console.name = console
log4j2.appender.console.layout.type = PatternLayout
log4j2.appender.console.layout.pattern = %logger/%class [%level] %message%n
log4j2.appender.file.type = File
log4j2.appender.file.name = file
log4j2.appender.file.fileName = logs/service.log
log4j2.appender.file.layout.type = PatternLayout
log4j2.appender.file.layout.pattern = %C | %M | %F | %L : [%p] %m%n
log4j2.rootLogger.level = info
log4j2.rootLogger.appenderRef.console.ref = console
log4j2.logger.my.name = my.logger
log4j2.logger.my.level = info
log4j2.logger.my.appenderRef.file.ref = file
log4j2.logger.my.additivity = falseSIFT logging
Sifting (segregating) logger can split incoming logging events and pass them to different or parameterized appenders. Segregation is done using configured key. This key is then looked up in MDC which always contains the following entries (provided by Pax Logging itself):
bundle.name - from bundle symbolic name
bundle.version - from bundle version
Other libraries may use/add other keys. Apache camel adds these, when Camel context is MDC-aware:
camel.exchangeId
camel.messageId
camel.contextId
camel.correlationId
camel.breadcrumbId
Here’s sample SIFT Logging Appender configuration in properties syntax (with explanation):
log4j2.appender.sift.name = sift
# org.apache.logging.log4j.core.appender.routing.RoutingAppender
log4j2.appender.sift.type = Routing
# org.apache.logging.log4j.core.appender.routing.Routes
log4j2.appender.sift.routes.type = Routes
log4j2.appender.sift.routes.pattern = ${ctx:my.key}
# "sift" is one of the Route elelemnts inside Routes. There's no key, thus the route is default
log4j2.appender.sift.routes.sift.type = Route
# dynamic declaration of the appender - to resolve file name using the map
log4j2.appender.sift.routes.sift.appender.type = File
log4j2.appender.sift.routes.sift.appender.name = dynamic-file
log4j2.appender.sift.routes.sift.appender.fileName = target/logs-log4j2/${ctx:my.key}-file-appender.log
log4j2.appender.sift.routes.sift.appender.layout.type = PatternLayout
log4j2.appender.sift.routes.sift.appender.layout.pattern = %c/%C [%p] %m%n
# another Route in Routes - with key "${ctx:my.key}" (thus non default from the point of view of RoutingAppender
# but actually a default from user point of view - used when there's no my.key in MDC). It's a kind of trick when
# "${ctx:my.key}" resolves back to "${ctx:my.key}" (when there's no key in MDC).
log4j2.appender.sift.routes.default.type = Route
log4j2.appender.sift.routes.default.key = ${ctx:my.key}
# static reference to appender
log4j2.appender.sift.routes.default.ref = file
# normal appender that may be referenced from logger or from the route above
log4j2.appender.file.type = File
log4j2.appender.file.name = file
log4j2.appender.file.fileName = target/logs-log4j2/default-file-appender.log
log4j2.appender.file.layout.type = PatternLayout
log4j2.appender.file.layout.pattern = %c/%C [%p] %m%n
log4j2.rootLogger.level = info
log4j2.rootLogger.appenderRef.sift.ref = siftAnd here’s XML version - this time with standard bundle.name key:
<Configuration>
<Appenders>
<Routing name="sift">
<!--
"ctx" is one of the prefixes supported by org.apache.logging.log4j.core.lookup.StrSubstitutor.variableResolver
which is org.apache.logging.log4j.core.lookup.Interpolator which maps:
strLookupMap = {java.util.HashMap@5274} size = 13
"date" -> {org.apache.logging.log4j.core.lookup.DateLookup@5319}
"ctx" -> {org.apache.logging.log4j.core.lookup.ContextMapLookup@5321}
"main" -> {org.apache.logging.log4j.core.lookup.MainMapLookup@5323}
"env" -> {org.apache.logging.log4j.core.lookup.EnvironmentLookup@5325}
"sys" -> {org.apache.logging.log4j.core.lookup.SystemPropertiesLookup@5327}
"sd" -> {org.apache.logging.log4j.core.lookup.StructuredDataLookup@5329}
"java" -> {org.apache.logging.log4j.core.lookup.JavaLookup@5331}
"marker" -> {org.apache.logging.log4j.core.lookup.MarkerLookup@5333}
"jndi" -> {org.apache.logging.log4j.core.lookup.JndiLookup@5335}
"jvmrunargs" -> {org.apache.logging.log4j.core.lookup.JmxRuntimeInputArgumentsLookup@5337}
"map" -> {org.apache.logging.log4j.core.lookup.MapLookup@5339}
"bundle" -> {org.apache.logging.log4j.core.lookup.ResourceBundleLookup@5341}
"log4j" -> {org.apache.logging.log4j.core.lookup.Log4jLookup@5343}
-->
<Routes pattern="${ctx:bundle.name}">
<Route>
<File name="file-${ctx:bundle.name}">
<fileName>logs/${ctx:bundle.name}-service.log</fileName>
<append>true</append>
<PatternLayout>
<pattern>%logger/%class [%level] %mdc %message%n</pattern>
</PatternLayout>
</File>
</Route>
</Routes>
</Routing>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="sift" />
</Root>
</Loggers>
</Configuration>Customizing Log4J2
Users are allowed to extend the functionality of Logback through mechanisms provided by Pax Logging.
Using whiteboard pattern, users may register services implementing interfaces from org.ops4j.pax.logging.spi package. PaxOsgi element is a Pax Logging special plugin for Log4J2 that maybe used wherever an appender is expected in Log4j2 configuration. Here’s sample XML configuration with comments.
<Configuration id="custom">
<Appenders>
<Console name="console">
<PatternLayout pattern="%logger/%class [%level] %message%n" />
</Console>
<!-- Will translate to "(&(objectClass=org.ops4j.pax.logging.spi.PaxAppender)(org.ops4j.pax.logging.appender.name=custom))" -->
<PaxOsgi name="custom" filter="custom" />
</Appenders>
<Loggers>
<Logger name="my.logger" level="info" additivity="false">
<AppenderRef ref="custom" />
</Logger>
<Root level="debug">
<AppenderRef ref="console" />
</Root>
</Loggers>
</Configuration>As referred to from Configuring Log4J1 and Configuring Logback, users can also extend Log4J2 using fragment bundles. Why is it needed? When Log4j2 library itself parses the configuration it has to instantiate classes for appenders, layouts, filters, … pax-logging-log4j2 itself doesn’t provide enough elements on its Import-Package manifest header, so it won’t be able to instantiate everything. That’s where fragments come into play.
https://github.com/ops4j/org.ops4j.pax.logging/tree/paxlogging-1.11.x/pax-logging-samples/fragment-log4j2is a sample fragment bundle which shows how to prepare a fragment that can:
attach to
pax-logging-log4j2bundleprovide custom filter, appender and trigger
declare them as Log4J2 plugins
In order to inform Log4J2 about new plugins, we need this POM fragment:
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>log4j2-plugin-processor</id>
<goals>
<goal>compile</goal>
</goals>
<phase>process-classes</phase>
<configuration>
<proc>only</proc>
<annotationProcessors>
<annotationProcessor>org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor</annotationProcessor>
</annotationProcessors>
</configuration>
</execution>
</executions>
</plugin>which will generated correct /META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat descriptor with cached plugin information. For example, this above fragment contains these plugins (by name):
Always- implementingorg.apache.logging.log4j.core.appender.rolling.TriggeringPolicyPaxDebug- extendingorg.apache.logging.log4j.core.filter.AbstractFilterList- extendingorg.apache.logging.log4j.core.appender.AbstractAppender
These plugins may then be used in Log4J2 configuration, simply:
log4j2.appender.l.type = List
log4j2.appender.l.name = custom-appender
log4j2.logger.my.name = my.logger
log4j2.logger.my.level = info
log4j2.logger.my.additivity = false
log4j2.logger.my.appenderRef.l.ref = custom-appender