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.
- Create a database schema with name application_logs using below sql statement.
Create schema application_logs
- 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
) ;
- 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.
- 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)

