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)