Added graph Intervall, Shift Sliders

master
Harald Wolff 2019-10-15 12:20:36 +02:00
parent f6d962ed5e
commit e6d6b16430
8 changed files with 215 additions and 24 deletions

View File

@ -17,11 +17,14 @@ namespace ln.skyscanner.checks
{ {
public enum CheckState { OK, WARN, CRITICAL, FAIL, ERROR } public enum CheckState { OK, WARN, CRITICAL, FAIL, ERROR }
public struct CheckStateChange public class CheckStateChange
{ {
public CheckState NewState; public CheckState NewState;
public DateTime Timestamp; public DateTime Timestamp;
private CheckStateChange()
{
}
public CheckStateChange(CheckState checkState) public CheckStateChange(CheckState checkState)
{ {
NewState = checkState; NewState = checkState;

View File

@ -108,11 +108,11 @@ namespace ln.skyscanner.services
PerformanceValueService = performanceValueService; PerformanceValueService = performanceValueService;
} }
public PerfValue[] GetPerfData(string[] perfPath,int timeWindow = 3600) public PerfValue[] GetPerfData(string[] perfPath,int timeWindow,int timeSkip)
{ {
PerfFile perfFile = PerformanceValueService.GetPerfFile(perfPath); PerfFile perfFile = PerformanceValueService.GetPerfFile(perfPath);
perfFile.EnsureOpen(); perfFile.EnsureOpen();
PerfValue[] perfData = perfFile.QueryTime(timeWindow, 0); PerfValue[] perfData = perfFile.QueryTime(timeWindow, timeSkip);
return perfData; return perfData;
} }
} }

View File

@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.application", "..\ln.app
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.json", "..\ln.json\ln.json.csproj", "{D9342117-3249-4D8B-87C9-51A50676B158}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ln.json", "..\ln.json\ln.json.csproj", "{D9342117-3249-4D8B-87C9-51A50676B158}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "odb.tool", "..\odb.tool\odb.tool.csproj", "{24C9C372-DCA6-420D-ACD3-5C89C6935D6A}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86 Debug|x86 = Debug|x86
@ -67,5 +69,9 @@ Global
{D9342117-3249-4D8B-87C9-51A50676B158}.Debug|x86.Build.0 = Debug|Any CPU {D9342117-3249-4D8B-87C9-51A50676B158}.Debug|x86.Build.0 = Debug|Any CPU
{D9342117-3249-4D8B-87C9-51A50676B158}.Release|x86.ActiveCfg = Release|Any CPU {D9342117-3249-4D8B-87C9-51A50676B158}.Release|x86.ActiveCfg = Release|Any CPU
{D9342117-3249-4D8B-87C9-51A50676B158}.Release|x86.Build.0 = Release|Any CPU {D9342117-3249-4D8B-87C9-51A50676B158}.Release|x86.Build.0 = Release|Any CPU
{24C9C372-DCA6-420D-ACD3-5C89C6935D6A}.Debug|x86.ActiveCfg = Debug|x86
{24C9C372-DCA6-420D-ACD3-5C89C6935D6A}.Debug|x86.Build.0 = Debug|x86
{24C9C372-DCA6-420D-ACD3-5C89C6935D6A}.Release|x86.ActiveCfg = Release|x86
{24C9C372-DCA6-420D-ACD3-5C89C6935D6A}.Release|x86.Build.0 = Release|x86
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

View File

@ -481,4 +481,12 @@ span#nWARN, span#nCRITICAL, span#nOK {
text-decoration: underline; text-decoration: underline;
} }
input.ln-slider {
display: block;
width: 100%;
}
div.ln-slider {
width: 360px;
text-align: center;
}

View File

@ -28,6 +28,9 @@
this.currentNodes = []; this.currentNodes = [];
this.currentAction = "";
this.currentState = "";
this.issues = { this.issues = {
OK: 0, OK: 0,
WARN: 0, WARN: 0,
@ -50,6 +53,14 @@
return initializers; return initializers;
} }
action(msg){
this.currentAction = msg;
}
state(msg){
this.currentState = msg;
}
wsUpdate(state) wsUpdate(state)
{ {
try try
@ -80,11 +91,12 @@
updateIssues(){ updateIssues(){
var self = this; var self = this;
console.log("Update issue list");
LN().rpc("CheckService","GetIssueList",[],function(r,e){ this.action("updating issue list...");
LN().rpc("CheckService","GetIssueList",[],(r,e) => {
if (e){ if (e){
alert("Error fetching current issue list!\n" + JSON.stringify(e)); self.state("Error fetching current issue list!\n" + JSON.stringify(e));
} else { } else {
self.currentIssues = r; self.currentIssues = r;
@ -103,6 +115,7 @@
self.lastIssueUpdate = moment().format(); self.lastIssueUpdate = moment().format();
} }
self.currentTimeout = setTimeout(function(){ self.updateIssues(); }, 10000); self.currentTimeout = setTimeout(function(){ self.updateIssues(); }, 10000);
this.action("");
}); });
} }
@ -153,7 +166,9 @@
loadNode(nodeID,cb,refreshIntervall){ loadNode(nodeID,cb,refreshIntervall){
var self = this; var self = this;
LN().rpc("entities","GetNode",[nodeID,],function(r,e){ this.action("loading node " + nodeID);
LN().rpc("entities","GetNode",[nodeID,],(r,e) => {
if (refreshIntervall && self.currentTimeout) if (refreshIntervall && self.currentTimeout)
clearTimeout(self.currentTimeout); clearTimeout(self.currentTimeout);
@ -164,6 +179,8 @@
setTimeout(()=>{ setTimeout(()=>{
self.loadNode(nodeID,cb,refreshIntervall); self.loadNode(nodeID,cb,refreshIntervall);
}, refreshIntervall); }, refreshIntervall);
this.action("");
}); });
} }
@ -172,8 +189,8 @@
return ("" + t).replace( /[\.\/]/g, "_"); return ("" + t).replace( /[\.\/]/g, "_");
} }
loadPerformanceGraph(perfPath,interval,cb){ loadPerformanceGraph(perfPath,interval,shift,cb){
LN().rpc("perfValues","GetPerfData",[perfPath,interval],(perfData,e)=>{ LN().rpc("perfValues","GetPerfData",[perfPath,interval,shift],(perfData,e)=>{
if (e){ if (e){
console.log(e); console.log(e);
} else { } else {

View File

@ -63,7 +63,27 @@
<textarea>{{ JSON.stringify( node ) }}</textarea> <textarea>{{ JSON.stringify( node ) }}</textarea>
</div> </div>
</div> </div>
<div class="flex column grow" id="graphs"></div> <div class="flex column grow" id="graphs">
<div class="controls">
<div class="center">
Intervall
<ln-slider
v-model="graphInterval"
v-bind:values="viewIntervals"
@change="loadGraphs(node,this.graphInterval,this.graphShift);"
></ln-slider>
</div>
<div class="center">
Verschiebung
<ln-slider
v-bind:max="48 * graphInterval"
v-bind:step="graphInterval * 0.25"
v-model="graphShift"
@change="loadGraphs(node,this.graphInterval,this.graphShift);"
></ln-slider>
</div>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,111 @@
SkyScanner.getInitializers().push( Vue.component('ln-slider',{
model: {
prop: 'value',
event: 'change',
},
props: {
value: {
type: Number,
default: 1,
},
min: {
type: Number,
default: 0,
},
max: {
type: Number,
default: 100,
},
step: {
type: Number,
default: 1,
},
islogarithmic: {
type: Boolean,
default: false,
},
values: {
type: Array,
}
},
data: function(){
let d = {
};
if (this.values){
this.min = 0;
this.max = this.values.length - 1;
this.step = 1;
} else if (this.islogarithmic){
/* ToDo: Implement */
} else {
}
// console.log(`min=${this.min} max=${this.max} step=${this.step} value=${this.value}`);
return d;
},
computed: {
displayValue: function(){
if (this.values)
{
let sv = this.sliderValue;
let element = this.values[this.sliderValue];
return element[1] || element;
}
return this.mapFromRange(this.value);
},
sliderValue: {
get: function(){ return this.mapToRange(this.value); },
set: function(v){ this.value = this.mapFromRange(v); this.$emit('change', this.value); },
}
},
methods: {
mapToRange: function(v){
if (this.values)
{
for (let idx=0;idx<this.values.length;idx++)
{
let element = this.values[idx];
if (v == (element[0] || element))
{
return idx;
}
}
return 0;
}
return this.islogarithmic ? null : v;
},
mapFromRange: function(v){
if (this.values)
{
let element = this.values[v];
let rv = element[0] || element;
return rv;
}
return this.islogarithmic ? null : v;
},
fireChange: function(){
this.$emit('change',this.value);
}
},
template: `
<div class='ln-slider'>
<input
class="ln-slider"
type="range"
v-bind:min="min"
v-bind:max="max"
v-bind:step="step"
v-model="sliderValue"
@change="fireChange"
>{{ displayValue }}
</div>`,
});
SkyScanner.getInitializers().push(
new Promise((resolve, reject) => { new Promise((resolve, reject) => {
LN().load("/vue/ln.skyscanner.node.html"). LN().load("/vue/ln.skyscanner.node.html").
then((template) => { then((template) => {
@ -7,14 +114,38 @@
path: "/vue/nodes/:nodeID", path: "/vue/nodes/:nodeID",
component: { component: {
template: template, template: template,
data: function () { return { node: null }; }, data: function () {
return {
node: null,
graphInterval: 600,
graphShift: 0,
viewIntervals: [
[ 600,'10 Minuten'],
[ 3600,'1 Stunde'],
[ 7200,'2 Stunden'],
[ 14400,'4 Stunden'],
[ 28800,'8 Stunden'],
[ 57600,'16 Stunden'],
[ 86400,'1 Tag'],
[ 86400 * 2,'2 Tage'],
[ 86400 * 4,'4 Tage'],
[ 86400 * 7,'1 Woche'],
[ 86400 * 14,'2 Wochen'],
[ 86400 * 28,'4 Wochen'],
[ 86400 * 7 * 8,'8 Wochen'],
[ 86400 * 7 * 16,'16 Wochen'],
[ 86400 * 7 * 32,'32 Wochen'],
[ 86400 * 7 * 64,'64 Wochen'],
],
};
},
beforeRouteEnter: function (to, from, next) { beforeRouteEnter: function (to, from, next) {
next((vm) => { next((vm) => {
skyscanner.loadNode(to.params.nodeID, (node) => { skyscanner.loadNode(to.params.nodeID, (node) => {
vm.node = node; vm.node = node;
vm.$nextTick(() => { vm.$nextTick(() => {
skyscanner.buildGraphs(node); skyscanner.buildGraphs(node);
loadGraphs(node); loadGraphs(node,vm.graphInterval,vm.graphShift);
}); });
}, 10000); }, 10000);
}); });
@ -137,14 +268,13 @@ function toSI(value, perfUnit) {
return `${nValue}${prefix}`; return `${nValue}${prefix}`;
} }
function loadGraphs(node) { function loadGraphs(node,viewInterval,graphShift) {
for (group in node._graphs) { for (group in node._graphs) {
if (!node._graphs.hasOwnProperty(group)) continue; if (!node._graphs.hasOwnProperty(group)) continue;
let dataSets = []; let dataSets = [];
let yScales = []; let yScales = [];
let perfValueDict = {};
for (perfUnit in node._graphs[group]) { for (perfUnit in node._graphs[group]) {
if (!node._graphs[group].hasOwnProperty(perfUnit)) continue; if (!node._graphs[group].hasOwnProperty(perfUnit)) continue;
@ -183,6 +313,7 @@ function loadGraphs(node) {
dataSets.push({ dataSets.push({
perfName: perfName, perfName: perfName,
perfUnit: perfUnit, perfUnit: perfUnit,
perfValue: perfValue,
label: perfName + (perfUnit ? " [" + perfUnit + "]" : ""), label: perfName + (perfUnit ? " [" + perfUnit + "]" : ""),
data: [], data: [],
borderColor: color, borderColor: color,
@ -191,28 +322,32 @@ function loadGraphs(node) {
yAxisID: perfUnit, yAxisID: perfUnit,
}); });
perfValueDict[perfName] = perfValue;
} }
} }
let chart = getOrCreateChart(`chart-${group}`, yScales, dataSets); let chart = getOrCreateChart(`chart-${group}`, yScales, dataSets);
chart.options.title.text = `${group}`; chart.options.title.text = `${group}`;
chart.data.datasets.forEach((dataSet) => { loadChartLines(chart, viewInterval,graphShift);
console.log("dataSet: " + dataSet.perfName);
loadChartLine(chart, dataSet, perfValueDict[dataSet.perfName]);
});
chart.update(); chart.update();
} }
} }
function loadChartLine(chart, dataSet, perfValue) { function loadChartLines(chart, viewInterval, graphShift){
console.log("loadChartLine()"); if (!viewInterval)
return;
skyscanner.loadPerformanceGraph(perfValue.PerfPath, 3600, (perfData) => { chart.data.datasets.forEach((dataSet) => {
console.log("loadPerformaceGraph(): callback"); loadChartLine(chart, dataSet, dataSet.perfValue, viewInterval, graphShift);
});
}
function loadChartLine(chart, dataSet, perfValue, viewInterval, graphShift) {
if (!viewInterval)
return;
skyscanner.loadPerformanceGraph(perfValue.PerfPath, viewInterval, graphShift, (perfData) => {
let chartColor = perfValue.CheckState == "CRITICAL" ? '#C00000' : (perfValue.CheckState == "WARN") ? '#C0C000' : '#008000'; let chartColor = perfValue.CheckState == "CRITICAL" ? '#C00000' : (perfValue.CheckState == "WARN") ? '#C0C000' : '#008000';
let perfName = perfValue.PerfName; let perfName = perfValue.PerfName;

View File

@ -57,6 +57,8 @@
<div id="footer" class="flex row"> <div id="footer" class="flex row">
<div id="ServerString" class="silver" style="">{{ serverString }}</div> <div id="ServerString" class="silver" style="">{{ serverString }}</div>
<div id="CurrentActionLabel">{{ currentAction }}</div>
<div id="CurrentStateLabel">{{ currentState }}</div>
<div class="grow"></div> <div class="grow"></div>
<div id="ServerTime" class="" style="margin-right: 12px;">{{ serverTime }}</div> <div id="ServerTime" class="" style="margin-right: 12px;">{{ serverTime }}</div>
</div> </div>