* fixed #194 PHP 5.6 error * - closed #102 added "set waypoint/destination" context menu to route finder module - update "Select2" 4.0.0 -> 4.0.3 - update "Font Awesome" 4.6.1 -> 4.6.3 * - added *.js files for develop branch * - closed #195 fixed "BASE" dir for subDir installations - fixed "Home" menu link * - #195 improved js load path * - added "clear cache" function for manually cache clearing to /setup #200 #105 #158 - added cache size information to /setup - added current pathfinder "VERSION" to /setup - updated "requireJs" 2.1.20 ->2.2.0 - removed unnecessary page cache timings from static templates (page cache) * - added "document_root", "port", "protocol" and "PHP framework version" to /setup page - added new "shattered" wormhole types to "signature table", closed #182, #179 * - added new "delete old signatures" option to "signature reader" dialog, closed #95 * - added new housekeeping cronjob für cached files, closed #200 - added new cache size information to /setup page * - fixed signature groupId/typeId "overwriting" for already known signatures. closed #207 - improved system search dialog. Added trim(); before "api/signatures-> search" request * updated README.me * fixed PHP error "default object from empty value", closed #209 * reduced image file size * - added local storage (IndexedDB) - added local storage for map scroll position. closed #69 * - added "notice" panel for upcoming release information - improved layout for "release dialog" (GitHub API) - improved pagespeed (removed render blocking javascripts) - improved map scrollbar configuration - improved Chrome browser custom scrollbar layout - removed "sign up" buttons from "map panels", closed #214 * - fixed some session and cookie bugs * - added new requirement check for `max_input_vars` to /setup URL, closed #224 * - fixed isWormhole(); bug * -v1.1.1 added js build files * - removed IGB support #206 - removed location tracking by IGB * - added build files for upcoming version 1.1.2 - improved ajax authentication check and "logout" notification | closed #198 - improved logging, added missing log file configuration to pathfinder.ini - added logging for "unauthorized" requests | closed #198 - updated js "jQuery" 1.11.3 -> 3.0.0 | #206 - updated js "datatables" plugin 1.10.7 -> 1.10.12 | #206 - updated js "mCustomScrollbar" 3.1.14 -> 3.1.4 | #206 * - fixed some minor bugs in signature table module * - fixed type "Cataclysmic", closed #241 * - added new setup DB indexing for "system_neighbour" table to /setup route, #125 - fixed system "TrueSec" rounding in "routes module", closed #109 * - fixed system "TrueSec" rounding in "routes module", closed #109 * - added new wormhole statics for "Thera", closed #240 * - fixed missing statics for constellation "21000062" , closed #232 * - added "static" wormholes for "shattered" systems , closed #180 - added im/export function for "index" tables (*.csv import), as an alternative to the *.sql import, closed #125 * - added new system tooltip for "region name", closed #236 - updated "Bootstrap" JS-library 3.3.0 -> 3.3.5 * - removed console.log(),,, * minor bugfixes in /setup page * - added basic support for Russian signatures, closed #256 - added warning notification for invalid signature stings * - added basic support for Russian signatures, closed #256 * - added requirement check for "PDO", "PDO_MYSQL" to "/setup" route - imrpved DB PDO connection (added "TIMEOUT", forced "ERRMODE") - fixed broken "system alias" renaming dialog * - fixed "system graph" module rendering if there was no data available - improved "image gallery" initialization on landing page - added navigation to /setup page - updated "blueImpGallery" (fixed some bugs after jQuery 3.0 upgrade) 1.15.2 -> 2.21.3 - updated "blueImpGalleryBootstrap" (fixed some bugs after jQuery 3.0 upgrade) 3.1.1 -> 3.4.2 * - JS build files vor 1.1.2 * Updated pathfinder.css
504 lines
16 KiB
JavaScript
504 lines
16 KiB
JavaScript
/**
|
|
* logging
|
|
*/
|
|
|
|
define([
|
|
'jquery',
|
|
'app/init',
|
|
'app/util',
|
|
'bootbox'
|
|
], function($, Init, Util, bootbox) {
|
|
|
|
'use strict';
|
|
|
|
var logData = []; // cache object for all log entries
|
|
var logDataTable = null; // "Datatables" Object
|
|
|
|
// Morris charts data
|
|
var maxGraphDataCount = 30; // max date entries for a graph
|
|
var chartData = {}; // chart Data object for all Morris Log graphs
|
|
|
|
var config = {
|
|
dialogDynamicAreaClass: 'pf-dynamic-area', // class for dynamic areas
|
|
logGraphClass: 'pf-log-graph', // class for all log Morris graphs
|
|
tableToolsClass: 'pf-table-tools' // class for table tools
|
|
};
|
|
|
|
/**
|
|
* get log time string
|
|
* @returns {string}
|
|
*/
|
|
var getLogTime = function(){
|
|
|
|
var serverTime = Util.getServerTime();
|
|
|
|
var logTime = serverTime.toLocaleTimeString('en-US', { hour12: false });
|
|
|
|
return logTime;
|
|
};
|
|
|
|
/**
|
|
* shows the logging dialog
|
|
*/
|
|
var showDialog = function(){
|
|
|
|
// dialog content
|
|
|
|
var content = $('<div>');
|
|
|
|
// content row for log graphs
|
|
var rowElementGraphs = $('<div>', {
|
|
class: 'row'
|
|
});
|
|
|
|
content.append(rowElementGraphs);
|
|
|
|
|
|
|
|
var tableHeadline = $('<h4>', {
|
|
text: ' Processes'
|
|
}).prepend( $('<i>', {
|
|
class: ['fa', 'fa-fw', 'fa-lg', 'fa-list-alt'].join(' ')
|
|
}));
|
|
|
|
// add content Structure to dome before table initialization
|
|
content.append(tableHeadline);
|
|
|
|
// log table area --------------------------------------------------
|
|
var logTableArea = $('<div>', {
|
|
class: config.dialogDynamicAreaClass
|
|
});
|
|
|
|
var logTableActionBar = $('<div>', {
|
|
class: config.tableToolsClass
|
|
});
|
|
logTableArea.append(logTableActionBar);
|
|
|
|
var logTable = $('<table>', {
|
|
class: ['compact', 'stripe', 'order-column', 'row-border'].join(' ')
|
|
});
|
|
logTableArea.append(logTable);
|
|
|
|
content.append(logTableArea);
|
|
|
|
// init log table
|
|
logDataTable = logTable.DataTable({
|
|
paging: true,
|
|
ordering: true,
|
|
order: [ 1, 'desc' ],
|
|
autoWidth: false,
|
|
hover: false,
|
|
pageLength: 15,
|
|
lengthMenu: [[10, 15, 25, 50, 50], [10, 15, 25, 50, 50]],
|
|
data: logData, // load cached logs (if available)
|
|
language: {
|
|
emptyTable: 'No entries',
|
|
zeroRecords: 'No entries found',
|
|
lengthMenu: 'Show _MENU_ entries',
|
|
info: 'Showing _START_ to _END_ of _TOTAL_ entries'
|
|
},
|
|
columnDefs: [
|
|
{
|
|
targets: 0,
|
|
title: '<i class="fa fa-lg fa-tag"></i>',
|
|
width: '18px',
|
|
searchable: false,
|
|
class: ['text-center'].join(' '),
|
|
data: 'status'
|
|
},{
|
|
targets: 1,
|
|
title: '<i class="fa fa-lg fa-fw fa-clock-o"></i> ',
|
|
width: '50px',
|
|
searchable: true,
|
|
class: 'text-right',
|
|
data: 'time'
|
|
},{
|
|
targets: 2,
|
|
title: '<i class="fa fa-lg fa-fw fa-history"></i> ',
|
|
width: '35px',
|
|
searchable: false,
|
|
class: 'text-right',
|
|
sType: 'html',
|
|
data: 'duration'
|
|
},{
|
|
targets: 3,
|
|
title: 'description',
|
|
searchable: true,
|
|
data: 'description'
|
|
},{
|
|
targets: 4,
|
|
title: 'type',
|
|
width: '40px',
|
|
searchable: true,
|
|
class: ['text-center'].join(' '),
|
|
data: 'type'
|
|
},{
|
|
targets: 5,
|
|
title: 'Prozess-ID ',
|
|
width: '80px',
|
|
searchable: false,
|
|
class: 'text-right',
|
|
data: 'key'
|
|
}
|
|
]
|
|
|
|
});
|
|
|
|
// open dialog
|
|
var logDialog = bootbox.dialog({
|
|
title: 'Task-Manager',
|
|
message: content,
|
|
size: 'large',
|
|
buttons: {
|
|
close: {
|
|
label: 'close',
|
|
className: 'btn-default'
|
|
}
|
|
}
|
|
});
|
|
|
|
// modal dialog is shown
|
|
logDialog.on('shown.bs.modal', function(e) {
|
|
|
|
// show Morris graphs ----------------------------------------------------------
|
|
|
|
// function for chart label formation
|
|
var labelYFormat = function(y){
|
|
return Math.round(y) + 'ms';
|
|
};
|
|
|
|
for(var key in chartData) {
|
|
if(chartData.hasOwnProperty(key)) {
|
|
// create a chart for each key
|
|
|
|
var colElementGraph = $('<div>', {
|
|
class: ['col-md-6'].join(' ')
|
|
});
|
|
|
|
|
|
// graph element
|
|
var graphElement = $('<div>', {
|
|
class: config.logGraphClass
|
|
});
|
|
|
|
var graphArea = $('<div>', {
|
|
class: config.dialogDynamicAreaClass
|
|
}).append( graphElement );
|
|
|
|
// headline
|
|
var headline = $('<h4>', {
|
|
text: key
|
|
}).prepend(
|
|
$('<span>', {
|
|
class: ['txt-color', 'txt-color-grayLight'].join(' '),
|
|
text: 'Prozess-ID: '
|
|
})
|
|
);
|
|
|
|
// show update ping between function calls
|
|
var updateElement = $('<small>', {
|
|
class: ['txt-color', 'txt-color-blue', 'pull-right'].join(' ')
|
|
});
|
|
headline.append(updateElement).append('<br>');
|
|
|
|
// show average execution time
|
|
var averageElement = $('<small>', {
|
|
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],
|
|
units: 'ms',
|
|
parseTime: false,
|
|
ymin: 0,
|
|
yLabelFormat: labelYFormat,
|
|
padding: 10,
|
|
hideHover: true,
|
|
pointSize: 3,
|
|
lineColors: ['#375959'],
|
|
pointFillColors: ['#477372'],
|
|
pointStrokeColors: ['#313335'],
|
|
lineWidth: 2,
|
|
grid: false,
|
|
gridStrokeWidth: 0.3,
|
|
gridTextSize: 9,
|
|
gridTextFamily: 'Oxygen Bold',
|
|
gridTextColor: '#63676a',
|
|
behaveLikeLine: true,
|
|
goals: [],
|
|
goalLineColors: ['#66c84f'],
|
|
smooth: false,
|
|
fillOpacity: 0.3,
|
|
resize: true
|
|
});
|
|
|
|
graphArea.hideLoadingAnimation();
|
|
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
// add dataTable buttons (extension)
|
|
|
|
var buttons = new $.fn.dataTable.Buttons( logDataTable, {
|
|
buttons: [
|
|
{
|
|
extend: 'copy',
|
|
className: 'btn btn-sm btn-default',
|
|
text: '<i class="fa fa-fw fa-clipboard"></i> copy'
|
|
},{
|
|
extend: 'csv',
|
|
className: 'btn btn-sm btn-default',
|
|
text: '<i class="fa fa-fw fa-download"></i> csv'
|
|
}
|
|
]
|
|
} );
|
|
|
|
logDataTable.buttons().container().appendTo( $(this).find('.' + config.tableToolsClass));
|
|
});
|
|
|
|
|
|
// modal dialog is closed
|
|
logDialog.on('hidden.bs.modal', function(e) {
|
|
// clear memory -> destroy all charts
|
|
for (var key in chartData) {
|
|
if (chartData.hasOwnProperty(key)) {
|
|
chartData[key].graph = null;
|
|
}
|
|
}
|
|
});
|
|
|
|
// modal dialog before hide
|
|
logDialog.on('hide.bs.modal', function(e) {
|
|
|
|
// 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
|
|
*/
|
|
var updateLogGraph = function(key, duration){
|
|
|
|
// check if graph data already exist
|
|
if( !(chartData.hasOwnProperty(key))){
|
|
chartData[key] = {};
|
|
chartData[key].data = [];
|
|
chartData[key].graph = null;
|
|
chartData[key].averageElement = null;
|
|
chartData[key].updateElement = null;
|
|
}
|
|
|
|
// add new value
|
|
chartData[key].data.unshift(duration);
|
|
|
|
if(chartData[key].data.length > maxGraphDataCount){
|
|
chartData[key].data = chartData[key].data.slice(0, maxGraphDataCount);
|
|
}
|
|
|
|
function getGraphData(data) {
|
|
var tempChartData = {
|
|
data: [],
|
|
dataSum: 0,
|
|
average: 0
|
|
};
|
|
|
|
for(var x = 0; x < maxGraphDataCount; x++){
|
|
var 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;
|
|
}
|
|
|
|
var tempChartData = getGraphData(chartData[key].data);
|
|
|
|
// add new data to graph (Morris chart) - if is already initialized
|
|
if(chartData[key].graph !== null){
|
|
var avgElement = chartData[key].averageElement;
|
|
var updateElement = chartData[key].updateElement;
|
|
|
|
var delay = Util.getCurrentTriggerDelay( key, 0 );
|
|
|
|
if(delay){
|
|
updateElement[0].textContent = ' delay: ' + delay + 'ms ';
|
|
}
|
|
|
|
// set/change average line
|
|
chartData[key].graph.options.goals = [tempChartData.average];
|
|
|
|
// change avg. display
|
|
avgElement[0].textContent = 'Avg. ' + tempChartData.average + 'ms';
|
|
|
|
var avgStatus = getLogStatusByDuration(key, tempChartData.average);
|
|
var 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('problem');
|
|
}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}
|
|
*/
|
|
var getLogStatusByDuration = function(logKey, logDuration){
|
|
|
|
var 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}
|
|
*/
|
|
var getLogTypeIconClass = function(logType){
|
|
|
|
var logIconClass = '';
|
|
|
|
switch(logType){
|
|
case 'client':
|
|
logIconClass = 'fa-user';
|
|
break;
|
|
case 'server':
|
|
logIconClass = 'fa-download';
|
|
break;
|
|
}
|
|
|
|
return logIconClass;
|
|
};
|
|
|
|
/**
|
|
* init logging -> set global log event
|
|
*/
|
|
var init = function(){
|
|
|
|
var maxEntries = 150;
|
|
|
|
// set global logging listener
|
|
$(window).on('pf:log', function(e, logKey, options){
|
|
|
|
// check required logging information
|
|
if(
|
|
options &&
|
|
options.duration &&
|
|
options.description
|
|
){
|
|
var logDescription = options.description;
|
|
var logDuration = options.duration;
|
|
var logType = options.type;
|
|
|
|
// check log status by duration
|
|
var logStatus = getLogStatusByDuration(logKey, logDuration);
|
|
|
|
var statusClass = Util.getLogInfo( logStatus, 'class' );
|
|
|
|
var typeIconClass = getLogTypeIconClass(logType);
|
|
|
|
// update graph data
|
|
updateLogGraph(logKey, logDuration);
|
|
|
|
var logRowData = {
|
|
status: '<i class="fa fa-fw fa-circle txt-color ' + statusClass + '"></i>',
|
|
time: getLogTime(),
|
|
duration: '<span class="txt-color ' + statusClass + '">' + logDuration + '<small>ms</small></span>',
|
|
description: logDescription,
|
|
type: '<i class="fa ' + typeIconClass + '"></i>',
|
|
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 ---------------------------------
|
|
var rowCount = logData.length;
|
|
|
|
if( rowCount >= 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,
|
|
getLogTime: getLogTime,
|
|
showDialog: showDialog
|
|
};
|
|
}); |