Showing posts with label log4j. Show all posts
Showing posts with label log4j. Show all posts

July 13, 2010

Logback or Log4j Additivity Explained

If you have come across the notion of additivity, while trying to figure out how to stop Logback or Log4j from dumping too much or too little data to the console or a file, but don't quite understand how it works, here is a quick explanation.

First, the very basics

Logback and Log4j have 3 main items that you should understand:

  1. Loggers - objects that log something
  2. Appenders - each logger has one or more. An appender is an output destination (eg. the console or a file)
  3. Layouts - each appender has a layout. A layout is the format of the stuff being logged.

Also

  • A logger can have a parent based on what name you give it (using the . notation). For example, a logger called bob is a parent of a logger called bob.stuff or bob.stuff.foo
  • The root logger is always the parent of every other logger.

So what is aditivity

When a method like log.debug() or log.info() is called on a logger X.Y.Z, it is forwarded to all appenders associated with logger X.Y.Z, as well as all appenders associated with X's parents (such as logger X.Y and logger X). The message is also forwarded to all appenders of the root logger.

For example, if the root logger has an appender for a standard console output, and you have another logger X which has a file appender, calling x.debug() on logger x, will log both to the console (the root logger's appender) and to the file (the X logger's file appender).

If the aditivity flag of logger X however is set to false, or disabled, then calling x.debug() will only log to the file. In other words disabling additivity for a logger, prevents parents of that logger from using their appenders to display the message.

Hope that makes sense.

If you are just starting out with Logback

If you're just starting out with Logback or Log4j, and don't quite understand the naming convention used by these logging frameworks for naming the loggers, keep in mind the following quote from Logback's official documentation:

"Logback makes it easy to name loggers by software component. This can be accomplished by instantiating a logger in each class, with the logger name equal to the fully qualified name of the class. This is a useful and straightforward method of defining loggers. As the log output bears the name of the generating logger, this naming strategy makes it easy to identify the origin of a log message. However, this is only one possible, albeit common, strategy for naming loggers. Logback does not restrict the possible set of loggers. As a developer, you are free to name loggers as you wish."

So hopefully now when you see the following line of code, which defines a logger in a class, you understand what it does:

//get the logger called "com.foo.SomeClassName"
private static Logger log = LoggerFactory.getLogger(SomeClassName.class);  

June 17, 2010

Log SQL statements with MyBatis and Log4j

Here is a basic log4j.properties file you can use to dump all your SQL statements to a log file: l

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.