Home > java > How to configure log4j for a web app

How to configure log4j for a web app

server logI often see environments where web applications use log4j for logging into files using various appenders. That is all well and good until I see that the logs are getting written into the application server’s logs. In JBOSS for example this is server.log. So why is this a bad idea ?

Why not to write into server.log:

  1. An application server’s log is supposed to be used by the app server and not by your application.
  2. This log is supposed to contain app server level information like loading war files / exceptions that were handed over to the container etc.
  3. Weeding through the logs of about 10 applications to find a particular debug / error line is going to be crazy.
  4. A PROD logging configuration should never have a console appender. The reason your application logs are getting logged into the server’s logs could be that your log4j configuration defines a console appender. This could mean you are logging the same thing in 2 places (assuming there is another file appender defined for your app).

Ideally each application should manage its own logging needs. Many developers seem to be unaware of a class named DomConfigurator in the log4j API that can load a log4j XML and configure it for your application. Here are the steps I usually take to prepare an application for logging

  1. Write a custom class that implements ServletContextListener like the one shown below. The class looks for a context param named log4jFileName that is defined in web.xml. This locates the log4j XML configuration file. This will configure log4j before other classes use it.

Custom listener:

public class StartupListener implements ServletContextListener
{
    @Override
    public void contextDestroyed(ServletContextEvent arg0)
    {
        // Cleanup code goes here
    }
 
    @Override
    public void contextInitialized(ServletContextEvent sce)
    {
        Logger logger = null;
        ServletContext servletContext = sce.getServletContext();
        String log4jFile = servletContext.getInitParameter("log4jFileName");
        DOMConfigurator.configure(log4jFile);
        logger = LogManager.getLogger(StartupListener.class.getName());
        logger.debug("Loaded: " + log4jFile);
    }
}

2. In your web.xml define the listener and a context param like so

Web.xml entries:

<context-param>
    <param-name>log4jFileName</param-name>
    <param-value>
         /usr/local/app/log4j/config/log4jConfig.xml
    </param-value>
</context-param>
 
<listener>
    <listener-class>
        com.yourpackage.YourListener
    </listener-class>
</listener>

3. Now configure your log4jConfig.xml appropriately to ensure that your application logs are logged under an appropriate path. Use a file appender like RollingFileAppender to handle the retention policy for your applications.

Here is a sample log4j XML to help you

Sample log4j XML: (Customize as necessary)

<?xml version="1.0" encoding="UTF-8"?>
<log4j:configuration xmlns:log4j = "http://jakarta.apache.org/log4j/" debug = "false">
    <appender name = "FILE" class = "org.apache.log4j.RollingFileAppender">
        <param name = "File" value = "/usr/local/path/to/application.log"/>
        <param name = "MaxFileSize" value = "5MB"/>
        <param name = "MaxBackupIndex" value = "50"/>
        <layout class = "org.apache.log4j.PatternLayout">
            <param name = "ConversionPattern" value = "[%d{dd/MM/yy hh:mm:ss:sss z}] %5p %c{2}: %m%n"/>
        </layout>
    </appender>
    <category name = "com.your.application.package">
        <priority value = "debug"/>
    </category>
    <category name = "org.apache.catalina">
        <priority value = "error"/>
    </category>
    <category name = "org.hibernate">
        <priority value = "error"/>
    </category>
    <root>
        <priority value = "info"/>
        <appender-ref ref = "FILE"/>
    </root>
</log4j:configuration>

That is pretty much it. This will ensure that your application’s logs are logged elsewhere from the server’s own logs. Makes managing log files a little easier.





Categories: java Tags: , ,
  1. May 7th, 2010 at 16:29 | #1

    looks exactly like the stuff i recently blogged about:

    http://blog.nofail.de/2010/04/taming-webapp-logging-with-log4j/

  2. May 8th, 2010 at 03:38 | #2

    @phoet

    Your method seems similar except for the fact that you use ‘configure and watch’ and do not use a context param. The JMX extension approach is interesting but is not practical. I would not expect logging to be a managed extension that can have changes at runtime.

    Yes, we are talking about trying to improve the standard and thus about the same thing. But if you are implying that I tried to copy the idea of your standard, you are way off. I know several projects that use these standards before either of these blog entries were ever written.

  3. June 14th, 2010 at 09:15 | #3

    Good suggestion.

    Does this approach have advantages over using a custom init servlet, as described in the Ant 1.2 manual @ http://logging.apache.org/log4j/1.2/manual.html ?

  4. June 14th, 2010 at 09:43 | #4

    @Vladimir Dzhuvinov

    The Init servlet is also an option as well. It comes down to a matter of preference I guess. I usually choose a listener over an init servlet since I believe they are easier to spot.

  5. June 14th, 2010 at 17:31 | #5

    @CertPal
    Thank you. Today I implemented your suggestion my current web app project, a JSON-RPC service. Implementing the listener interface was simpler to code and also seems semantically more correct than using a custom init servlet.

  6. June 15th, 2010 at 07:47 | #6

    @Vladimir Dzhuvinov

    That’s great to hear ! Have a nice day.

  7. June 29th, 2010 at 18:04 | #7

    CertPal :
    But if you are implying that I tried to copy the idea of your standard

    no, that was not my intention. i just wanted to link to my post ;-)

  8. June 30th, 2010 at 04:12 | #8

    @phoet

    hahaha ! ok. The down vote plus the comment seemed like a subtle message to me.

    Cheers

  9. Albert
    December 24th, 2011 at 03:28 | #9

    Very Useful information

  10. Nikhil
    May 17th, 2012 at 05:50 | #10

    Very nice. Just one thing you need to change:

    DOMConfigurator.configure(sce.getServletContext().getRealPath(log4jFile));

    otherwise, it tries to search for the config file in apache/bin

    see: http://stackoverflow.com/questions/7151832/in-java-web-application-how-to-read-log4j-xml-from-web-inb-conf-location-with-s

  1. No trackbacks yet.