r150 - in trunk/nuiton-web/src/main/java/org/nuiton/web: . filter jmx
Author: bleny Date: 2011-12-01 17:17:57 +0100 (Thu, 01 Dec 2011) New Revision: 150 Url: http://nuiton.org/repositories/revision/nuiton-web/150 Log: #1841 Add a filter to gather stats on computation time for all application pages on a per page basis Added: trunk/nuiton-web/src/main/java/org/nuiton/web/filter/MonitoringFilter.java trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/RequestStatistics.java trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsService.java trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsServiceMBean.java Added: trunk/nuiton-web/src/main/java/org/nuiton/web/filter/MonitoringFilter.java =================================================================== --- trunk/nuiton-web/src/main/java/org/nuiton/web/filter/MonitoringFilter.java (rev 0) +++ trunk/nuiton-web/src/main/java/org/nuiton/web/filter/MonitoringFilter.java 2011-12-01 16:17:57 UTC (rev 150) @@ -0,0 +1,90 @@ +package org.nuiton.web.filter; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.web.jmx.ServletStatisticsService; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import java.io.IOException; +import java.lang.management.ManagementFactory; + +/** + * Monitoring filter is a simple non-intrusive servlet filter that collect + * statistics about page computing time per request URI. + * + * All gathered data are published using JMX Bean to make it available through + * monitoring tools such as jconsole. + * + * @since 1.8 + */ +public class MonitoringFilter implements Filter { + + /** Logger. */ + private static final Log log = LogFactory.getLog(MonitoringFilter.class); + + protected ObjectName servletStatisticsMBeanName; + + protected ServletStatisticsService servletStatisticsService; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + try { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + // MBean implementation + servletStatisticsService = new ServletStatisticsService(); + // Bind the stats to a SessionFactory + // Register the Mbean on the server + servletStatisticsMBeanName = new ObjectName("Servlet:application=Statistics"); + server.registerMBean(servletStatisticsService, servletStatisticsMBeanName); + log.info("mbean " + servletStatisticsService + " attached as " + servletStatisticsMBeanName); + } catch (MalformedObjectNameException e) { + log.error("unable to register mbean", e); + } catch (InstanceAlreadyExistsException e) { + log.error("unable to register mbean", e); + } catch (MBeanRegistrationException e) { + log.error("unable to register mbean", e); + } catch (NotCompliantMBeanException e) { + log.error("unable to register mbean", e); + } + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { + + servletStatisticsService.preFilter(servletRequest, servletResponse, filterChain); + + filterChain.doFilter(servletRequest, servletResponse); + + servletStatisticsService.postFilter(servletRequest, servletResponse, filterChain); + + } + + @Override + public void destroy() { + + log.info("statistics:\n" + servletStatisticsService.toCsv()); + + try { + MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + server.unregisterMBean(servletStatisticsMBeanName); + log.info("mbean detached " + servletStatisticsMBeanName); + } catch (InstanceNotFoundException e) { + log.error("unable to unregister mbean", e); + } catch (MBeanRegistrationException e) { + log.error("unable to unregister mbean", e); + } + } + +} Added: trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/RequestStatistics.java =================================================================== --- trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/RequestStatistics.java (rev 0) +++ trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/RequestStatistics.java 2011-12-01 16:17:57 UTC (rev 150) @@ -0,0 +1,56 @@ +package org.nuiton.web.jmx; + +import java.io.Serializable; + +public class RequestStatistics implements Serializable { + + protected int count; + + protected long elapsedSum; + + protected long lowestElapsed = Long.MAX_VALUE; + + protected long highestElapsed; + + public int getCount() { + return count; + } + + public long getElapsedSum() { + return elapsedSum; + } + + public long getLowestElapsed() { + return lowestElapsed; + } + + public long getHighestElapsed() { + return highestElapsed; + } + + public long getAverageElapsed() { + return elapsedSum / count; + } + + public void count(long start, long stop) { + count += 1; + long elapsed = stop - start; + elapsedSum += elapsed; + if (elapsed < lowestElapsed) { + lowestElapsed = elapsed; + } + if (elapsed > highestElapsed) { + highestElapsed = elapsed; + } + } + + @Override + public String toString() { + return "count=" + count + + ", elapsedSum=" + elapsedSum + + ", lowestElapsed=" + lowestElapsed + + ", highestElapsed=" + highestElapsed + + ", averageElapsed=" + getAverageElapsed() + + '}'; + } +} Added: trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsService.java =================================================================== --- trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsService.java (rev 0) +++ trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsService.java 2011-12-01 16:17:57 UTC (rev 150) @@ -0,0 +1,80 @@ +package org.nuiton.web.jmx; + +import javax.servlet.FilterChain; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; + +/** Implementation of {@link ServletStatisticsServiceMBean}. + * + * + */ +public class ServletStatisticsService implements ServletStatisticsServiceMBean { + + protected Map<ServletRequest, Long> requestStartTime = + new HashMap<ServletRequest, Long>(); + + protected Map<String, RequestStatistics> perRequestStatistics = + new HashMap<String, RequestStatistics>(); + + public void preFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) { + + long start = System.currentTimeMillis(); + + requestStartTime.put(servletRequest, start); + + } + + public void postFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) { + + String contentType = servletResponse.getContentType(); + + if (contentType != null && contentType.startsWith("text/html")) { + + long stop = System.currentTimeMillis(); + + long start = requestStartTime.get(servletRequest); + + if (servletRequest instanceof HttpServletRequest) { + String requestURI = ((HttpServletRequest) servletRequest).getRequestURI(); + RequestStatistics requestStatistics = + (RequestStatistics) perRequestStatistics.get(requestURI); + if (requestStatistics == null) { + requestStatistics = new RequestStatistics(); + perRequestStatistics.put(requestURI, requestStatistics); + } + requestStatistics.count(start, stop); + } + } + + requestStartTime.remove(servletRequest); + } + + public Map<String, RequestStatistics> getPerRequestStatistics() { + return perRequestStatistics; + } + + @Override + public String toCsv() { + StringBuilder csv = new StringBuilder(); + csv.append("PAGE,NOMBRE_DEMANDES,DUREE_TOTALE,DUREE_MOYENNE,DUREE_MIN,DUREE_MAX\n"); + for (Map.Entry<String, RequestStatistics> requestStatistics : perRequestStatistics.entrySet()) { + String request = requestStatistics.getKey(); + RequestStatistics statistics = requestStatistics.getValue(); + csv.append(request).append(',') + .append(statistics.getCount()).append(',') + .append(statistics.getElapsedSum()).append(',') + .append(statistics.getAverageElapsed()).append(',') + .append(statistics.getLowestElapsed()).append(',') + .append(statistics.getHighestElapsed()).append('\n'); + } + return csv.toString(); + } + + @Override + public void reset() { + perRequestStatistics.clear(); + } +} Added: trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsServiceMBean.java =================================================================== --- trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsServiceMBean.java (rev 0) +++ trunk/nuiton-web/src/main/java/org/nuiton/web/jmx/ServletStatisticsServiceMBean.java 2011-12-01 16:17:57 UTC (rev 150) @@ -0,0 +1,12 @@ +package org.nuiton.web.jmx; + +import java.util.Map; + +public interface ServletStatisticsServiceMBean { + + Map<String, RequestStatistics> getPerRequestStatistics(); + + void reset(); + + String toCsv(); +}
participants (1)
-
bleny@users.nuiton.org