运用highcharts实现实时监控曲线图
使用highcharts实现实时监控曲线图
最近一段时间由于服务器响应有些异常,所以花了半天做了一个简单实时监控页面。如下图


基本原理如下:
1、使用Filter拦截请求,采集服务器响应数据。
若是要收集响应状态码注意构造新的HttpServletResponse
若只统计错误状态码则区分Response Code是否大于400,小于400的都是正确响应
如200(OK),206(断点续传),301(永久重定向),302(临时重定向),304(内容未变),大于等于400的状态都是错误响应,计算响应速度区间和平均响应时间的代码我就不贴了
2、定时程序或线程把数据入库或保存到内存中。尽量不要使用java内嵌数据库如hsqldb,H2等,因为这些内存数据库运行时会把所有数据加到内存中,不太适合保存数据采集结果
3、使用Highcharts绘制监控页面
可以参照官网例子http://www.highcharts.com/demo/dynamic-update,
需要注意的是:
1、在series的load事件中使用ajax定时加载数据,需要控制当前chart中的Point数据量,
series.addPoint(point, true, isShift);
当series中Point数量超过指定值,设定isShift为true,就可以移除第一个Point,防止浏览器内存占用太大无响应
2、ajax请求时只请求最新采集数据,所以每次加载采集数据后把最后时间保留下来,ajax请求时把当前chart中最后时间带上,获取最新数据
如果每秒采集一下数据并保存到数据库,可以扩充一下功能实现BI的数据挖掘和各维度的钻取该也不能。但由于是浏览器使用svg技术绘制曲线,采集的点太多时初次显示还是比较慢。
最近一段时间由于服务器响应有些异常,所以花了半天做了一个简单实时监控页面。如下图
基本原理如下:
1、使用Filter拦截请求,采集服务器响应数据。
若是要收集响应状态码注意构造新的HttpServletResponse
package com.cmgame.ecms.statistic import javax.servlet.http.HttpServletResponseWrapper import javax.servlet.http.HttpServletResponse /** * 功能描述 * @author huzl * @version 0.0.1, 12-7-30 下午3:11 */ class StatusExposingServletResponse extends HttpServletResponseWrapper { private Integer status = SC_OK;; public Integer getStatus() { return status } def StatusExposingServletResponse(HttpServletResponse response) { super(response); } @Override void sendError(int sc, String msg) { super.sendError(sc, msg) status = sc; } @Override void sendError(int sc) { super.sendError(sc) status = sc; } @Override void sendRedirect(String location) { super.sendRedirect(location) status = SC_MOVED_TEMPORARILY; } @Override void setStatus(int sc) { super.setStatus(sc) status = sc; } @Override void setStatus(int sc, String sm) { super.setStatus(sc, sm) status = sc; } } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){ long startTime = System.currentTimeMillis(); StatusExposingServletResponse response = new StatusExposingServletResponse(servletResponse); Throwable exception = null; try { filterChain.doFilter(servletRequest,response) } catch (Throwable e) { exception = e; throw e; }finally{ statisticResult.completeRequest(servletRequest,response,exception,startTime); } }
若只统计错误状态码则区分Response Code是否大于400,小于400的都是正确响应
如200(OK),206(断点续传),301(永久重定向),302(临时重定向),304(内容未变),大于等于400的状态都是错误响应,计算响应速度区间和平均响应时间的代码我就不贴了
2、定时程序或线程把数据入库或保存到内存中。尽量不要使用java内嵌数据库如hsqldb,H2等,因为这些内存数据库运行时会把所有数据加到内存中,不太适合保存数据采集结果
3、使用Highcharts绘制监控页面
可以参照官网例子http://www.highcharts.com/demo/dynamic-update,
var charts = new Array(); var serverCount = 6; var lastTimes = new Array(); var max = ${params.int("max")?:120}; $(document).ready(function() { Highcharts.setOptions({ global: { useUTC: false } }); for (var i = 0; i < serverCount; i++) { charts[i] = new Highcharts.Chart({ chart: { renderTo: 'container' + i, type: 'spline', events: { load: function() { // set up the updating of the chart each second var series = this.series; var serverIndex = i; lastTimes[serverIndex] = 0; var loadData = function() { $.getJSON("http://${request.serverName}:${request.serverPort}${request.contextPath}/toolkits/queryStatistics.gsp", {"lasTime":lastTimes[serverIndex],"proxy":true,"index":serverIndex,"max":max}, function(data) { for (var k = 0; k < series.length; k++) { for (var j = 0; j < data[k].length; j++) { var point = data[k][j]; var isShift = series[k].data.length >= max; console.log("series " + k + ".data.length=" + series[k].data.length); var lastTime = 0; if (series[k].data.length > 0) lastTime = series[k].data[series[k].data.length - 1].x; if (point[0] > lastTime) series[k].addPoint([point[0],point[1]], true, isShift); lastTimes[serverIndex] = point[0]; } } }) }; loadData(); setInterval(loadData, 60000); } } }, title: { text: '访问量实时监控' }, xAxis: [ { type: 'datetime', tickPixelInterval: 120 } ], yAxis: [ { title: { text: '总请求/分钟', style: { color: '#3E576F' } } }, { title: { text: '平均响应时间', style: { color: '#00AA00' } },opposite:true } ], plotOptions: { spline: { marker:{ enabled: false, states: { hover: { enabled: true, symbol: 'circle', radius: 5, lineWidth: 1 } } } } }, tooltip: { formatter: function() { return '<b>' + this.series.name + '</b><br/>' + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' + Highcharts.numberFormat(this.y, 2); } }, legend: { enabled: true }, exporting: { enabled: false }, series: [ { name: '总请求数', data: [] }, { name: '错误请求数', data: [] }, { name: '平均响应时间', yAxis:1, data: [] } ] }); } })
需要注意的是:
1、在series的load事件中使用ajax定时加载数据,需要控制当前chart中的Point数据量,
series.addPoint(point, true, isShift);
当series中Point数量超过指定值,设定isShift为true,就可以移除第一个Point,防止浏览器内存占用太大无响应
2、ajax请求时只请求最新采集数据,所以每次加载采集数据后把最后时间保留下来,ajax请求时把当前chart中最后时间带上,获取最新数据
如果每秒采集一下数据并保存到数据库,可以扩充一下功能实现BI的数据挖掘和各维度的钻取该也不能。但由于是浏览器使用svg技术绘制曲线,采集的点太多时初次显示还是比较慢。