', {
class: ['col-md-6'].join(' ')
});
// graph element
let graphElement = $('
', {
class: config.logGraphClass
});
let graphArea = $('
', {
class: Util.config.dynamicAreaClass
}).append( graphElement );
let headline = $('
', {
text: key
}).prepend(
$('', {
class: ['txt-color', 'txt-color-grayLight'].join(' '),
text: 'Prozess-ID: '
})
);
// show update ping between function calls
let updateElement = $('', {
class: ['txt-color', 'txt-color-blue', 'pull-right'].join(' ')
});
headline.append(updateElement).append('
');
// show average execution time
let averageElement = $('', {
class: 'pull-right'
});
headline.append(averageElement);
colElementGraph.append(headline);
colElementGraph.append(graphArea);
graphArea.showLoadingAnimation();
rowElementGraphs.append( colElementGraph );
// cache DOM Elements that will be updated frequently
chartData[key].averageElement = averageElement;
chartData[key].updateElement = updateElement;
chartData[key].graph = Morris.Area({
element: graphElement,
data: [],
xkey: 'x',
ykeys: ['y'],
labels: [key],
lineColors: ['#375959'],
lineWidth: 2,
pointSize: 3,
pointFillColors: ['#477372'],
pointStrokeColors: ['#313335'],
ymin: 0,
smooth: false,
hideHover: true,
parseTime: false,
postUnits: 'ms',
yLabelFormat: labelYFormat,
goals: [],
goalStrokeWidth: 1,
goalLineColors: ['#66c84f'],
grid: true,
gridTextColor: '#63676a',
gridTextSize: 9,
gridTextFamily: 'Arial, "Oxygen Bold"',
gridTextWeight: 'bold',
gridStrokeWidth: 0.3,
resize: true, // we use our own resize function
dataLabels: false,
hoverReversed: true,
// Area chart specific options
behaveLikeLine: true,
fillOpacity: 0.5,
belowArea: true,
areaColors: ['#3c3f41'],
// Not documented but working
padding: 8,
});
updateLogGraph(key);
graphArea.hideLoadingAnimation();
}
}
/*
Util.getResizeManager().observe(
this.querySelector('.modal-dialog'),
(el, contentRect) => Object.values(chartData).forEach(data => {
if(data.graph) data.graph.redraw();
}),
{debounce: true, ms: 100}
);*/
});
// modal dialog before hide
logDialog.on('hide.bs.modal', function(e){
Object.entries(chartData).forEach(([key, data]) => {
if(data.graph){
data.graph.destroy();
delete chartData[key].graph;
}
});
// destroy logTable
logDataTable.destroy(true);
logDataTable= null;
// remove event -> prevent calling this multiple times
$(this).off('hide.bs.modal');
});
});
};
/**
* updates the log graph for a log key
* @param key
* @param duration (if undefined -> just update graph with current data)
*/
let updateLogGraph = (key, duration) => {
// check if graph data already exist
if(!chartData.hasOwnProperty(key)){
chartData[key] = {
data: [],
graph: null,
averageElement: null,
updateElement: null
};
}
// add new value
if(duration !== undefined){
chartData[key].data.unshift(duration);
}
if(chartData[key].data.length > maxGraphDataCount){
chartData[key].data = chartData[key].data.slice(0, maxGraphDataCount);
}
let getGraphData = data => {
let tempChartData = {
data: [],
dataSum: 0,
average: 0
};
for(let x = 0; x < maxGraphDataCount; x++){
let value = 0;
if(data[x]){
value = data[x];
tempChartData.dataSum = Number((tempChartData.dataSum + value).toFixed(2));
}
tempChartData.data.push({
x: x,
y: value
});
}
// calculate average
tempChartData.average = Number((tempChartData.dataSum / data.length).toFixed(2));
return tempChartData;
};
let tempChartData = getGraphData(chartData[key].data);
// add new data to graph (Morris chart) - if is already initialized
if(chartData[key].graph){
let avgElement = chartData[key].averageElement;
let updateElement = chartData[key].updateElement;
let delay = Util.getCurrentTriggerDelay(key, 0);
if(delay){
updateElement[0].textContent = ' delay: ' + delay.toFixed(2) + ' ms';
}
// set/change average line
chartData[key].graph.options.goals = [tempChartData.average];
// change avg. display
avgElement[0].textContent = 'avg. ' + tempChartData.average.toFixed(2) + ' ms';
let avgStatus = getLogStatusByDuration(key, tempChartData.average);
let avgStatusClass = Util.getLogInfo( avgStatus, 'class');
//change avg. display class
if( !avgElement.hasClass(avgStatusClass) ){
// avg status changed!
avgElement.removeClass().addClass('pull-right txt-color ' + avgStatusClass);
// change goals line color
if(avgStatus === 'warning'){
chartData[key].graph.options.goalLineColors = ['#e28a0d'];
$(document).setProgramStatus('slow connection');
}else{
chartData[key].graph.options.goalLineColors = ['#5cb85c'];
}
}
// set new data and redraw
chartData[key].graph.setData( tempChartData.data );
}
return tempChartData.data;
};
/**
* get the log "status" by log duration (ms).
* If duration > warning limit -> show as warning
* @param logKey
* @param logDuration
* @returns {string}
*/
let getLogStatusByDuration = (logKey, logDuration) => {
let logStatus = 'info';
if(logDuration > Init.timer[logKey].EXECUTION_LIMIT){
logStatus = 'warning';
}
return logStatus;
};
/**
* get the css class for a specific log type
* @param logType
* @returns {string}
*/
let getLogTypeIconClass = logType => {
let logIconClass = '';
switch(logType){
case 'client':
logIconClass = 'fa-user';
break;
case 'server':
logIconClass = 'fa-download';
break;
}
return logIconClass;
};
/**
* init logging -> set global log events
*/
let init = () => {
let maxEntries = 150;
$(window).on('pf:syncStatus', () => {
updateSyncStatus();
});
// set global logging listener
$(window).on('pf:log', (e, logKey, options) => {
// check required logging information
if(
options &&
options.duration &&
options.description
){
let logDescription = options.description;
let logDuration = options.duration;
let logType = options.type;
// update graph data
updateLogGraph(logKey, logDuration);
let time = Util.getServerTime();
let timestamp = time.getTime();
let timestampFormatted = time.toLocaleTimeString('en-US', { hour12: false });
let logRowData = {
status: getLogStatusByDuration(logKey, logDuration),
timestamp: timestamp,
timestampFormatted: timestampFormatted,
duration: logDuration,
description: logDescription,
logType: logType,
key: logKey
};
if(logDataTable){
// add row if dataTable is initialized before new log
logDataTable.row.add( logRowData ).draw(false);
}else{
// add row data to cache
logData.push(logRowData);
}
}
// delete old log entries from table ---------------------------------
if(logData.length >= maxEntries){
if(logDataTable){
logDataTable.rows(0, {order:'index'}).remove().draw(false);
}else{
logData.shift();
}
}
// cache logs in order to keep previous logs in table after reopening the dialog
if(logDataTable){
logData = logDataTable.rows({order:'index'}).data();
}
});
};
return {
init: init,
showDialog: showDialog
};
});