Every web request takes a certain amount of time to get processed by the server. In order to find out how much time it takes to process a web request, we need to calculate the time difference between the starting time and ending time of a web request process. We can achieve that by using the interceptor concept. Let's see how to configure our own
interceptor in our project to log the execution time of every web request:
Open pom.xml; you can find pom.xml under the root directory of the project
1. itself.
You will see some tabs at the bottom of the pom.xml file; select the Dependencies
2. tab and click on the Add button in the Dependencies section.
A Select Dependency window will appear; enter Group Id as log4j, Artifact Id
3. as log4j, and Version as 1.2.17, select Scope as compile, click the OK button, and save pom.xml.
Create a class named ProcessingTimeLogInterceptor under the
4.
com.packt.webstore.interceptor package in the src/main/java source folder, and add the following code to it:
package com.packt.webstore.interceptor;
import javax.servlet.http.HttpServletRequest;
Internalize Your Store with Interceptor
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class ProcessingTimeLogInterceptor implements
HandlerInterceptor {
private static final Logger LOGGER =
Logger.getLogger(ProcessingTimeLogInterceptor.class);
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler, ModelAndView
modelAndView) {
String queryString = request.getQueryString() == null ? "" : "?" + request.getQueryString();
String path = request.getRequestURL() + queryString;
long startTime = (Long)
request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
LOGGER.info(String.format("%s millisecond taken to
process the request %s.",(endTime - startTime), path));
}
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception exceptionIfAny){
// NO operation.
}
}
Now open your web application context configuration file
5. WebApplicationContextConfig.java, add the following method to it, and save the file:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new
ProcessingTimeLogInterceptor());
}
Internalize Your Store with Interceptor
[ 158 ]
Create a property file named log4j.properties under the
6. src/main/resources directory, and add the following content. Then, save the file:
# Root logger option
log4j.rootLogger=INFO, file, stdout
# Direct log messages to a log file
log4j.appender.file=org.apache.log4j.RollingFileAppender
log4j.appender.file.File= C:\\webstore\\webstore-
performance.log
log4j.appender.file.MaxFileSize=1MB
log4j.appender.file.MaxBackupIndex=1
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd
HH:mm:ss} %-5p %c{1}:%L - %m%n
# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd
HH:mm:ss} %-5p %c{1}:%L - %m%n
Now run our application, enter the
7.
http://localhost:8080/webstore/market/products URL, and navigate to some pages; you should able to see the logging in the console as follows:
Showing ProcessingTimeLogInterceptor logging messages in the console
Open the file C:\webstore\webstore-performance.log; you can see the
8. same log message in the logging file as well.
What just happened?
Our intention was to record the execution time of every request coming to our web
application, so we decided to record the execution times in a log file. In order to use a logger, we needed the log4j library, so we added the log4j library as a Maven
dependency in step 3.
Internalize Your Store with Interceptor
In step 4, we defined an interceptor class named ProcessingTimeLogInterceptor by implementing the HandlerInterceptor interface. As we already saw, there are three methods that need to be implemented. We will see each method one by one. The first method is preHandle(), which is called before the execution of the Controller method:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
long startTime = System.currentTimeMillis();
request.setAttribute("startTime", startTime);
return true;
}
In the previously shown preHandle method, we just set the current time value in the request object for later retrieval. Whenever a request comes to our web application, it first comes through this preHandle method and sets the current time in the request object before reaching the Controller. We are returning true from this method because we want the execution chain to proceed with the next interceptor or the Controller itself. Otherwise, DispatcherServlet assumes that this interceptor has already dealt with the response itself. So if we return false from the preHandle method, the request won't proceed to the Controller or the next interceptor.
The second method is postHandle, which will be called after the Controller method's execution:
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
String queryString = request.getQueryString() == null ? "" : "?" + request.getQueryString();
String path = request.getRequestURL() + queryString;
long startTime = (Long) request.getAttribute("startTime");
long endTime = System.currentTimeMillis();
LOGGER.info(String.format("%s millisecond taken to process the request
%s.",(endTime - startTime), path));
}
In the preceding method, we are simply logging the difference between the current time, which is considered to be the request processing finish time, and the start time, which we got from the request object. Our final method is afterCompletion, which is called after the View is rendered. We don't want to put any logic in this method, that's why I left the method empty.
Internalize Your Store with Interceptor
[ 160 ]
If you don't want to implement all the methods from the
HandlerInterceptor interface in your interceptor class, you could
consider extending your interceptor from
org.springframework.web.servlet.handler.HandlerIntercepto rAdapter, which is a convenient class provided by Spring MVC as a
default implementation of all the methods from the
HandlerInterceptor interface.
After creating our ProcessingTimeLogInterceptor, we need to register our interceptor with Spring MVC, which is what we have done in step 5 through the addInterceptors overridden method of WebMvcConfigurerAdapter:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ProcessingTimeLogInterceptor());
}
In step 6, we have added a log4j.properties file in order to specify some logger-related configurations. You can see we have configured the log file location in log4j.properties
as follows:
log4j.appender.file.File= C:\\webstore\\webstore-performance.log
Finally, in step 7 we ran our application in order to record some performance logging, and
we were able to see that the logger is just working fine via the console. You can open the log file to view the performance logs.
So we understood how to configure an interceptor and saw
ProcessingTimeLogInterceptor in action. In the next exercise, we will see how to use some Spring-provided interceptors.