~/home of geeks

Hibernate Statistics JSP Reloaded

· 1045 Wörter · 5 Minute(n) Lesedauer

hall full of ice figures, sci-fi

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.

<%@ 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"/>
<%@ page import="org.hibernate.hql.spi.QueryTranslatorFactory" %>
<%@ page import="org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory" %>
<%@ page import="org.hibernate.engine.spi.SessionFactoryImplementor" %>
<%@ page import="org.hibernate.hql.spi.QueryTranslator" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%!
    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, null );
                newQueryTranslator.compile( Collections.EMPTY_MAP, false );
                return newQueryTranslator.getSQLString();
            }

            return null;
        }
    }
    static HqlToSqlTranslator translator = new HqlToSqlTranslator();

    public static class 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\
");
    }
    else if ("deactivate".equals(action) &&
        statistics.isStatisticsEnabled()){
        statistics.setStatisticsEnabled(false);
        deactivation = new Date();
        info.append("Statistics disabled\
");
    }
    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\
");
    }

    boolean active = statistics.isStatisticsEnabled();
    if (info.length()>0){
%>
<p/><div class="success">
    <%=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?
    (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>