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:
- put the Log4J jar files in the right place
- setup a configuration file
- instantiate a Logger object in the code
- 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 namedserver.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