Log4J 2 Interoperability¶
Log4J is split into log4j-api
and log4j-core
jars:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${log4j2.version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j2.version}</version>
</dependency>
To configure GeoTools to use Log4J API:
GeoTools.setLoggerFactory("org.geotools.util.logging.Log4J2LoggerFactory");
Reference:
Log4j Guidance¶
Communication from different Logging frameworks have to Log4J 2 API:
To bridge slf4j to Log4J:
Include the following jar:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j18-impl</artifactId> <version>${log4j2.version}</version> </dependency>
This routes slf4j api calls to
log4j-core
.
To bridge java util logging to Log4J:
Include the following jar:
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jul</artifactId> <version>${log4j2.version}</version> </dependency>
This bridge provides the following mapping:
java.util.logging.Filter: yes
java.util.logging.Handler: no
Levels:
Java Level
Log4j Level
OFF
OFF
FATAL
FATAL
SEVERE
ERROR
WARNING
WARN
INFO
INFO
CONFIG
CONFIG
FINE
DEBUG
FINER
TRACE
FINEST
FINEST
ALL
ALL
There are several ways to enable
java.util.logging
bridge to Log4J:System property:
-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager
System property during application init:
System.setProperty("java.util.logging.manager","org.apache.logging.log4j.jul.LogManager");
Setup configure application
logging.properties
with the following:handlers = org.apache.logging.log4j.jul.Log4jBridgeHandler org.apache.logging.log4j.jul.Log4jBridgeHandler.propagateLevels = true
Explicitly call
Log4jBridgeHandler.install()
during application init:
Log4jBridgeHandler.install();
To bridge Log4J 1.x to Log4J (replacing the need for Reload4J):
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-1.2-api</artifactId> <version>${log4j2.version}</version> </dependency>
Reference: https://logging.apache.org/log4j/2.x/manual/migration.html
Log4j Integration¶
The following example is taken from our integration testing, this test only has Log4j 2 API in play
so GeoTools.init()` is able to unambiguously determine ``Log4JLoggerFactory
can be used.
Setup
pom.xml
with dependencies on geotools and Log4J:<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.geotools.tutorial</groupId> <artifactId>log4j</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>GeoTools Log4j Integration Example</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.deploy.skip>true</maven.deploy.skip> <geotools.version>31-SNAPSHOT</geotools.version> <log4j2.version>2.17.2</log4j2.version> </properties> <dependencies> <dependency> <groupId>org.geotools</groupId> <artifactId>gt-metadata</artifactId> <version>${geotools.version}</version> </dependency> <dependency> <groupId>org.geotools.ogc</groupId> <artifactId>net.opengis.ows</artifactId> <version>${geotools.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j2.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j2.version}</version> </dependency> <!-- java util logging logging to log4j 2 --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jul</artifactId> <version>${log4j2.version}</version> </dependency> <!-- commons logging bridge to log4j 2 --> <!-- <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-jcl</artifactId> <version>${log4j2.version}</version> </dependency> --> <!-- slf4j bridge to log4j 2 --> <!--<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j-impl</artifactId> <version>${log4j2.version}</version> </dependency> --> </dependencies> <repositories> <repository> <id>osgeo</id> <name>OSGeo Release Repository</name> <url>https://repo.osgeo.org/repository/release/</url> <snapshots><enabled>false</enabled></snapshots> <releases><enabled>true</enabled></releases> </repository> <repository> <id>osgeo-snapshot</id> <name>OSGeo Snapshot Repository</name> <url>https://repo.osgeo.org/repository/snapshot/</url> <snapshots><enabled>true</enabled></snapshots> <releases><enabled>false</enabled></releases> </repository> </repositories> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.3.0</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.11.0</version> <configuration> <source>11</source> <target>11</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-resources-plugin</artifactId> <version>3.1.0</version> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>3.1.0</version> <configuration> <executable>java</executable> <arguments> <argument>-classpath</argument> <!-- uses dependencies and build directory --> <classpath/> <argument>-Djava.awt.headless=true</argument> <argument>org.geotools.tutorial.logging.Log4JIntegration</argument> </arguments> </configuration> <executions> <execution> <id>jul</id> <phase>integration-test</phase> <goals> <goal>exec</goal> </goals> <configuration> <executable>java</executable> <arguments> <argument>-classpath</argument> <!-- uses dependencies and build directory --> <classpath/> <argument>-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager</argument> <argument>-Dlog4j2.configurationFile=log4j2-production.xml</argument> <argument>-Djava.awt.headless=true</argument> <argument>org.geotools.tutorial.logging.Log4JIntegration</argument> </arguments> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Configure log4j wtih
log4j2.xml
added tosrc/main/resources
:<?xml version="1.0" encoding="UTF-8"?> <!-- Concise Syntax --> <Configuration status="info" dest="out"> <CustomLevels> <CustomLevel name="CONFIG" intLevel="450" /> <CustomLevel name="FINEST" intLevel="700" /> </CustomLevels>> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%date{HH:mm:ss.SSS} %-6level [%logger{2}] - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="org.geotools.tutorial.logging" level="all" additivity="false"> <AppenderRef ref="Console"/> </Logger> <Logger name="org.geotools" level="debug" additivity="false"> <AppenderRef ref="Console"/> </Logger> <Root level="error"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
Of interest above is defining the CONFIG and FINEST custom levels.
During startup logback will search for
log4j2.xml
on the CLASSPATH.To search for a different file on the classpath use
-Dlog4j2.configurationFile=log4j2-production.xml
.Application
Log4JIntegration.java
startup example forsrc/min/java
.Example is taking care to call
GeoTools.init()
prior to logger use:/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2016, Open Source Geospatial Foundation (OSGeo) * * This file is hereby placed into the Public Domain. This means anyone is * free to do whatever they wish with this file. Use it well and enjoy! */ package org.geotools.tutorial.logging; import java.util.logging.Logger; import org.geotools.util.factory.GeoTools; import org.geotools.util.logging.Log4J2LoggerFactory; import org.geotools.util.logging.Logging; /** Example illustrating use of Log4J 2 API and startup environment. */ public class Log4JIntegration { static { GeoTools.init(); } static final Logger LOGGER = Logging.getLogger(Log4JIntegration.class); public static void main(String args[]) { LOGGER.info("Welcome to Log4j Integration Example"); if (!LOGGER.getClass().getName().equals("org.geotools.util.logging.Log4J2Logger")) { LOGGER.severe("Log4J2Logger expected, but was:" + LOGGER.getClass().getName()); } // Log4J2 properties LOGGER.info("Welcome to Log4j Integration Example"); checkProperty("log4j2.configurationFile"); LOGGER.config("Configuration " + Logging.ALL.lookupConfiguration()); LOGGER.finest("Everything is finest..."); LOGGER.finer("Everything is finer..."); LOGGER.fine("Everything is fine..."); LOGGER.config("Everything is configured..."); LOGGER.log(Logging.OPERATION, "Everything is operating..."); LOGGER.info("Everything is okay."); LOGGER.warning("Everything is alarming!"); LOGGER.severe("Everything is terrible!"); LOGGER.log(Logging.FATAL, "Everything has died!"); } private static void checkProperty(String property) { if (System.getProperties().containsKey(property)) { LOGGER.config(property + "=" + System.getProperty(property)); } } }
An
exec:exec
target is provided to make this easier to test:mvn exec:exec
Is the equivalent of:
java -Djava.awt.headless=true \\ org.geotools.tutorial.logging.Log4JIntegration
An
exec:exec@jul
target is provided to try out a more realistic production setting.mvn exec:exec@jul
Is the equivalent of:
java -Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager \\ -Dlog4j2.configurationFile=log4j2-production.xml \\ -Djava.awt.headless=true \\ org.geotools.tutorial.logging.Log4JIntegration
This makes use of the
log4j2-production.xml
configuration, and sets up log4j jul bridge.<?xml version="1.0" encoding="UTF-8"?> <!-- Concise Syntax --> <Configuration status="info" dest="out"> <CustomLevels> <CustomLevel name="CONFIG" intLevel="450" /> <CustomLevel name="FINEST" intLevel="700" /> </CustomLevels>> <Appenders> <Console name="Console" target="SYSTEM_OUT"> <PatternLayout pattern="%date{HH:mm:ss.SSS} %-6level [%logger{2}] - %msg%n"/> </Console> </Appenders> <Loggers> <Logger name="org.geotools" level="config" additivity="false"> <AppenderRef ref="Console"/> </Logger> <Root level="error"> <AppenderRef ref="Console"/> </Root> </Loggers> </Configuration>
This logging configuration reduces the levels recorded.