
In a J2EE application, performance is one of the crucial factors for the success of the application. Ongoing monitoring of the performance of the application is an activity during the entire lifetime of an application In most of cases, an external performance monitoring tool is used to test the application performance in a production like environment.
In an enterprise application scenario, with the application interacting with the various back end systems and the database, performance becomes the major challenge. They are
- Total time taken by the application to process the request
- Calculation of time spent in each of the tier.
- Time spent in the integration tier to talk to different back end or database
- Capturing the data in the production environment.
In order to address these issues, one of the solutions is to have a performance monitoring as a part of application which can be enabled or disabled based on the preference. This article will help the developer in implementing a simple performance logging using log4J, Servlet filter and Weblogic application server.
This above figure shows the basic architecture for implementing performance logging with the help of log4j and filter Servlet. The architecture displayed above consists of the following components
- Filter Servlet
- Log4J.xml
- Web.xml
Filter Servlet
A filter is like a preprocessor of the request and postprocessor of the response coming to a Servlet engine. Filters can be applied to any resources served by a Servlet engine, whether it's flat HTML, graphics, a JSP page, Servlet, or whatever. Filters are essentially a server plug-in that works with any Servlet container compliant with version 2.3 or later of the Servlet specification.
Log4j
Log4j is a widely used API for logging messages in an application. Log4j is configured with the help of the configuration file.
The log4j provides the flexibility of defining appender for an application based on the needs. This appender can be configured using the configuration file to log the messages in the file.
The next section describes the implementation of the performance filter.
Implementation
The implementation is defined in a step by step manner as defined below.
1. Define the log4j appender
2. Define the parameters in web.xml
3. Define the logging parameters
4. Define the Filter Servlet
5. Package and Deploy
A custom appender to be defined in the log4j.xml which would log all the messages pertaining to the performance in this file.
The description of the parameters specified in Performance Appender is as follows.
| Parameter | Description |
| File | Name of the file where the performance data should be stored |
| Append | File to be appended every time |
| MaxFileSize | Maximum size of the file |
The log4J.xml file can be stored in the application server domain home. Include the following line in the weblogic startup script so that the application server can locate the file and load it appropriately.
set LOG4J_CONFIG_FILE=%DOMAIN_HOME%/log4j.xml
In order control the logging of the performance filter we can define the following
| Parameter | Value |
| enablePerformanceHeaders | 1 = True 0 = False |
| enablePerformanceLogging | 1 = True 0 = False |
The enablePerformanceLogging would be used for enabling or disabling of the performance logging.
Logging Parameters
The logging parameters can be defined based on the application requirement working. In case the application caters to variety of the backend and services, it would be useful to create more number of parameters. For the current example, we could consider the following
| Description | |
| responseId | A unique id for a given request/response for the application instance |
| remoteAddress | Client IP |
| userID | User ID used in the application |
| callTime | Total time spent in the application from the time the request came and the response given. |
| response Time1 | A long variable defining the time spent in the business layer |
| response Time2 | A long variable defining the time spent in the Database or the integration layer |
| extraData | Any additional data required |
These responseTime1, responseTime2 and extra data parameters need to be populated in the application. In order to ensure filter receives this data, the application will be logging this parameter as part of the response object.
Performance Filter
This filter is used as pre-processor and post processor for the application.
/**
* This filter is to log the time taken to process each request
*/
package com.hp.presentation.common.filters;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class PerformanceFilter implements Filter {
// Used for performance logging to a Log4J appender
private static Log perfLog = LogFactory.getLog("performance.perflog");
private FilterConfig config = null;
// Initialiase the FilterConfig object
public void init(FilterConfig filterConfig) throws ServletException {
this.config = filterConfig;
}
// destroy this instance
public void destroy() {
this.config = null;
}
// This method is called for every hit to the server
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
if (!perfLog.isInfoEnabled() || (req.getAttribute("FIRST_URI") != null))
{
chain.doFilter(req, res);
return;
}
// Get the current time in milli seconds before serving the request
long before = System.currentTimeMillis();
// Make sure that it's a HTTP Request
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// used to synchronize the testtool with the logfile
String responseID = generateID();
If (enablePerformanceHeaders) {
response.setHeader("BEP_RESPONSE_ID", responseID);
}
// Initialise a string to hold the request URI
String name = request.getRequestURI();
// Used to filter out forwards
request.setAttribute("FIRST_URI", name);
String remoteAddress = (String) request.getHeader("WL-Proxy-Client-IP");
if (remoteAddress == null) {
remoteAddress = request.getRemoteAddr();
}
// Continue with the Filter for the next request
chain.doFilter(request, res);
//logger.debug("ExtraPerfData***"+extraPerfData);
String responseTime1 = "";
String responseTime2 = "";
String extraPerfData = "";
if ((request.getAttribute("RESPONSETIME1")) != null) {
responseTime1 = (String) request.getAttribute("RESPONSETIME1");
}
if ((request.getAttribute("RESPONSETIME2")) != null) {
responseTime2 = (String) request.getAttribute("RESPONSETIME2");
}
if ((request.getAttribute("EXTRAPERFDATA")) != null) {
extraPerfData = (String)request.getAttribute("EXTRAPERFDATA");
}
// Get the current time in milli seconds after serving the request
long after = System.currentTimeMillis();
Long callTime = new Long(after - before);
// Log to performance log (File, JMS Topic, Chainsaw etc.)
if (perfLog.isInfoEnabled()) {
StringBuffer strBuff = new StringBuffer(132);
strBuff.append(responseID);
strBuff.append(";");
strBuff.append(remoteAddress);
strBuff.append(";");
strBuff.append(name);
strBuff.append(";");
strBuff.append(callTime);
strBuff.append(";");
strBuff.append(responseTime1);
strBuff.append(";");
strBuff.append(responseTime2);
strBuff.append(";");
strBuff.append(extraPerfData);
perfLog.info(strBuff);
}
}
/**
* Generates simple ID for this call
* Only unique in this application instance and not garanteed after restart.
* Generation of UUID only available in Java 1.5!
*/
private static int idCounter = 0;
private static String loadTime =
(new Long(System.currentTimeMillis())).toString().substring(7);
public synchronized String generateID() {
return loadTime + idCounter++;
}
}
Usage of Performance logging in Application
This Performance login service can be used in the application as follows with minimum changes.
- Create log4j.xml file with Appender and configure it in the Weblogic Application Server as explained earlier.
- Copy the Servlet code as specified above.
- Set the parameters in the web.xml.
- In case the application specific parameters to be captured, add it accordingly in the application as the extraData parameter
- Capture the Response Time in Application. (Not doing this will only result in the one single call time logged)
Assumption: log4j is already configured with the application.