最近一段时间由于服务器响应有些异常,所以花了半天做了一个简单实时监控页面。如下图
基本原理如下:
1、使用Filter拦截请求,采集服务器响应数据。
若是要收集响应状态码注意构造新的HttpServletResponse
2
3 import javax.servlet.http.HttpServletResponseWrapper
4 import javax.servlet.http.HttpServletResponse
5
6 /**
7 * 功能描述
8 * @author huzl
9 * @version 0.0.1, 12-7-30 下午3:11
10 */
11 class StatusExposingServletResponse extends HttpServletResponseWrapper {
12 private Integer status = SC_OK;;
13
14 public Integer getStatus() {
15 return status
16 }
17
18 def StatusExposingServletResponse(HttpServletResponse response) {
19 super(response);
20 }
21
22 @Override
23 void sendError(int sc, String msg) {
24 super.sendError(sc, msg)
25 status = sc;
26 }
27
28 @Override
29 void sendError(int sc) {
30 super.sendError(sc)
31 status = sc;
32 }
33
34 @Override
35 void sendRedirect(String location) {
36 super.sendRedirect(location)
37 status = SC_MOVED_TEMPORARILY;
38 }
39
40 @Override
41 void setStatus(int sc) {
42 super.setStatus(sc)
43 status = sc;
44 }
45
46 @Override
47 void setStatus(int sc, String sm) {
48 super.setStatus(sc, sm)
49 status = sc;
50 }
51
52 }
53
54 public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain){
55 long startTime = System.currentTimeMillis();
56 StatusExposingServletResponse response = new StatusExposingServletResponse(servletResponse);
57 Throwable exception = null;
58 try {
59 filterChain.doFilter(servletRequest,response)
60 } catch (Throwable e) {
61 exception = e;
62 throw e;
63 }finally{
64 statisticResult.completeRequest(servletRequest,response,exception,startTime);
65 }
66 }
若只统计错误状态码则区分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 var charts = new Array();
2 var serverCount = 6;
3 var lastTimes = new Array();
4 var max = ${params.int("max")?:120};
5 $(document).ready(function() {
6 Highcharts.setOptions({
7 global: {
8 useUTC: false
9 }
10 });
11
12
13 for (var i = 0; i < serverCount; i++) {
14 charts[i] = new Highcharts.Chart({
15 chart: {
16 renderTo: 'container' + i,
17 type: 'spline',
18 events: {
19 load: function() {
20
21 // set up the updating of the chart each second
22 var series = this.series;
23 var serverIndex = i;
24 lastTimes[serverIndex] = 0;
25 var loadData = function() {
26 $.getJSON("http://${request.serverName}:${request.serverPort}${request.contextPath}/toolkits/queryStatistics.gsp", {"lasTime":lastTimes[serverIndex],"proxy":true,"index":serverIndex,"max":max}, function(data) {
27 for (var k = 0; k < series.length; k++) {
28 for (var j = 0; j < data[k].length; j++) {
29 var point = data[k][j];
30 var isShift = series[k].data.length >= max;
31 console.log("series " + k + ".data.length=" + series[k].data.length);
32 var lastTime = 0;
33 if (series[k].data.length > 0)
34 lastTime = series[k].data[series[k].data.length - 1].x;
35 if (point[0] > lastTime)
36 series[k].addPoint([point[0],point[1]], true, isShift);
37 lastTimes[serverIndex] = point[0];
38 }
39 }
40 })
41 };
42
43 loadData();
44 setInterval(loadData, 60000);
45 }
46 }
47 },
48 title: {
49 text: '访问量实时监控'
50 },
51 xAxis: [
52 {
53 type: 'datetime',
54 tickPixelInterval: 120
55 }
56 ],
57 yAxis: [
58 {
59 title: {
60 text: '总请求/分钟',
61 style: {
62 color: '#3E576F'
63 }
64 }
65 },
66 {
67 title: {
68 text: '平均响应时间',
69 style: {
70 color: '#00AA00'
71 }
72 },opposite:true
73 }
74 ],
75 plotOptions: {
76 spline: {
77 marker:{
78 enabled: false,
79 states: {
80 hover: {
81 enabled: true,
82 symbol: 'circle',
83 radius: 5,
84 lineWidth: 1
85 }
86 }
87 }
88 }
89 },
90 tooltip: {
91 formatter: function() {
92 return '<b>' + this.series.name + '</b><br/>' +
93 Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
94 Highcharts.numberFormat(this.y, 2);
95 }
96 },
97 legend: {
98 enabled: true
99 },
100 exporting: {
101 enabled: false
102 },
103 series: [
104 {
105 name: '总请求数',
106 data: []
107 },
108 {
109 name: '错误请求数',
110 data: []
111 },
112 {
113 name: '平均响应时间',
114 yAxis:1,
115 data: []
116 }
117 ]
118 });
119 }
120
121 })
需要注意的是:
1、在series的load事件中使用ajax定时加载数据,需要控制当前chart中的Point数据量,
series.addPoint(point, true, isShift);
当series中Point数量超过指定值,设定isShift为true,就可以移除第一个Point,防止浏览器内存占用太大无响应
2、ajax请求时只请求最新采集数据,所以每次加载采集数据后把最后时间保留下来,ajax请求时把当前chart中最后时间带上,获取最新数据
3、其他非关键代码就不附上了,因为使用grails工程而且与项目xiangg