Просмотр исходного кода

:construction: api性能实时监控

visuddhinanda@gmail.com 4 лет назад
Родитель
Сommit
fe4e0a2138

+ 23 - 0
public/app/log/loglist.php

@@ -0,0 +1,23 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+</head>
+<body>
+<ol>
+<?php
+require_once("../config.php");
+$scan = scandir(_DIR_LOG_);
+$fileCounter = 0;
+
+foreach($scan as $filename) {
+	if (is_file(_DIR_LOG_."/".$filename)){
+		if(substr($filename,0,5)=='pref_'){
+			$date = substr($filename,5,-4);
+			echo "<li><a href='showlog.php?file={$filename}' target='log'>".$date.'</a></li>';
+		}
+	}
+}
+?>
+</ol>
+</body>
+</html>

+ 10 - 0
public/app/log/performance.html

@@ -0,0 +1,10 @@
+<html>
+
+<frameset cols="15%,85%">
+
+<frame src="./loglist.php">
+<frame src="" name="log">
+
+</frameset>
+
+</html>

+ 37 - 0
public/app/log/pref_live.php

@@ -0,0 +1,37 @@
+<?php
+require_once(__DIR__."/../config.php");
+require_once(__DIR__."/../redis/function.php");
+
+
+if(isset($_GET["item"])){
+    $item = $_GET["item"];
+}else{
+    return 1;
+}
+if(isset($_GET["api"])){
+    $api = $_GET["api"];
+}else{
+    $api = "all";
+}
+    $times = 10;
+    $key= "pref-s/";
+    $redis = redis_connect();
+    $currTime = time();
+    if($redis){
+        $begin = $currTime - $times - 1;
+        $value = 0;
+        for ($i=$begin; $i <= $currTime; $i++) { 
+            $keyAll = $key.$api."/".$i;
+            if($redis->exists($keyAll)){
+                if($item == 'average'){
+                    $value += intval($redis->hGet($keyAll,'delay') / $redis->hGet($keyAll,'count'));
+                }else{
+                    $value += (int)$redis->hGet($keyAll,$item);
+                }
+            }
+        }
+        $value = $value/$times;
+        echo $value;
+    }else{
+        echo 'redis error';
+    }

+ 37 - 0
public/app/log/pref_log.php

@@ -1,8 +1,33 @@
 <?php
 require_once("../config.php");
+require_once("../redis/function.php");
+
+
 $logstart = microtime(true)*1000;
+$iTime = time();
 $strstart = date("h:i:sa");
 function PrefLog(){
+    $delay = microtime(true)*1000-$GLOBALS['logstart'];
+    $redis = redis_connect();
+    $timeMinute = intval(time()/60);
+    $timeSecond = time();
+    if($redis){
+        $key= "pref/";
+        $keyAll = $key."all/".$timeMinute;
+        UpdateCache($redis,$keyAll,$delay);
+        $keyApi = $key.$_SERVER['PHP_SELF']."/".$timeMinute;
+        UpdateCache($redis,$keyApi,$delay);
+
+        $key= "pref-s/";
+        $keyAll = $key."all/".$timeSecond;
+        UpdateCache($redis,$keyAll,$delay,30);
+        $keyApi = $key.$_SERVER['PHP_SELF']."/".$timeSecond;
+        UpdateCache($redis,$keyApi,$delay,30);
+
+        $keyApiName = "pref-hour/api/".$_SERVER['PHP_SELF'];
+        $redis->set($keyApiName,1);
+        $redis->expire($keyApiName,3600);
+    }
 	$file = fopen(_DIR_LOG_."/pref_".date("Y-m-d").".log","a");
 	if($file){
 		fputcsv($file,[$_SERVER['PHP_SELF'],$GLOBALS['strstart'],sprintf("%d",microtime(true)*1000-$GLOBALS['logstart']),$_SERVER['REMOTE_ADDR']]);
@@ -10,5 +35,17 @@ function PrefLog(){
 	}
 }
 
+function UpdateCache($redis,$key,$delay,$expire=3600){
+
+        if($redis->exists($key)){
+            $redis->hSet($key,"count",$redis->hGet($key,"count")+1);
+            $redis->hSet($key,"delay",$redis->hGet($key,"delay")+$delay);
+        }else{
+            #没有,创建
+            $redis->hSet($key,"count",1);
+            $redis->hSet($key,"delay",$delay);
+            $redis->expire($key,$expire);
+        }
+}
 
 ?>

+ 37 - 0
public/app/log/pref_realtime_get.php

@@ -0,0 +1,37 @@
+<?php
+require_once("../config.php");
+require_once("../redis/function.php");
+
+echo "Time, Value".PHP_EOL;
+if(isset($_GET["item"])){
+    $item = $_GET["item"];
+}else{
+    return 1;
+}
+if(isset($_GET["api"])){
+    $api = $_GET["api"];
+}else{
+    $api = "all";
+}
+    $key= "pref/";
+    $redis = redis_connect();
+    $currMinute = intval(time()/60);
+    if($redis){
+        $begin = $currMinute - 60;
+        for ($i=$begin; $i < $currMinute; $i++) { 
+            $keyAll = $key.$api."/".$i;
+            if($redis->exists($keyAll)){
+                if($item == 'average'){
+                    $value = $redis->hGet($keyAll,'delay') / $redis->hGet($keyAll,'count');
+                }else{
+                    $value = $redis->hGet($keyAll,$item);
+                }
+            }else{
+                $value = 0;
+            }
+            $time = date("Y-m-d\TH:i:s.u\Z",$i*60);
+            echo "{$time},{$value}".PHP_EOL;
+        }
+    }else{
+        echo "Time, Value";
+    }

+ 608 - 0
public/app/log/showlog.js

@@ -0,0 +1,608 @@
+
+function getData(filename){
+	$.get("../../tmp/log/"+filename,
+	function(data,status){
+	  
+	//生成数据数组
+	  let rowData= data.split('\n');
+	  let arrData = new Array();
+	  for (const iterator of rowData) {
+		arrData.push(iterator.split(","));
+	  }
+	  console.log(arrData);
+	  let api = new Object;
+	  let delayInMinute
+	  
+	  //遍历所有数据
+	  for (const iterator of arrData) {
+		let delay = parseInt(iterator[2]);
+		if (api.hasOwnProperty.call(api, iterator[0])) {
+			let element = api[iterator[0]];
+			element.times++;
+			element.delay += delay;
+			try{
+				let hour = parseInt(iterator[1].split(':')[0]);
+				element.delayHour[hour] += delay;
+				if(delay>api[iterator[0]].delayMaxHour[hour]){
+					api[iterator[0]].delayMaxHour[hour] = delay;
+				}
+				if(delay < api[iterator[0]].delayMinHour[hour]){
+					api[iterator[0]].delayMinHour[hour] = delay;
+				}	
+				element.timesHour[hour] ++;
+				
+			}catch(e){
+
+			}
+
+		}else{
+			api[iterator[0]] = {
+				times:1,
+				timesHour:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+				delay:delay,
+				//一小时总执行时间
+				delayHour:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+				//一小时最高执行时间
+				delayMaxHour:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+				//一小时最低执行时间
+				
+				delayMinHour:[30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000,30000],
+				//一小时平均执行时间
+				delayAverageHour:[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
+			};
+			try{
+				let hour = parseInt(iterator[1].split(':')[0]);
+				api[iterator[0]].delayHour[hour] = parseInt(iterator[2]);
+				api[iterator[0]].delayMaxHour[hour] = parseInt(iterator[2]);
+				api[iterator[0]].delayMinHour[hour] = parseInt(iterator[2]);
+				api[iterator[0]].timesHour[hour] = 1;
+			}catch(e){
+
+			}
+
+		}
+	  }
+	  let api_timms = new Array();
+	  let api_delay = new Array();
+	  let ApiDelayInHour = new Array();
+	  let ApiTimesInHour = new Array();
+	  let ApiAverageInHour = new Array();
+	  let ohlc = new Array();
+	  let volume = new Array();
+	  for (const key in api) {
+		  if (api.hasOwnProperty.call(api, key)) {
+			  //计算每个小时的平均执行时间
+			  for (let index = 0; index < api[key].delayAverageHour.length; index++) {
+				  api[key].delayAverageHour[index] = api[key].delayHour[index]/api[key].timesHour[index];
+			  }
+			  const element = api[key];
+			  api_timms.push({
+				  name:key,
+				  y:element.times
+			  });
+			  api_delay.push({
+				name:key,
+				y:element.delay
+			  });
+			  ApiDelayInHour.push({
+				name:key,
+				data:element.delayHour
+			  });
+			  ApiTimesInHour.push({
+				name:key,
+				data:element.timesHour
+			  });
+			  ApiAverageInHour.push({
+				name:key,
+				data:element.delayAverageHour
+			  });
+			  for (let index = 1; index < api[key].delayAverageHour.length; index++) {
+				api[key].delayAverageHour[index] = api[key].delayHour[index]/api[key].timesHour[index];
+				if(key=="/app/uwbw/update.php"){
+					ohlc.push([
+						Date.UTC(2022,1,1,index,0,0,0), // the date
+						api[key].delayAverageHour[index-1], // open
+						api[key].delayMaxHour[index], // high
+						api[key].delayMinHour[index], // low
+						api[key].delayAverageHour[index] // close
+					]);
+			
+					volume.push([
+						Date.UTC(2022,1,1,index,0,0,0), // the date
+						element.timesHour[index] // the volume
+					]);
+				}				
+			  }
+
+		  }
+	  }
+
+	  chart_1(api_timms);
+	  chart_2(api_delay);
+	  chart_3(ApiDelayInHour);
+	  chart_3a(ApiAverageInHour);
+	  chart_4(ApiTimesInHour);
+	  chart_5(ohlc,volume);
+	  chart_6(ohlc,volume);
+	});
+  
+}
+
+function chart_1(data){
+	// Make monochrome colors
+var pieColors = (function () {
+    var colors = [],
+        base = Highcharts.getOptions().colors[0],
+        i;
+
+    for (i = 0; i < 10; i += 1) {
+        // Start out with a darkened base color (negative brighten), and end
+        // up with a much brighter color
+        colors.push(Highcharts.color(base).brighten((i - 3) / 7).get());
+    }
+    return colors;
+}());
+
+// Build the chart
+Highcharts.chart('chart-1', {
+    chart: {
+        plotBackgroundColor: null,
+        plotBorderWidth: null,
+        plotShadow: false,
+        type: 'pie'
+    },
+    title: {
+        text: 'API 执行次数'
+    },
+    tooltip: {
+        pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
+    },
+    accessibility: {
+        point: {
+            valueSuffix: '%'
+        }
+    },
+    plotOptions: {
+        pie: {
+            allowPointSelect: true,
+            cursor: 'pointer',
+            colors: pieColors,
+            dataLabels: {
+                enabled: true,
+                format: '<b>{point.name}</b><br>{point.percentage:.1f} %',
+                distance: -50,
+                filter: {
+                    property: 'percentage',
+                    operator: '>',
+                    value: 4
+                }
+            }
+        }
+    },
+    series: [{
+        name: 'Share',
+        data: data
+    }]
+});
+}
+
+function chart_2(data){
+	// Make monochrome colors
+var pieColors = (function () {
+    var colors = [],
+        base = Highcharts.getOptions().colors[0],
+        i;
+
+    for (i = 0; i < 10; i += 1) {
+        // Start out with a darkened base color (negative brighten), and end
+        // up with a much brighter color
+        colors.push(Highcharts.color(base).brighten((i - 3) / 7).get());
+    }
+    return colors;
+}());
+
+// Build the chart
+Highcharts.chart('chart-2', {
+    chart: {
+        plotBackgroundColor: null,
+        plotBorderWidth: null,
+        plotShadow: false,
+        type: 'pie'
+    },
+    title: {
+        text: 'API 累积执行时间'
+    },
+    tooltip: {
+        pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>'
+    },
+    accessibility: {
+        point: {
+            valueSuffix: '%'
+        }
+    },
+    plotOptions: {
+        pie: {
+            allowPointSelect: true,
+            cursor: 'pointer',
+            colors: pieColors,
+            dataLabels: {
+                enabled: true,
+                format: '<b>{point.name}</b><br>{point.percentage:.1f} %',
+                distance: -50,
+                filter: {
+                    property: 'percentage',
+                    operator: '>',
+                    value: 4
+                }
+            }
+        }
+    },
+    series: [{
+        name: 'Share',
+        data: data
+    }]
+});
+}
+
+//按照小时计算的api 执行时间
+function chart_3(data){
+	Highcharts.chart('chart-3', {
+
+		title: {
+			text: '按照小时计算的 API 执行时间'
+		},
+	
+		subtitle: {
+			text: 'Source: thesolarfoundation.com'
+		},
+	
+		yAxis: {
+			title: {
+				text: '执行时间'
+			}
+		},
+	
+		xAxis: {
+			categories: [
+				'8',
+				'9',
+				'10',
+				'11',
+				'12',
+				'13',
+				'14',
+				'15',
+				'16',
+				'17',
+				'18',
+				'19',
+				'20',
+				'21',
+				'22',
+				'23',
+				'0',
+				'1',
+				'2',
+				'3',
+				'4',
+				'5',
+				'6',
+				'7'
+			],
+			accessibility: {
+				rangeDescription: 'Range: 0 to 23'
+			}
+		},
+	
+		legend: {
+			layout: 'vertical',
+			align: 'right',
+			verticalAlign: 'middle'
+		},
+	
+		plotOptions: {
+			series: {
+				label: {
+					connectorAllowed: false
+				},
+				pointStart: 0
+			}
+		},
+	
+		series: data,
+	
+		responsive: {
+			rules: [{
+				condition: {
+					maxWidth: 500
+				},
+				chartOptions: {
+					legend: {
+						layout: 'horizontal',
+						align: 'center',
+						verticalAlign: 'bottom'
+					}
+				}
+			}]
+		}
+	
+	});
+}
+function chart_3a(data){
+	Highcharts.chart('chart-3a', {
+
+		title: {
+			text: '按照小时计算的 API 平均执行时间'
+		},
+	
+		subtitle: {
+			text: '总执行时间/次数'
+		},
+	
+		yAxis: {
+			title: {
+				text: '执行时间'
+			}
+		},
+	
+		xAxis: {
+			categories: [
+				'8',
+				'9',
+				'10',
+				'11',
+				'12',
+				'13',
+				'14',
+				'15',
+				'16',
+				'17',
+				'18',
+				'19',
+				'20',
+				'21',
+				'22',
+				'23',
+				'0',
+				'1',
+				'2',
+				'3',
+				'4',
+				'5',
+				'6',
+				'7'
+			],
+			accessibility: {
+				rangeDescription: 'Range: 0 to 23'
+			}
+		},
+	
+		legend: {
+			layout: 'vertical',
+			align: 'right',
+			verticalAlign: 'middle'
+		},
+	
+		plotOptions: {
+			series: {
+				label: {
+					connectorAllowed: false
+				},
+				pointStart: 0
+			}
+		},
+	
+		series: data,
+	
+		responsive: {
+			rules: [{
+				condition: {
+					maxWidth: 500
+				},
+				chartOptions: {
+					legend: {
+						layout: 'horizontal',
+						align: 'center',
+						verticalAlign: 'bottom'
+					}
+				}
+			}]
+		}
+	
+	});
+}
+function chart_4(data){
+	Highcharts.chart('chart-4', {
+		chart: {
+			type: 'column'
+		},
+		title: {
+			text: 'API 执行次数'
+		},
+		subtitle: {
+			text: 'Source: WorldClimate.com'
+		},
+		xAxis: {
+			categories: [
+				'8',
+				'9',
+				'10',
+				'11',
+				'12',
+				'13',
+				'14',
+				'15',
+				'16',
+				'17',
+				'18',
+				'19',
+				'20',
+				'21',
+				'22',
+				'23',
+				'0',
+				'1',
+				'2',
+				'3',
+				'4',
+				'5',
+				'6',
+				'7'
+			],
+			crosshair: true
+		},
+		yAxis: {
+			min: 0,
+			title: {
+				text: '执行次数'
+			}
+		},
+		legend: {
+			layout: 'vertical',
+			align: 'right',
+			verticalAlign: 'middle'
+		},
+		tooltip: {
+			headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
+			pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
+				'<td style="padding:0"><b>{point.y} 次</b></td></tr>',
+			footerFormat: '</table>',
+			shared: true,
+			useHTML: true
+		},
+		plotOptions: {
+			column: {
+				pointPadding: 0.2,
+				borderWidth: 0
+			}
+		},
+		series: data
+	});
+}
+
+function chart_6(ohlc,volume){
+{
+
+    // create the chart
+    Highcharts.stockChart('chart-6', {
+
+
+        title: {
+            text: 'AAPL stock price by minute'
+        },
+
+        rangeSelector: {
+            buttons: [{
+                type: 'hour',
+                count: 1,
+                text: '1h'
+            }, {
+                type: 'day',
+                count: 1,
+                text: '1D'
+            }, {
+                type: 'all',
+                count: 1,
+                text: 'All'
+            }],
+            selected: 1,
+            inputEnabled: false
+        },
+
+        series: [{
+            name: 'AAPL',
+            type: 'candlestick',
+            data: ohlc,
+            tooltip: {
+                valueDecimals: 2
+            }
+        }]
+    });
+}
+}
+
+function chart_5(ohlc,volume){
+	  // create the chart
+	  groupingUnits = [[
+		'week',                         // unit name
+		[1]                             // allowed multiples
+	], [
+		'month',
+		[1, 2, 3, 4, 6]
+	]];
+	  Highcharts.stockChart('chart-5', {
+
+
+		rangeSelector: {
+		  selected: 2
+		},
+	
+		title: {
+		  text: 'progress_curve'
+		},
+			yAxis: [{
+				labels: {
+					align: 'right',
+					x: -3
+				},
+				title: {
+					text: 'EXP'
+				},
+				height: '60%',
+				lineWidth: 2,
+				resize: {
+					enabled: true
+				}
+			}, {
+				labels: {
+					align: 'right',
+					x: -3
+				},
+				title: {
+					text: 'action'
+				},
+				top: '65%',
+				height: '35%',
+				offset: 0,
+				lineWidth: 2
+			}],
+	
+		tooltip: {
+				shared: false,
+				useHTML: true,
+				pointFormatter: function() {
+					if(this.high){
+						return '<b><a href="../">'+this.series.name + ' : ' + this.high + '&nbsp;' +'gLocal.gui.h'+ '</a><br><a href="../">' +'gLocal.gui.day_EXP' + ' : ' + Math.round((this.high - this.low)*100)/100 + '&nbsp;' +'gLocal.gui.h'+'</a></b><br/>'; 
+					}
+					else{
+						return '<b><a href="../">'+this.series.name + ' : ' + this.y + '&nbsp;' +'gLocal.gui.times'+'</a><span style="display:none;">'+this.x+'</span></b>'; 
+					}
+				},
+				valueDecimals: 2,//保留两位小數
+				split: true
+			},
+	
+		series: [{
+		  type: 'ohlc',
+		  name: 'gLocal.gui.EXP_in_total',
+		  data: ohlc,
+		  dataGrouping: {
+			units: [[
+			  'week', // unit name
+			  [1] // allowed multiples
+			], [
+			  'month',
+			  [1, 2, 3, 4, 6]
+			]]
+		  }
+			}, {
+				type: 'column',
+				name: 'gLocal.gui.day_action',
+				data: volume,
+				yAxis: 1,
+				dataGrouping: {
+					units: groupingUnits
+				}
+			}]
+	  });
+}

+ 86 - 0
public/app/log/showlog.php

@@ -0,0 +1,86 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+	<meta name="viewport" content="width=device-width, initial-scale=1">
+	<script src="../../node_modules/jquery/dist/jquery.js"></script>
+
+	<style type="text/css">
+
+	.highcharts-figure, .highcharts-data-table table {
+		flex:1;
+		min-width: 220px; 
+		max-width: 100%;
+		margin: 1em auto;
+	}
+
+	.highcharts-data-table table {
+		font-family: Verdana, sans-serif;
+		border-collapse: collapse;
+		border: 1px solid #EBEBEB;
+		margin: 10px auto;
+		text-align: center;
+		width: 100%;
+		max-width: 500px;
+	}
+	.highcharts-data-table caption {
+		padding: 1em 0;
+		font-size: 1.2em;
+		color: #555;
+	}
+	.highcharts-data-table th {
+		font-weight: 600;
+		padding: 0.5em;
+	}
+	.highcharts-data-table td, .highcharts-data-table th, .highcharts-data-table caption {
+		padding: 0.5em;
+	}
+	.highcharts-data-table thead tr, .highcharts-data-table tr:nth-child(even) {
+		background: #f8f8f8;
+	}
+	.highcharts-data-table tr:hover {
+		background: #f1f7ff;
+	}
+	.chart_head_1 {
+		text-align: center;
+		font-size: x-large;
+		margin-bottom: 0;
+		font-weight: bold;
+	}
+	.highcharts-data-label {
+		font-size: small;
+	}
+	</style>
+
+	<script src="../../node_modules/highcharts/highstock.js"></script>
+	<script src="../../node_modules/highcharts/modules/data.js"></script>
+	<script src="../../node_modules/highcharts/modules/exporting.js"></script>
+
+	<script src="./showlog.js"></script>
+
+</head>
+<body>
+<h2><?php echo $_GET['file'];?></h2>
+<div style="display:flex;">
+<div id='chart-1'></div>
+<div id='chart-2'></div>
+</div>
+<div id='chart-3'></div>
+<div id='chart-4'></div>
+<div id='chart-3a'></div>
+<div id='chart-5'></div>
+
+<div id="chart-6"></div>
+
+
+
+
+<script>
+
+</script>
+
+<script type="text/javascript">
+getData('<?php echo $_GET['file'];?>');
+</script>
+</body>
+</html>

+ 144 - 0
public/app/log/showrealtime.js

@@ -0,0 +1,144 @@
+
+var apiName="all";
+
+function createChart(div,title,api,item) {
+    Highcharts.chart(div, {
+        chart: {
+            type: 'spline'
+        },
+        title: {
+            text: title
+        },
+        accessibility: {
+            announceNewData: {
+                enabled: true,
+                minAnnounceInterval: 15000,
+                announcementFormatter: function (allSeries, newSeries, newPoint) {
+                    if (newPoint) {
+                        return 'New point added. Value: ' + newPoint.y;
+                    }
+                    return false;
+                }
+            }
+        },
+        data: {
+            csvURL: './pref_realtime_get.php?api='+api+'&item='+item,
+            enablePolling: true,
+            dataRefreshRate: 60
+        }
+    });
+
+
+}
+
+
+
+function create_live(container,title,api){
+    Highcharts.chart(container, {
+
+    chart: {
+        type: 'gauge',
+        plotBackgroundColor: null,
+        plotBackgroundImage: null,
+        plotBorderWidth: 0,
+        plotShadow: false
+    },
+
+    title: {
+        text: title
+    },
+
+    pane: {
+        startAngle: -150,
+        endAngle: 150,
+        background: [{
+            backgroundColor: {
+                linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
+                stops: [
+                    [0, '#FFF'],
+                    [1, '#333']
+                ]
+            },
+            borderWidth: 0,
+            outerRadius: '109%'
+        }, {
+            backgroundColor: {
+                linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
+                stops: [
+                    [0, '#333'],
+                    [1, '#FFF']
+                ]
+            },
+            borderWidth: 1,
+            outerRadius: '107%'
+        }, {
+            // default background
+        }, {
+            backgroundColor: '#DDD',
+            borderWidth: 0,
+            outerRadius: '105%',
+            innerRadius: '103%'
+        }]
+    },
+
+    // the value axis
+    yAxis: {
+        min: 0,
+        max: 5000,
+
+        minorTickInterval: 'auto',
+        minorTickWidth: 1,
+        minorTickLength: 10,
+        minorTickPosition: 'inside',
+        minorTickColor: '#666',
+
+        tickPixelInterval: 30,
+        tickWidth: 2,
+        tickPosition: 'inside',
+        tickLength: 10,
+        tickColor: '#666',
+        labels: {
+            step: 2,
+            rotation: 'auto'
+        },
+        title: {
+            text: '毫秒/API'
+        },
+        plotBands: [{
+            from: 0,
+            to: 2000,
+            color: '#55BF3B' // green
+        }, {
+            from: 2000,
+            to: 3500,
+            color: '#DDDF0D' // yellow
+        }, {
+            from: 3500,
+            to: 5000,
+            color: '#DF5353' // red
+        }]
+    },
+
+    series: [{
+        name: 'Speed',
+        data: [80],
+        tooltip: {
+            valueSuffix: ' ms/s'
+        }
+    }]
+
+},
+// Add some life
+function (chart) {
+    if (!chart.renderer.forExport) {
+        setInterval(function () {
+            $.get("./pref_live.php?api="+api+"&item=average",function(data){
+                var point = chart.series[0].points[0];
+                newVal = parseInt(data);
+                point.update(newVal);
+            });
+        }, 3000);
+    }
+});
+
+}

+ 124 - 0
public/app/log/showrealtime.php

@@ -0,0 +1,124 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+	<meta name="viewport" content="width=device-width, initial-scale=1">
+	<script src="../../node_modules/jquery/dist/jquery.js"></script>
+
+	<style type="text/css">
+
+	.highcharts-figure, .highcharts-data-table table {
+		flex:1;
+		min-width: 220px; 
+		max-width: 100%;
+		margin: 1em auto;
+	}
+
+	.highcharts-data-table table {
+		font-family: Verdana, sans-serif;
+		border-collapse: collapse;
+		border: 1px solid #EBEBEB;
+		margin: 10px auto;
+		text-align: center;
+		width: 100%;
+		max-width: 500px;
+	}
+	.highcharts-data-table caption {
+		padding: 1em 0;
+		font-size: 1.2em;
+		color: #555;
+	}
+	.highcharts-data-table th {
+		font-weight: 600;
+		padding: 0.5em;
+	}
+	.highcharts-data-table td, .highcharts-data-table th, .highcharts-data-table caption {
+		padding: 0.5em;
+	}
+	.highcharts-data-table thead tr, .highcharts-data-table tr:nth-child(even) {
+		background: #f8f8f8;
+	}
+	.highcharts-data-table tr:hover {
+		background: #f1f7ff;
+	}
+	.chart_head_1 {
+		text-align: center;
+		font-size: x-large;
+		margin-bottom: 0;
+		font-weight: bold;
+	}
+	.highcharts-data-label {
+		font-size: small;
+	}
+	</style>
+
+
+
+<script src="../../node_modules/highcharts/highcharts.js"></script>
+<script src="../../node_modules/highcharts/highcharts-more.js"></script>
+<script src="../../node_modules/highcharts/modules/exporting.js"></script>
+<script src="../../node_modules/highcharts/modules/export-data.js"></script>
+<script src="../../node_modules/highcharts/modules/accessibility.js"></script>
+
+	<script src="../../node_modules/highcharts/modules/data.js"></script>
+	<script src="../../node_modules/highcharts/modules/exporting.js"></script>
+
+</head>
+<body>
+<h2>实时监控</h2>
+<?php
+require_once(__DIR__."/../config.php");
+require_once(__DIR__."/../redis/function.php");
+$redis = redis_connect();
+if($redis){
+    $key="pref-hour/api/";
+    $apis = $redis->keys($key.'*');
+    echo "<ol>";
+    echo "<li><a href='showrealtime.php?api=all'>all</a></li>";
+    foreach ($apis as  $value) {
+        $api = substr($value,strlen($key));
+        echo "<li><a  href='showrealtime.php?api={$api}'>".$api."</a></li>";
+    }
+    echo "</ol>";
+}
+?>
+<div class="ld-row" style="display:none;">
+	<label class="ld-label">
+		Enable Polling
+	</label>
+	<input type="checkbox" checked="checked" id="enablePolling"/>
+</div>
+<div style="display:flex;">
+    <div id='chart-1'></div>
+    <div id='chart-2'></div>
+</div>
+<div style="display:flex;">
+    <div id='chart-3'></div>
+    <div id='chart-4'></div>
+</div>
+<div id='chart-3a'></div>
+<div id='chart-5'></div>
+
+<div id="chart-6"></div>
+
+
+<script src="./showrealtime.js"></script>
+
+<script>
+<?php 
+    if(isset($_GET["api"])){
+        echo "apiName = '{$_GET["api"]}';";
+    }else{
+         echo "apiName = 'all';";
+    }
+    
+?>
+
+// Create the chart
+createChart("chart-1",'总请求次数/分钟',apiName,'count');
+createChart("chart-2",'总响应时间(毫秒/分钟)',apiName,'delay');
+createChart("chart-3",'平均响应时间(毫秒/API)',apiName,'average');
+create_live("chart-4","实时响应时间(毫秒/API)",apiName);
+</script>
+</body>
+</html>