#

Hibernate Statistics JSP Reloaded

Some time ago I posted a JSP-Page for displaying Hibernate-Statistics within an application. Meanwhile I also posted some Code to translate HQL queries to SQL. Now I merged both together to a new version of the Hibernate Statistics page that also displays SQL statements, and it’s still not a code-beauty 😉

The actual version uses the HTMLEscapeWriter from an earlier post of me. It’s still a dirty hack and not really safe, but works as a base.

The resulting page will look something like this (depending on stylesheets I forgot to include):

Don’t wonder about wrong sums in the image, since I had to clip a lot off.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<jsp:directive.page import="java.util.*"/>
<jsp:directive.page import="org.hibernate.SessionFactory"/>
<jsp:directive.page import="org.hibernate.stat.Statistics"/>
<jsp:directive.page import="org.hibernate.stat.QueryStatistics"/>
<jsp:directive.page import="java.text.Collator"/>
<jsp:directive.page import="org.hibernate.stat.EntityStatistics"/>
<jsp:directive.page import="org.hibernate.stat.CollectionStatistics"/>
<jsp:directive.page import="org.hibernate.stat.SecondLevelCacheStatistics"/>
<jsp:directive.page import="org.springframework.context.ApplicationContext"/>
<jsp:directive.page import="org.springframework.web.context.support.WebApplicationContextUtils"/>
<jsp:directive.page import="java.util.Map"/>
<jsp:directive.page import="java.util.Date"/>
<%!
	static Map<String, QueryStatistics> queryStatistics = 
		Collections.synchronizedMap(
			new TreeMap<String, QueryStatistics>(Collator.getInstance()));
	static Map<String, EntityStatistics> entityStatistics = 
		Collections.synchronizedMap(
			new TreeMap<String, EntityStatistics>(Collator.getInstance()));
	static Map<String, CollectionStatistics> collectionStatistics = 
		Collections.synchronizedMap(
			new TreeMap<String, CollectionStatistics>(Collator.getInstance()));
	static Map<String, SecondLevelCacheStatistics> secondLevelCacheStatistics = 
		Collections.synchronizedMap(new TreeMap<String, SecondLevelCacheStatistics>(Collator.getInstance()));
	static List<Long> generalStatistics = Collections.synchronizedList(new ArrayList<Long>(18));
	static{
		for (int i=0; i<9; i++){
			generalStatistics.add(new Long(-1));
		}
	}
	static Date lastUpdate;
	static Date activation;
	static Date deactivation;
 
	public class HqlToSqlTranslator {
		public String toSql(SessionFactory sessionFactory, String hqlQueryText){
		    if (hqlQueryText!=null){
 
		        final QueryTranslatorFactory ast = new ASTQueryTranslatorFactory();
	    	    final SessionFactoryImplementor factory =
	        		(SessionFactoryImplementor) sessionFactory;
		        final QueryTranslator newQueryTranslator = 
		        	ast.createQueryTranslator( 
	    	    		hqlQueryText, 
	        			hqlQueryText, 
	        			Collections.EMPTY_MAP, factory );
		        newQueryTranslator.compile( Collections.EMPTY_MAP, false );
		        return newQueryTranslator.getSQLString(); 
	    	}
 
		    return null;
		}
	}
	static HqlToSqlTranslator translator = new HqlToSqlTranslator();
 
	public static StringUtils{
		public static final String format(final Date date, final String dateformat) {
			if (date == null){
				return null;
			}
			final SimpleDateFormat sdf = new SimpleDateFormat(dateformat);
			return sdf.format(date);
		}
	}
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
	<title>Hibernate statistics</title>
	<style>
.c{
	text-align: center;
}
.r{
	text-align: right;
}
.l{
	text-align: left;
}
.t{
	vertical-align: top;
}
.b{
	vertical-align: bottom;
}
.odd{
	background-color: #D4D4D4;
}
.even{
	background-color: #EEEEEE;
}
.bd1{
	border: solid #888888 1px;
}
.bg1{
	background-color: #CCCCCC;
}
.bg2{
	background-color: #DDDDDD;
}
	</style>
</head>
<body>
<p/>
<%
	final ApplicationContext appContext = 
		WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
	final SessionFactory sessionFactory = 
		(SessionFactory) appContext.getBean("hibernateSessionFactory");
	final Statistics statistics = sessionFactory.getStatistics();
 
	final String action = request.getParameter("do");
	final StringBuilder info = new StringBuilder(512);
 
 
	if ("activate".equals(action) && 
			!statistics.isStatisticsEnabled()){
		statistics.setStatisticsEnabled(true);
		activation = new Date();
		info.append("Statistics enabled\n");
	}
	else if ("deactivate".equals(action) && 
			statistics.isStatisticsEnabled()){
		statistics.setStatisticsEnabled(false);
		deactivation = new Date();
		info.append("Statistics disabled\n");
	}
	else if ("clear".equals(action)){
		activation = null;
		deactivation = null;
		statistics.clear();
		generalStatistics.set(0, new Long(0));
		generalStatistics.set(1, new Long(0));
 
		generalStatistics.set(2, new Long(0));
		generalStatistics.set(3, new Long(0));
 
		generalStatistics.set(4, new Long(0));
		generalStatistics.set(5, new Long(0));
 
		generalStatistics.set(6, new Long(0));
		generalStatistics.set(7, new Long(0));
		generalStatistics.set(8, new Long(0));
		queryStatistics.clear();
		entityStatistics.clear();
		collectionStatistics.clear();
		secondLevelCacheStatistics.clear();
		info.append("Statistics cleared\n");
	}
 
	boolean active = statistics.isStatisticsEnabled();
	if (info.length()>0){
		%>
		<p/><div class="success">
				<%=HTMLEscapeWriter.escape(info.toString())%>
			</div>
		<%
	}
	%>
<p/>
<a href="hibernate.jsp">Reload</a>
<p/>
<a href="hibernate.jsp?do=<%=(active?"deactivate":"activate")%>">
<%=(active?"DEACTIVATE":"ACTIVATE")%></a> | 
<a href="hibernate.jsp?do=clear">CLEAR</a>
<%
	if (active){
		lastUpdate = new Date();
		String [] names;
 
		generalStatistics.set(0, statistics.getConnectCount());
		generalStatistics.set(1, statistics.getFlushCount());
 
		generalStatistics.set(2, statistics.getPrepareStatementCount());
		generalStatistics.set(3, statistics.getCloseStatementCount());
 
		generalStatistics.set(4, statistics.getSessionCloseCount());
		generalStatistics.set(5, statistics.getSessionOpenCount());
 
		generalStatistics.set(6, statistics.getTransactionCount());
		generalStatistics.set(7, statistics.getSuccessfulTransactionCount());
		generalStatistics.set(8, statistics.getOptimisticFailureCount());
 
		queryStatistics.clear();
		names = statistics.getQueries();
		if (names!=null && names.length>0){
			for (int i=0; i<names.length; i++){
				queryStatistics.put(names[i], 
					statistics.getQueryStatistics(names[i]));
			}
		}
 
		entityStatistics.clear();
		names = statistics.getEntityNames();
		if (names!=null && names.length>0){
			for (int i=0; i<names.length; i++){
				entityStatistics.put(names[i], 
					statistics.getEntityStatistics(names[i]));
			}
		}
 
		collectionStatistics.clear();
		names = statistics.getCollectionRoleNames();
		if (names!=null && names.length>0){
			for (int i=0; i<names.length; i++){
				collectionStatistics.put(names[i], 
					statistics.getCollectionStatistics(names[i]));
			}
		}
 
		secondLevelCacheStatistics.clear();
		names = statistics.getSecondLevelCacheRegionNames();
		if (names!=null && names.length>0){
			for (int i=0; i<names.length; i++){
				secondLevelCacheStatistics.put(names[i], 
					statistics.getSecondLevelCacheStatistics(names[i]));
			}
		}
	}
 
	%>
	<p/>
	Last update: <%=(lastUpdate!=null?
		StringUtils.format(lastUpdate, "dd.MM.yy HH:mm:ss"):"none")%><br/>
	Activation: <%=(activation!=null?
		StringUtils.format(activation, "dd.MM.yy HH:mm:ss"):"none")%><br/>
	Deactivation: <%=(deactivation!=null?
		StringUtils.format(deactivation, "dd.MM.yy HH:mm:ss"):"none")%><br/>
	Active duration: <%=(activation!=null?
		StringUtils.formatTime((deactivation!=null?
			deactivation.getTime():
			new Date().getTime())-activation.getTime()):
			"none")%>
	<p/>
	<%
	boolean hasGeneral = false;
	for (int i=0; i<9; i++){
		if (generalStatistics.get(i).longValue()>-1){
			hasGeneral = true;
			break;
		}
	}
	if (hasGeneral){
		%>
		<table>
			<tr>
				<th class="c bd1 bg1">Connects</th>
				<td><%=generalStatistics.get(0)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Flushes</th>
				<td><%=generalStatistics.get(1)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Prepare statements</th>
				<td><%=generalStatistics.get(2)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Close statements</th>
				<td><%=generalStatistics.get(3)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Session opens</th>
				<td><%=generalStatistics.get(5)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Session closes</th>
				<td><%=generalStatistics.get(4)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Total Transactions</th>
				<td><%=generalStatistics.get(6)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Successfull Transactions</th>
				<td><%=generalStatistics.get(7)%></td>
			</tr>
			<tr>
				<th class="c bd1 bg1">Optimistic failures</th>
				<td><%=generalStatistics.get(8)%></td>
			</tr>
		</table>
		<p/>
		<%
	}
	%>
 
	<%
	if (queryStatistics.size()>0){
		%>
		<table width="100%">
			<tr><th colspan="11" class="c bd1 bg2">Query statistics</th></tr>
			<tr>
				<th class="c bd1 bg1">HQL Query</th>
				<th class="c bd1 bg1">SQL Query</th>
				<th class="c bd1 bg1">Calls</th>
				<th class="c bd1 bg1">Total rowcount</th>
				<th class="c bd1 bg1">Max dur.</th>
				<th class="c bd1 bg1">Min dur.</th>
				<th class="c bd1 bg1">Avg dur.</th>
				<th class="c bd1 bg1">Total dur.</th>
				<th class="c bd1 bg1">Cache hits</th>
				<th class="c bd1 bg1">Cache miss</th>
				<th class="c bd1 bg1">Cache put</th>
			</tr>
		<%
		QueryStatistics queryStats;
		boolean odd = true;
		for (String query:queryStatistics.keySet()){
			queryStats = queryStatistics.get(query);
			%>
			<tr class="<%=(odd?"odd":"even")%>">
				<td class="t"><%=query%></td>
				<td><small><%=translator.toSql(sessionFactory, query)%></small></td>
				<td class="t"><%=queryStats.getExecutionCount()%></td>
				<td class="t"><%=queryStats.getExecutionRowCount()%></td>
				<td class="t"><%=queryStats.getExecutionMaxTime()%></td>
				<td class="t"><%=queryStats.getExecutionMinTime()%></td>
				<td class="t"><%=queryStats.getExecutionAvgTime()%></td>
				<td class="t">
					<%=queryStats.getExecutionAvgTime()*queryStats.getExecutionCount()%>
				</td>
				<td class="t"><%=queryStats.getCacheHitCount()%></td>
				<td class="t"><%=queryStats.getCacheMissCount()%></td>
				<td class="t"><%=queryStats.getCachePutCount()%></td>
			</tr>
			<%
			odd = !odd;
		}
		%>
		</table>
		<p/>
	<%
	}
 
	if (entityStatistics.size()>0){
	%>
		<table width="100%">
			<tr><th colspan="7" class="c bd1 bg2">Entity statistics</th></tr>
			<tr>
				<th class="c bd1 bg1">Entity</th>
				<th class="c bd1 bg1">Loads</th>
				<th class="c bd1 bg1">Fetches</th>
				<th class="c bd1 bg1">Inserts</th>
				<th class="c bd1 bg1">Updates</th>
				<th class="c bd1 bg1">Deletes</th>
				<th class="c bd1 bg1">Optimistic failures</th>
			</tr>
		<%
		EntityStatistics entityStats;
		boolean odd = true;
		for (String entity:entityStatistics.keySet()){
			entityStats = entityStatistics.get(entity);
			%>
			<tr class="<%=(odd?"odd":"even")%>">
				<td><%=entity%></td>
				<td><%=entityStats.getLoadCount()%></td>
				<td><%=entityStats.getFetchCount()%></td>
				<td><%=entityStats.getInsertCount()%></td>
				<td><%=entityStats.getUpdateCount()%></td>
				<td><%=entityStats.getDeleteCount()%></td>
				<td><%=entityStats.getOptimisticFailureCount()%></td>
			</tr>
			<%
			odd = !odd;
		}
		%>
		</table>
		<p/>
	<%
	}
 
	if (collectionStatistics.size()>0){
	%>
		<table width="100%">
			<tr><th colspan="6" class="c bd1 bg2">Collection statistics</th></tr>
			<tr>
				<th class="c bd1 bg1">Role</th>
				<th class="c bd1 bg1">Loads</th>
				<th class="c bd1 bg1">Fetches</th>
				<th class="c bd1 bg1">Updates</th>
				<th class="c bd1 bg1">Recreate</th>
				<th class="c bd1 bg1">Remove</th>
			</tr>
		<%
		CollectionStatistics collectionStats;
		boolean odd = true;
		for (String collection:collectionStatistics.keySet()){
			collectionStats = collectionStatistics.get(collection);
			%>
			<tr class="<%=(odd?"odd":"even")%>">
				<td><%=collection%></td>
				<td><%=collectionStats.getLoadCount()%></td>
				<td><%=collectionStats.getFetchCount()%></td>
				<td><%=collectionStats.getUpdateCount()%></td>
				<td><%=collectionStats.getRecreateCount()%></td>
				<td><%=collectionStats.getRemoveCount()%></td>
			</tr>
			<%
			odd = !odd;
		}
		%>
		</table>
		<p/>
	<%
	}
 
	if (secondLevelCacheStatistics.size()>0){
		long totalSizeInMemory = 0;
	%>
		<table width="100%">
			<tr><th colspan="7" class="c bd1 bg2">2nd level cache statistics</th></tr>
			<tr>
				<th class="c bd1 bg1">Regionname</th>
				<th class="c bd1 bg1">Puts</th>
				<th class="c bd1 bg1">Hits</th>
				<th class="c bd1 bg1">Misses</th>
				<th class="c bd1 bg1">Elements in memory</th>
				<th class="c bd1 bg1">Size in memory</th>
				<th class="c bd1 bg1">Elements on disk</th>
			</tr>
		<%
		SecondLevelCacheStatistics cacheStats;
		boolean odd = true;
		for (String cache:secondLevelCacheStatistics.keySet()){
			cacheStats = secondLevelCacheStatistics.get(cache);
			totalSizeInMemory += cacheStats.getSizeInMemory();
			%>
			<tr class="<%=(odd?"odd":"even")%>">
				<td><%=cache%></td>
				<td><%=cacheStats.getPutCount()%></td>
				<td><%=cacheStats.getHitCount()%></td>
				<td><%=cacheStats.getMissCount()%></td>
				<td><%=cacheStats.getElementCountInMemory()%></td>
				<td><%=cacheStats.getSizeInMemory()%></td>
				<td><%=cacheStats.getElementCountOnDisk()%></td>
			</tr>
			<%
			odd = !odd;
		}
		%>
			<tr>
				<td colspan="5">&nbsp;</td>
				<td><%=totalSizeInMemory%></td>
				<td>&nbsp;</td>
			</tr>
		</table>
		<p/>
	<%
	}
	%>
</body>
</html>

One Response to “Hibernate Statistics JSP Reloaded” »»

  1. Comment by Pix | 0:31 25.10.12|X

Leave a Reply »»

Note: All comments are manually approved to avoid spam. So if your comment doesn't appear immediately, that's ok. Have patience, it can take some days until I have the time to approve my comments.