Skip to content

Writing to separate log files with Log4J

Apache Log4J is a very efficient way to manage log file entries in any java application. At a minimum, all a developer has to do is:

  1. put the Log4J jar files in the right place
  2. setup a configuration file
  3. instantiate a Logger object in the code
  4. use the available methods [^1]

This beauty of this arrangement is that log entries can be routed to a different location (console, file, database, etc.) just by changing the config file. In the case of a Java EE application, the Log4J config file can be external to it, allowing the configuration to be controlled by administrative personnel rather than software developers.

I want to discuss a particular configuration that I setup for an application I worked on. I needed to have a standard logger for the application, and a second logger that writes statistics to disk. The statistics shouldn't appear in the standard log, and the standard log entries shouldn't appear in the statistics log.

I started with this configuration:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">

<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">

    <!-- general application log file-->
    <appender name="MainLogFile" class="org.apache.log4j.FileAppender">
        <param name="File" value="server.log" />
        <param name="Threshold" value="INFO" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%-5p %t [%-40.40c] %x - %m%n" />
        </layout>
    </appender>

    <!-- stats logging -->
    <appender name="StatsLogFile" class="org.apache.log4j.FileAppender">
        <param name="File" value="stats.log" />
        <param name="Append" value="true"/>
            <param name="DatePattern" value="'.'yyyy-MM-dd"/>
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%m%n" />
        </layout>
    </appender>
    <logger name="com.myapp.mypackage.StatsLogger">
        <level value="info" />
        <appender-ref ref="StatsLogFile" />
    </logger>
    <root>
        <priority value="info" />
        <appender-ref ref="MainLogFile" />
    </root>
</log4j:configuration>

This gave me two features I wanted:

  • a log file called server.log that is rotated every night (with historical logs named server.log.[current date])
  • another log file called stats.log with similar properties

But it also gave me a feature I didn't want: the content of stats.log was showing up in server.log.

After a little bit of research, I discovered a property called additivity. It should be set to false in any logger whose output should not be added to its parent logger. Hence, my revised StatsLogger looks like this:

    <logger name="com.myapp.mypackage.StatsLogger" additivity="false">
        <level value="info" />
        <appender-ref ref="StatsLogFile" />
    </logger>

And my output is created as expected.

[^1] Typically these are: Logger.trace(), Logger.debug(), Logger.info, Logger.warn, Logger.error(), and Logger.fatal