Using Apache Log4j 2 as logger for WildFly 9

Introduction

WildFly 9 comes with a lot of in-build logger, like Console, File, Size, Syslog. But if you want to use specialized loggers or other data stores (database, HDFS) you need to build a custom log handler which handles all of these things. 

In our case we wanted to use Apache Flume as log collector and Hadoop/HDSF as storage for our logs.

To use Log4j as log handler for WildFly you have to do the following steps:

  1. Write a handler which extends java.util.logging.Handler
  2. "Install" Log4j and all dependent libraries in WildFly
  3. Create a new handler in WildFly configuration and create a logj4.xml with Log4j configuration

So let’s do this step by step. You can download the code from GitHub.

Write a handler which extends java.util.logging.Handler

All custom handlers which you want to use in WildFly have to extend the abstract class java.util.logging.Handler. It is a bridge from java.util.logging to Log4j so the name of the handler is JulToLog4jHandler. 

The handler includes the following steps:

  • Initialize Log4j with the appropriate configuration. This is necessary because Log4j can not find the configuration automatically.
  • Convert the java.util.logging.Level to log4j-level
  • Create a logger and write the log data with this

The initialization is done in the constructor.

public JulToLog4jHandler() {
  ConfigurationSource source;
    
  try {
    source = new ConfigurationSource(this.getClass()
          .getClassLoader().getResourceAsStream("log4j.xml"));
    Configurator.initialize(null, source);
  } catch (IOException e) {
      e.printStackTrace();
  }
}

Since java.util.logging and Log4j have different level, a conversion is necessary.

private org.apache.logging.log4j.Level convertLeveltoLog4j(Level level) {

    if (level.equals(Level.SEVERE)) {
      return org.apache.logging.log4j.Level.ERROR;
    } else if (level.equals(Level.WARNING)) {
      return org.apache.logging.log4j.Level.WARN;
    } else if (level.equals(Level.INFO)) {
      return org.apache.logging.log4j.Level.INFO;
    } else if (level.equals(Level.FINE)) {
      return org.apache.logging.log4j.Level.DEBUG;
    } else if (level.equals(Level.FINEST)) {
      return org.apache.logging.log4j.Level.TRACE;
    } else if (level.equals(Level.OFF)) {
      return org.apache.logging.log4j.Level.OFF;
    }

    return org.apache.logging.log4j.Level.OFF;
}

Method that publish the log records to the appropriate Log4j logger.

@Override
public void publish(LogRecord record) {
  if (record.getLevel().equals(Level.OFF)) return;
    
  Logger log4j = getTargetLogger(record.getLoggerName());
  org.apache.logging.log4j.Level level = convertLeveltoLog4j(record.getLevel());
  log4j.log(level, toLog4jMessage(record), record.getThrown());
}

Create a jar file with maven by executing mvn clean package.

"Install" Log4j and all dependent libraries in WildFly

You can download the modules.zip and extract it into modules/system/layers/base under WildFly home directory or do the following steps manually.

The following steps are all done under WILDFLY_HOME/modules/system/layers/base. We assume that MODULES_BASE points to WILDFLY_HOME/modules/system/layers/base.

Install the new handler

  • Create a directory MODULES_BASE/de/bdegmbh/logging/main and copy the created jar file from step 1 in
  • Create a module.xml and insert the following
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="de.bdegmbh.logging">
  <resources>
     <resource-root path="jul2log4j-0.0.1.jar"/>
     <resource-root path="."/> 
  </resources>
    
  <dependencies>
     <module name="org.apache.logging.log4j"/>
     <module name="org.apache.flume"/>
     <module name="org.slf4j"/>
  </dependencies>
</module>
  • Create a log4j.xml in this directory with your Log4j configuration

Install Log4j

  • Create a directory MODULES_BASE/org/apache/logging/log4j/main and copy the following files in : log4j-1.2-api-2.3.jar, log4j-api-2.3.jar, log4j-core-2.3.jar, log4j-flume-ng-2.3.jar, log4j-slf4j-impl-2.3.jar
  • Create a module.xml and insert the following:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.apache.logging.log4j">
  <resources>
     <resource-root path="log4j-api-2.3.jar"/>
     <resource-root path="log4j-core-2.3.jar"/>
     <resource-root path="log4j-1.2-api-2.3.jar"/>
     <resource-root path="log4j-slf4j-impl-2.3.jar "/>
     <resource-root path="log4j-flume-ng-2.3.jar"/>    
  </resources>
  
  <dependencies>
     <module name="javax.api"/>
     <module name="org.apache.flume"/>
  </dependencies>
</module>

Since we want to use Flume we need to include the required libraries

  • Create a directory MODULES_BASE/org/apache/flume/main and copy the following files in : flume-ng-configuration-1.6.0.jar, flume-ng-core-1.6.0.jar, flume-ng-log4jappender-1.6.0.jar, flume-ng-sdk-1.6.0.jar
  • Create a module.xml and insert the following:
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="org.apache.flume">
  <resources>
     <resource-root path="flume-ng-core-1.6.0.jar"/>  
     <resource-root path="flume-ng-sdk-1.6.0.jar"/>
     <resource-root path="flume-ng-log4jappender-1.6.0.jar"/>
     <resource-root path="flume-ng-configuration-1.6.0.jar"/>            
  </resources>
  
  <dependencies>
     <module name="org.slf4j"/>
  </dependencies>
</module>

Create a new handler in WildFly configuration

The last step is to define a new custom handler in WildFly configuration via web interface or in appropriate xml file and assign it as handler for your classes.

<subsystem xmlns="urn:jboss:domain:logging:3.0">
    <console-handler name="CONSOLE">
        <level name="INFO"/>
        <formatter>
            <named-formatter name="COLOR-PATTERN"/>
        </formatter>
    </console-handler>

    <custom-handler name="LOG4J" class="de.bdegmbh.logging.jul2log4j.JulToLog4jHandler" module="de.bdegmbh.logging"/>
    .
    .
    .
</subsystem>

That's all. If you have any questions or suggestions, do not hesitate to contact us.

comments powered by Disqus