Using Log4j 2 with WSO2 Servers

Hasitha Hiranya Abeykoon
Hasitha’s Tech Blessings
3 min readFeb 3, 2019

It is known that log4j2 has number of benefits over log4j 1.x. One of the main reasons to switch to log4j 2 is the performance in logging. Log4j 2 has async logging supported by LMAX Disruptor library. In this way actual processing of message does not need to wait until logging I/O operation happens, as it happens on a separate thread.

Unfortunately, WSO2 C4 based products are not yet powered by log4j 2. However, there are workarounds you can use. This post narrates how you can enable log4j 2 for WSO2 C4 based products for custom extensions.

More details on the carbon logging framework of Carbon C4 can be found at Monitoring Logs section in WSO2 Official Documentation. You can expect log4j 2 support in upcoming WSO2 products as it is incorporated in C5 carbon framework on which future products are based on.

Log4j 2 Uber jar file

As WSO2 Carbon framework is built by a set of OSGI components, we can use log4j 2 even while the underlying framework uses log4j 1.x. For that we need to make a Log4J2 uber jar to package Log4J2 and its required dependencies.

Let us see how this can be done.

  1. Create a maven project containing a pom.xml and a java class for the Activator
package org.wso2.carbon.log4j2.internal;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;

public class CarbonLog4J2Activator implements BundleActivator {
private static final Logger logger =
LogManager.getLogger(CarbonLog4J2Activator.class);

public void start(BundleContext bundleContext)
throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Carbon Log4J2 bundle is activated.");
}
}

public void stop(BundleContext bundleContext)
throws Exception {
//do nothing
}
}

2. Use Maven Shade plugin to create the uber jar with the dependencies for log4j2. Make sure to export ONLY org.apache.logging.log4j.* when OSGI bundle is created using maven-bundle-plugin plugin.

<build>        
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>
${project.artifactId}
</Bundle-SymbolicName>
<Bundle-Name>${project.artifactId}</Bundle-Name>
<Import-Package>
org.osgi.framework.*,
org.osgi.service.*

</Import-Package>
<Export-Package>
org.apache.logging.log4j.*
</Export-Package>
<Bundle-Activator>
org.wso2.carbon.log4j2.internal.CarbonLog4J2Activator
</Bundle-Activator>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi</artifactId>
<version>3.9.1.v20130814-1242</version>
</dependency>
<dependency>
<groupId>org.eclipse.osgi</groupId>
<artifactId>org.eclipse.osgi.services</artifactId>
<version>3.3.100.v20130513-1956</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>

<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>

</dependencies>

3. When the project is complied, you will get a jar file, let’s name it as log4j2-core-apiv2.11.1–1.0.0.jar

You can refer to complete Uber jar project for log4j 2 by WSO2 Engineer Asma Zinneera Jabir.

Using log4j 2 in a product

Let us take WSO2 EI 6.4.0 as the example here. In simple terms, this product has the ability to mediate messages and transform messages across different services.

  • We can write a custom class mediator (an extension for WSO2 EI mediation engine) as below to log a custom message.
package org.wso2.carbon.test;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;
public class SimpleClassMediator extends AbstractMediator {private static final Logger logger = LogManager.getLogger(SimpleClassMediator.class);public SimpleClassMediator(){}public boolean mediate(MessageContext mc) {
// Do something useful..
logger.info(“Simple Class Mediator.This line is logged byLog4J2“);
return true;
}
}
  • Modify pom.xml file of this project to import org.apache.logging.log4j.* and export only the classes related to the Class Mediator using maven-bundle-plugin.
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>1.4.0</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>
org.wso2.carbon.test
</Bundle-SymbolicName>
<Bundle-Name>org.wso2.carbon.test</Bundle-Name>
<Export-Package>
org.wso2.carbon.test.*,
</Export-Package>
<Import-Package>
org.apache.logging.log4j.*,
*; resolution:=optional
</Import-Package>
</instructions>
</configuration>
</plugin>
  • Add log4j-core and log4j-api dependencies to the project as well using maven dependency plugins.
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.11.1</version>
</dependency>
  • Compile above class to a jar file. More about writing custom class mediators can be found here. You can also use WSO2 EI tooling to write the class mediator within minutes. Let’s consider this jar file to be mediator-1.0-SNAPSHOT.jar

You can refer to complete mediator project by WSO2 Engineer Asma Zinneera Jabir.

Deployment and configuration for EI server

You need to do following changes to WSO2 EI server copy to enable log4j2.

  • Copy above mediator-1.0-SNAPSHOT.jar into <EI_HOME>/dropins folder.
  • Download log4j2-core-apiv2.11.1–1.0.0.jar from here and copy it to <EI_HOME>/dropins folder.
  • Copy below log4j2.xml to <EI_HOME>/conf
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
<Appenders>
<Console name="CARBON_CONSOLE" target="SYSTEM_OUT">
<PatternLayout pattern="[%d] %5p {%c} - %m%ex%n"/>
</Console>
<RollingFile name="CARBON_LOGFILE" fileName="${sys:carbon.home}/repository/logs/carbon.log"
filePattern="${sys:carbon.home}/logs/carbon-%d{MM-dd-yyyy}.log">
<PatternLayout pattern="[%d] %5p {%c} - %m%ex%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="CARBON_CONSOLE"/>
<AppenderRef ref="CARBON_LOGFILE"/>
</Root>
<!--<Logger name="org.wso2.carbon.kernel" level="debug"/>-->
<Logger name="org.hibernate.validator" level="error"/>
</Loggers>
</Configuration>
  • Set the system property for log4j2 configuration (copied above) by adding the following line to <EI_HOME>/bin/integrator.sh
-Dlog4j.configurationFile="$CARBON_HOME/conf/log4j2.xml" \
  • Include this class mediator to an API/Proxy service in WSO2 EI and check for the log line printed by org.wso2.carbon.test.SimpleClassMediator in the Carbon Console and the <PRODUCT_HOME>/repository/logs/carbon.log file.

--

--