May 2, 2010

Setting up Log4j for simple Java Web Applications + Tomcat 5/6

If you have developed Java based web applications you probably felt the need at some point to use log4j for better more efficient logging.

There are different ways to setup log4j for you web application. Here I will present 2 of ways to setup log4j, particularly aimed at simple java web applications (eg. plain servlets/jsp webapps).

First you can download the following basic log4j.properties file. Just replace <appname> with your application name (eg. FunkyWebApp).


log4j.logger.<appname>logger=DEBUG, C, fileappender

log4j.additivity.<appname>logger=false
log4j.appender.C=org.apache.log4j.ConsoleAppender
log4j.appender.C.layout=org.apache.log4j.PatternLayout
#basic pattern
log4j.appender.C.layout.ConversionPattern=[%c] [%d{dd MMM yyyy - hh:mm:ss}] %5p - %m %n
#advanced pattern (slow)
#log4j.appender.C.layout.ConversionPattern=[%c] [%d{dd MMM yyyy - hh:mm:ss}] %5p - %m - in %M() at line %L of class %C %n 

log4j.appender.fileappender=org.apache.log4j.RollingFileAppender
log4j.appender.fileappender.File=${appRootPath}WEB-INF/logs/<appname>.log
log4j.appender.fileappender.MaxFileSize=500KB

## Keep one backup file
log4j.appender.fileappender.MaxBackupIndex=3
log4j.appender.fileappender.layout=org.apache.log4j.PatternLayout
log4j.appender.fileappender.layout.ConversionPattern=%p %t %c - %m%n
#log4j.appender.C.layout.ConversionPattern=[%c] [%d{dd MMM yyyy - hh:mm:ss}] %5p - %m %n

Now use one of the methods below to add and enable Log4J in your web application

Method 1: Use Servlet to initialize log4j

Step 1: Put log4j.properties file in the right place

  • Place 'log4j.properties' into the root of your classpath. See an example web application layout here

    Tip: when web application is deployed it should be in /WEB-INF/classes/log4j.properties.

  • If using eclipse place 'log4j.properties' under your project_name/src directory

Step 2: Define the servlet mapping in web.xml

Add the following code to WEB-INF/web.xml

<servlet> 
     <servlet-name>log4j-init</servlet-name>
     <servlet-class>com.FunkyWebapp.servlets.Log4jInit</servlet-class> 
     <init-param>
       <param-name>log4j-init-file</param-name>
       <param-value>WEB-INF/classes/log4j.properties</param-value>
     </init-param>
     <load-on-startup>1</load-on-startup>
</servlet> 

Make sure to change the java class file path to be relevant to your project. 'com.FunkyWebapp.servlets.Log4jInit'

Step 3: Add the servlet you mapped in Step 2 to your application

Add the following servlet to your project


import javax.servlet.http.HttpServlet;
import org.apache.log4j.PropertyConfigurator;

public class Log4jInit extends HttpServlet {

 public void init()
 {
     String prefix =  getServletContext().getRealPath("/");
     String file = getInitParameter("log4j-init-file");
 
     // if the log4j-init-file context parameter is not set, then no point in trying
     if(file != null){
      PropertyConfigurator.configure(prefix+file);
      System.out.println("Log4J Logging started: " + prefix+file);
     }
     else{
      System.out.println("Log4J Is not configured for your Application: " + prefix + file);
     }     
 }
}

Make sure the <servlet-class> element in Step 2 matches the fully qualified name of your servlet. And make sure it's in the right package.

Step 4: Initialize the logger and start logging from other servlets in your web application


public class MyServlet extends HttpServlet {
...
private Logger log = Logger.getLogger("<appname>logger");
.
.
.
log.debug("Some string to print out");

}

Make sure the <appname> part matches with the line

log4j.logger.<appname>logger in the log4j.properties file

Notes:
When you initialize log4j in a servlet you will only be able to log from classes which are loaded after the servlet (eg. other servlets). You won't be able to do logging from a ServletContextListener for example.

Method 2: Initialize log4j in a ServletContextListener

Step 1: Put properties file in the right place

  • Place 'log4j.properties' into the root of your classpath. See an example web application layout here

    Tip: when web application is deployed it should be in /WEB-INF/classes/log4j.properties.

  • If using eclipse place 'log4j.properties' under your project_name/src directory

Step 2: Define a listener mapping in web.xml

Add the following servlet listener mapping in web.xml:


<listener>
  <listener-class>
   com.package.listeners.ApplicationServletContextListener
  </listener-class>
</listener>

Step 3: Add the SerlvetContextListener class to the application

public class ApplicationServletContextListener implements ServletContextListener
{
 public void contextInitialized(ServletContextEvent event) 
 { 
     ServletContext ctx = e.getServletContext();
   
  String prefix =  ctx.getRealPath("/");     
  String file = "WEB-INF"+System.getProperty("file.separator")+"classes"+System.getProperty("file.separator")+"log4j.properties";
          
     if(file != null) {
       PropertyConfigurator.configure(prefix+file);
       System.out.println("Log4J Logging started for application: " + prefix+file);
     }
     else
     {
      System.out.println("Log4J Is not configured for application Application: " + prefix+file);
     } 
       
     
 }

 public void contextDestroyed(ServletContextEvent event) 
 {
  
 }

}

Step 4: Define the logger and start logging from other servlets in your applications


public class MyServlet extends HttpServlet {
...
private Logger log = Logger.getLogger("<appname>logger");
.
.
.
log.debug("Some string to print out");

}

Notes:

  • Easier to implement that Method 1
  • All web application now has access to log4j (including listeners)
  • Placing log4j initialization in a ServletContextListener allows initialization of log4j when your web application is loaded for the first time.

Other resources about log4j

Log4j, configuring a Web App to use a relative path.

15 comments:

Anonymous said...

Nice and simple. Thanks for the article.

Anonymous said...

Nice one. Thanks for sharing the same.

Anonymous said...

thank you for showing both approaches at one place and using same example.

very useful

thanks again

Bibhaw said...

nice one.
Thanks.

Michael Peterson said...

Thanks for the tutorial. Everything works as expected for me, except one thing. You have the variable ${appRootPath} in the File property for the append, but that comes up empty for me. How do you set it?


Since it's empty, it ends up creating a WEB-INF/logs dir in my home directory, rather than the tomcat webapps/.


Thanks for any extra help you can provide!

IdleWorx said...

I forgot to add that in there it seems. But it will only work with the Method 2 I described in the article (which uses a ServletContextListener and which is the better way to go anyway)

You can define appRootPath as a system property in the contextInitialized() method like this:

System.setProperty("appRootPath", context.getRealPath("/"));

Then it should reference the proper location relative to your webapp's root path when the log4j.properties is loaded.

IdleWorx said...

Correction, the fix above will also work with Method 1, as long as you call it before initializing log4j inside the init() method.

In other words before calling

PropertyConfigurator.configure(prefix+file);

Anonymous said...

Hi -

Is the logging just to the console or is this supposed to write to a file? If writing to a file, does this error mean it couldn't find the file to write to it?
STDERR

14:23:00,131 INFO [ServerImpl] JBoss (Microcontainer) [5.0.0.CR2 (build: SVNTag=JBoss_5_0_0_CR2 date=200809171139)] Started in 21s:536ms
14:23:01,637 ERROR [STDERR] Mar 1, 2012 2:23:01 PM mypackage.Helloworld doGet
INFO: message 1
14:23:01,638 ERROR [STDERR] Mar 1, 2012 2:23:01 PM mypackage.Helloworld doGet
INFO: message 2

It did send my INFO statments to the console - thanks for the code!

Anonymous said...

fileappender doesn't seems to work. It doesn't create the file, i am using method 1. When I browse the page it doesn't create the file. does the file name should be exactly like logger name?

Anonymous said...

Thank you very much.

Anonymous said...

Nice...thanks..chetan

Kristjan said...

Thank you very much, solved my problem with finding log4j.xml file.

MillionNeeds said...

Thank you soo much!!!!! I have been looking for method 2 for the past 6 months finally I have got from your blog. Thanks a lot...:)!!

Ranjithreddy said...

Hello,
I have tried both the steps and not able able to create any log file.
But I am not getting any error.

Could you you please provide sample struts app for this.

Thanks in advance.

Jorge Baltazar said...

i had a problem because the logFile was not created, and when it was the file location isnt there.

the solucion i find here

http://stackoverflow.com/questions/9967974/log4j-log-files-not-found

i need put this before
Define the property in contextInitialized()

System.setProperty("appRootPath", context.getRealPath("/"));
Restart the servlet container.