Thursday, November 25, 2004

Integrate JAMon with Spring

JAMon is a tool to monitor performance of application components. It's
very useful to determine bottlenecks on application and find the impacted component. It provides too statistics on calls ( between the start and the end of monitors ).

This tool can be download at the following url:
http://sourceforge.net/project/showfiles.php?group_id=96550
and you can find its documentations on these sites:
http://jamonapi.sourceforge.net/
http://www.javaperformancetuning.com/tools/jamon/index.shtml

To install it in your application, only JAMon.jar must be in your classpath.


Spring already has an aop interceptor to measure performance of application components based on commons-logging. The idea is to provide a simple JAMon interceptor to start monitor before the call and end it after the call.

It provides too facilities to name the JAMon monitor with class and method names.


The method getMonitorName determines the monitor name:




protected String getMonitorName(MethodInvocation invocation) {
StringBuffer monitorName=new StringBuffer();
monitorName.append(
invocation.getMethod().getDeclaringClass().getName());
monitorName.append(" ( ");
monitorName.append(invocation.getMethod().getName());
monitorName.append(" )");
return monitorName.toString();
}


The Spring AOP interceptor is simple:



import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import com.jamonapi.Monitor;
import com.jamonapi.MonitorFactory;

public class PerfIntercepteur implements MethodInterceptor {

protected String getMonitorName(MethodInvocation invocation) {
StringBuffer monitorName=new StringBuffer();
monitorName.append(
invocation.getMethod().getDeclaringClass().getName());
monitorName.append(" ( ");
monitorName.append(invocation.getMethod().getName());
monitorName.append(" )");
return monitorName.toString();
}

public Object invoke(MethodInvocation invocation) throws Throwable {
Monitor mon=MonitorFactory.start(getMonitorName(invocation));
Object rval=invocation.proceed();
mon.stop();
return rval;
}
}


and you can configure it in this way:


<!DOCTYPE beans PUBLIC
"-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
...
<bean id="perfInterceptor" class="aop.PerfIntercepteur"/>

<bean id="autoProxyCreator" class="org.springframework.aop.framework.
autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<idref local="perfInterceptor" />
</list>
</property>
<property name="beanNames">
<list>
<idref local="service" />
</list>
</property>
</bean>
</beans>


The aim is to plug the JAMon interceptor on the component of the application layer to identifity the component that has performance problem ( from presentation layer to dao layer ).

Wednesday, November 24, 2004

Integrate P6Spy with Spring

P6Spy is a tool to debug JDBC interaction with a database. It's a wrapper
of all JDBC elements ( Connection, PreparedStatement, ResultSet... ) and
it has a powerful feature in order to log all informations about those
interactions.

JDBC wrapper is described in the "Java Performance Tuning" book of Jack Shirazi ( O'Reilly) in the chapter 16.


All elements wrappers have a constructor with the element to wrap. We can use it but
there is another mode for datasource. This last mode must be used to wrap a datasource
defined in an application server for example.

However since we can manage our objects ( beans ) in Spring ( and datasources
too ), it's possible to add a P6Spy datasource and link it with the real datasource
with constructor injection.



<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
<bean id="myDataSourceTarget"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName">
<value>org.hsqldb.jdbcDriver</value>
</property>
<property name="url">
<value>jdbc:hsqldb:hsql://localhost:9001</value>
</property>
<property name="username"><value>sa</value></property>
<property name="password"><value></value></property>
</bean>

<bean id="myDataSource" class="com.p6spy.engine.spy.P6DataSource"
destroy-method="close">
<constructor-arg>
<ref local="myDataSourceTarget"/>
</constructor-arg>
</bean>

</beans>



Moreover a p6spy.log file must be add to the classpath of the application
to specify the location of the log file.



module.log=com.p6spy.engine.logging.P6LogFactory

executionthreshold=
outagedetection=false
outagedetectioninterval=
filter=false
include =
exclude =
sqlexpression =
autoflush = true
dateformat=
includecategories=
excludecategories=info,debug,result,batch

stringmatcher=
stacktraceclass=

reloadproperties=false
reloadpropertiesinterval=60

useprefix=false

appender=com.p6spy.engine.logging.appender.FileLogger
logfile = c:/spy.log

append=true

log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender
log4j.appender.STDOUT.layout=org.apache.log4j.PatternLayout
log4j.appender.STDOUT.layout.ConversionPattern=p6spy - %m%n

log4j.logger.p6spy=INFO,STDOUT



The output can be graphically view with a tool like Iron Track SQL.



Advantages of this solution are the following:

  • It isn't necessary to modify the configuration of the application
    server datasource in order to integrate P6Spy.

  • The use of P6Spy is much easier. No deep knowledge of the format
    of the P6Spy configuration file is required ( only specify the location
    of log file ).
  •