10 - Custom Appender and Layout in log4j

10.1 Overview

In earlier chapters we discussed that Log4j comes with several appenders and layout but sometime in an enterprise application we need to log the messages in a custom format and in a custom appenders. In this chapter we will explain how we can extend or write a custom layout and appender.

Consider a scenario where we have a User Objects and we want to store it in a database. The format of a message will be a xml representation of a user’s data so it can be later utilized by any other application.

10.2 Implementation

10.2.1 – User Class

Let’s write a UserObject class with three fields name, age and country.

package com.log4j.examples;

publicclassUserObject {

    private String name;
    private String age;
    private String country;
    public String getName() {
        return name;
    }
    publicvoidsetName(String name) {
        this.name = name;
    }
    public String getAge() {
        return age;
    }
    publicvoidsetAge(String age) {
        this.age = age;
    }
    public String getCountry() {
        return country;
    }
    publicvoidsetCountry(String country) {
        this.country = country;
    }
    publicUserObject(String name, String age, String country) {
        super();
        this.name = name;
        this.age = age;
        this.country = country;
    }

}

10.2.2 – Layout Class

Let’s write a Custom Layout which will create a XML representation of a User Object.  This class will extend PatternLayout and override format(LoggingEvent) method.

package com.log4j.examples;

import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;

public class CustomLogLayout  extends PatternLayout
{
    public String format(LoggingEvent event)
     {

         UserObject user = (UserObject)event.getMessage();

         StringBuffersb = new StringBuffer();

         String name = user.getName();
         String age= user.getAge();
         String country= user.getCountry();

         sb.append("<user>");
         sb.append("<name>").append(name).append("</name>");
         sb.append("<age>").append(age).append("</age>");
         sb.append("<country>").append(country).append("</country>");
         sb.append("</user>");
         sb.append("\n");

         returnsb.toString();        
     }
}

10.2.3 – Custom Appender Class

Let’s write a custom appender class which will log the message’s log level and its message in database. For database details we will add the properties which can be set in log4j.xml file.

  1. Create a database schema with name application_logs using below sql statement.

       Create schema application_logs

  1. Create table user_records in application_logs schema with below sql statement.

         CREATE TABLE  'user_records' (
        'LOG_LEVEL' varchar(10) DEFAULT NULL,
        'LOG_MESSAGE'` varchar(1000) DEFAULT NULL
        ) ;

  1. We will use MySQL  database so so we would require mysql driver as well so download mysql-connector-java-5.1.18-bin.jar from http://mvnrepository.com/artifact/mysql/mysql-connector-java/5.1.18  file and add it a build path of project.
  2. Create Custom Appender – We have added user, pass, driver and url property which will be configured in log4j.xml and will be used to connect to the database.
  • url- database url
  • driver-database driver
  • user- database username
  • pass- database password
  • we are storing messagesin xml format so we can grab the messages by calling layout.format(even)
  • to get the  log level, we can use event.getLevel()
package com.log4j.examples;

importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.PreparedStatement;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;

public class CustomJdbcAppender extends AppenderSkeleton {

     private String user;
     private String pass;
     private String driver;
     private String url;

     public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public String getDriver() {
        return driver;
    }
    public void setDriver(String driver) {
        this.driver = driver;
    }
    public String getUrl() {
        returnurl;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    @Override
    public void close() {            
    }

    @Override
    publicbooleanrequiresLayout() {
        return false;
    }    
    privatePreparedStatementpst;
    private String sql="insert into user_records values(?,?)";
    @Override
    protected void append(LoggingEvent event) {

       try
            {
                Class.forName(driver);
                Connection conn = DriverManager.getConnection(url, user, pass);
        
                pst= conn.prepareStatement(sql);
                pst.setString(1, event.getLevel().toString());
                
                pst.setString(2, layout.format(event));
               
                pst.executeUpdate();
                pst.close();
                conn.close();
                }
      catch(Exception e)
      {
         e.printStackTrace();
      }
    }
}

10.2.4 – Create log4j.xml 

Create  a log4j.xml and place it in src folder. We we will configure  our custom appender and custom layout and with our database details.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration>

    <appender name="CustomAppender" class="com.log4j.examples.CustomJdbcAppender">
      <param name="url" value="jdbc:mysql://localhost:3306/Application_Logs"/>
      <param name="driver" value="com.mysql.jdbc.Driver"/>
      <param name="user" value="root"/>
      <param name="pass" value="password"/>

      <layout class="com.log4j.examples.CustomLogLayout">
      </layout>
   </appender>

   <root>
        <level value="DEBUG" />
        <appender-ref ref="CustomAppender" />
   </root>

</log4j:configuration>

10.2.5 – Create Test Program

Our test program will create two objects of UserObject class and will log it with error and info severity.

package com.log4j.examples;

import org.apache.log4j.Logger;

public class Test {

   static Logger logger = Logger.getLogger(Test.class);

   public static void main(String[] args) {

   UserObject obj1 = new UserObject("User1","29","INDIA");
   UserObject obj2 = new UserObject("User2","32","USA");

   logger.info(obj1);
   logger.error(obj2);

   }
}

10.2.6 – Result

On running Test Program, two records will be inserted in user_record table with log level and xml messages (refer below)

     Log level xml meaages in log4j

Like us on Facebook