Log4j with xml configuration

Like many Java developers, I use Log4j as my logging solution.

However, unlike many Java developers (in my experience anyway) I configure Log4j using xml rather than a properties file.

XML has always struck me as a neater way to represent what is essentially a hierarchical configuration.

However, it’s not terribly well documented (although the latest Log4j download comes with lots of example xml files).

Here’s an example entry from one of my xml files that sets up a daily rolling file appender appending to the existing file on startup.

    

<!-- An appender which writes to file -->
<appender name="FILE" class="org.apache.log4j.DailyRollingFileAppender">
<param name="file" value="${user.home}/conf/apache/logs/boncey_app.log" />
<param name="datePattern" value="'.'yyyy-MM" />
<param name="append" value="true" />
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d [%t] %-5p %C{6} (%F:%L) - %m%n"/>
</layout>
</appender>

Getting Tomcat to use a log4j XML file is a bit fiddly. The log4j manual explains how to set it up.

Under Tomcat 3.x and 4.x, you should place the log4j.properties under the WEB-INF/classes directory of your web-applications. Log4j will find the properties file and initialize itself. This is easy to do and it works.

However, it’s not immediately clear what to do if you use an XML file.

Dropping log4j.xml into WEB-INF/classes doesn’t work – or it didn’t for me on Tomcat 5.5.

Log4j manual to the rescue once more.

You can also choose to set the system property log4j.configuration before starting Tomcat. For Tomcat 3.x The TOMCAT_OPTS environment variable is used to set command line options. For Tomcat 4.0, set the CATALINA_OPTS environment variable instead of TOMCAT_OPTS.

So I put export CATALINA_OPTS="-Dlog4j.configuration=log4j.xml" into my shell startup scripts, dropped the log4j.xml file into my WEB-INF/classes dir and I was logging in no time!

One other thing you may find about log4j once you start using it is that lots of other Apache code uses it so once you set it up you’ll find your logs start filling up with lots (and I mean lots) of extra logging from the Apache code.

The traditional way to stop this is to add an entry as follows:


<category name="org.apache.tomcat" additivity="false">
<priority value="info" />
<appender-ref ref="FILE" />
</category>

This says that for anything logged from org.apache.tomcat, suppress anything less than INFO level, ie, suppress all DEBUG level logging.

The problem with this approach is that you have to keep adding new entries to suppress the logging from other packages too (Hibernate is a good example of this).

There is an alternative approach which is stunningly obvious once you hear it.

It is of course, better practice, to keep your application log4j.properties ROOT log level set to WARN or ERROR, and just turn on debugging for your own application classes! (ie. org.appfuse=DEBUG )

So obvious! Can’t believe I never thought of that.

So I set my base level to WARN then added “appenders” to log my own code at DEBUG level.

Voila, no more Tomcat cruft in my logs.

That concludes my ramblings on log4j and xml, hopefully they’ll be of use to someone (other than me of course).

9 thoughts on “Log4j with xml configuration”

  1. I think the CATALINA_OPTS value should be:

    export CATALINA_OPTS=”-Dlog4j.configuration=log4j.xml”

    As a file-system tidyness freak, I don’t like putting resource files in the root classes directory. Having experimented a bit, it seems that you can do something like:

    export CATALINA_OPTS=”-Dlog4j.configuration=org/boncey/config/log4j.xml”

    …allowing you to keep the config files in a neater place in the source tree.

  2. Yes, well spotted.
    I don’t know how that got in there.

    I have also found that to get it working with resin you need to edit $RESIN_HOME/bin/wrapper.pl.
    Look for the line that starts $JAVA_ARGS= and set it to say $JAVA_ARGS="-Dlog4j.configuration=./log4j.xml";
    Note the “./” in front of the file name, resin seems to need that.

  3. You can also programmatically initialize log4j with a couple lines of code:

    import org.apache.log4j.xml.DOMConfigurator;
    import org.apache.log4j.LogManager;
    InputStream input = //however you want to load the xml file.
    new DOMConfigurator().doConfigure(input, LogManager.getLoggerRepository());

    Just put it anywhere in your application initialization code. Or in a listener if you want to be neat, like Spring’s Log4jListener.

    The advantage of this approach is that it doesn’t impose one single log4j config on the entire server VM.

  4. @Jing
    Thanks for the tip.
    The only problem I have found with that approach is that you have to do it early enough to catch any startup problems.
    If anything fails before your logging code is executed you won’t get any logging for it.
    I used to do it that way and had that very problem, hence switching to dropping it into my classes directory.

  5. Darren,

    Definitely a valid concern. I usually don’t have that problem probably because I use Spring’s Log4jListener which gets executed before almost everything else – and I keep everything strictly self-contained in the web app so they won’t be touched until after the listener.

    Come to think of it, if something fails before that, shouldn’t it end up in tomcat’s default logging?

    –Jing

  6. I have a problem where only sometimes it writes to my DailyFile specified with the DailyRollingFileAppender.

    Any idea what might be the cause?

  7. Thanx for your blog. Guys using log4j + slf4j can use following dependency to resolve logging issues in addition to what has been mentioned in this blog.

    Following

    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.2</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.2</version>
    </dependency>

Leave a Reply

Your email address will not be published. Required fields are marked *