mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-10-02 10:45:05 -04:00
BE+FE: System info -> Performance section
This commit is contained in:
1 parent
4aa2a0dddb
commit
66d13bd55c
3 files changed
+76
-24
No files matched your search
+23
-7
@@ -91,7 +91,17 @@ function deleteCookie (cookie) {
|
||||
// -----------------------------------------------------------------------------
|
||||
// DateTime utilities
|
||||
// -----------------------------------------------------------------------------
|
||||
function localizeTimestamp(input) {
|
||||
/**
|
||||
* Parses a timestamp in any of several common formats (unix seconds/ms,
|
||||
* DD/MM/YYYY, MM/DD/YYYY, ISO, RFC2822, DD-MM-YYYY) and formats it in the
|
||||
* user's configured TIMEZONE/UI_LOCALE settings.
|
||||
* @param {string|number} input - The timestamp to localize.
|
||||
* @param {Intl.DateTimeFormatOptions} [dtfOptions] - Full Intl.DateTimeFormat
|
||||
* options object, replacing (not merging with) the default year/month/day/
|
||||
* hour/minute/second/hour12 shape - e.g. for a shorter chart-axis label.
|
||||
* @returns {string} The localized, formatted timestamp.
|
||||
*/
|
||||
function localizeTimestamp(input, dtfOptions) {
|
||||
|
||||
// Read fresh on every call (not a module-level const): getSetting() reads
|
||||
// a localStorage cache that clearCache() wipes before reloading, so a
|
||||
@@ -99,6 +109,16 @@ function localizeTimestamp(input) {
|
||||
const tz = getSetting("TIMEZONE") || 'Europe/Berlin';
|
||||
const LOCALE = getSetting('UI_LOCALE') || 'en-GB';
|
||||
|
||||
// Optional second arg: full Intl.DateTimeFormat options object, replacing
|
||||
// (not merging with) the historical year+seconds default below - e.g. a
|
||||
// chart axis label that wants month/day/hour/minute only. Omit it for the
|
||||
// original full-precision behavior every existing caller relies on.
|
||||
const options = dtfOptions || {
|
||||
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hour12: false
|
||||
};
|
||||
|
||||
input = String(input || '').trim();
|
||||
|
||||
// 1. Unix timestamps (10 or 13 digits)
|
||||
@@ -106,9 +126,7 @@ function localizeTimestamp(input) {
|
||||
const ms = input.length === 10 ? parseInt(input, 10) * 1000 : parseInt(input, 10);
|
||||
return new Intl.DateTimeFormat('default', {
|
||||
timeZone: tz,
|
||||
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hour12: false
|
||||
...options
|
||||
}).format(new Date(ms));
|
||||
}
|
||||
|
||||
@@ -198,9 +216,7 @@ function localizeTimestamp(input) {
|
||||
return new Intl.DateTimeFormat(LOCALE, {
|
||||
// Convert from UTC to user's configured timezone
|
||||
timeZone: tz,
|
||||
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hour12: false
|
||||
...options
|
||||
}).format(date);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,23 @@
|
||||
// building a new one on the same canvas (Chart.js throws otherwise).
|
||||
var resourceHistoryChartInstances = {};
|
||||
|
||||
// Chart axis labels: time only - date/year are dropped entirely to keep the
|
||||
// axis readable; the full date (including year) is still available on
|
||||
// hover via each chart's tooltip title callback below. Passed as
|
||||
// localizeTimestamp()'s options override so parsing/timezone/locale logic
|
||||
// stays in one shared place (common.js).
|
||||
var CHART_TIMESTAMP_OPTIONS_AXIS = {
|
||||
hour: '2-digit', minute: '2-digit',
|
||||
hour12: false
|
||||
};
|
||||
|
||||
// Full timestamp (including year) shown in the tooltip title on hover.
|
||||
var CHART_TIMESTAMP_OPTIONS_TOOLTIP = {
|
||||
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hour12: false
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches Resource_History data for the given range ('hour'/'day'/'week'/'month')
|
||||
* and renders the four Performance-tab charts, or shows the disabled-state
|
||||
@@ -21,6 +38,7 @@ function initResourceHistoryGraphs(range) {
|
||||
$('#resourceHistoryCharts').removeClass('myhidden');
|
||||
|
||||
var labels = [];
|
||||
var fullLabels = [];
|
||||
var cpuData = [];
|
||||
var rssData = [];
|
||||
var ioReadData = [];
|
||||
@@ -36,7 +54,8 @@ function initResourceHistoryGraphs(range) {
|
||||
// hour/day rows carry resDateTime (raw); week/month rows carry bucket
|
||||
// (hourly rollup) instead - see const.py's sql_resource_history_* queries.
|
||||
var ts = entry.resDateTime || entry.bucket;
|
||||
labels.push(localizeTimestamp(ts).slice(0, 16));
|
||||
labels.push(localizeTimestamp(ts, CHART_TIMESTAMP_OPTIONS_AXIS));
|
||||
fullLabels.push(localizeTimestamp(ts, CHART_TIMESTAMP_OPTIONS_TOOLTIP));
|
||||
cpuData.push(round2(entry.resCpuPercent));
|
||||
rssData.push(round2(entry.resRssMb));
|
||||
// Bytes -> MB and ms -> s: raw units from the DB aren't a readable axis scale.
|
||||
@@ -46,7 +65,7 @@ function initResourceHistoryGraphs(range) {
|
||||
tickFailed.push(entry.resTickFailed == 1);
|
||||
});
|
||||
|
||||
renderResourceHistoryCharts(labels, cpuData, rssData, ioReadData, ioWriteData, durationData, tickFailed);
|
||||
renderResourceHistoryCharts(labels, fullLabels, cpuData, rssData, ioReadData, ioWriteData, durationData, tickFailed);
|
||||
}).fail(function () {
|
||||
console.error('Error fetching resource history data.');
|
||||
});
|
||||
@@ -57,9 +76,11 @@ function initResourceHistoryGraphs(range) {
|
||||
* memory usage MB, IO read+write MB, scan duration seconds) on the same time
|
||||
* axis. Rows written from the tick-failure `finally` path (resTickFailed = 1)
|
||||
* are rendered as visually distinct points rather than plain data, since
|
||||
* their numbers may reflect a truncated, crash-adjacent sample.
|
||||
* their numbers may reflect a truncated, crash-adjacent sample. `labels`
|
||||
* (time-only, used for the axis) and `fullLabels` (full date+year, used for
|
||||
* the hover tooltip title) are parallel arrays over the same rows.
|
||||
*/
|
||||
function renderResourceHistoryCharts(labels, cpuData, rssData, ioReadData, ioWriteData, durationData, tickFailed) {
|
||||
function renderResourceHistoryCharts(labels, fullLabels, cpuData, rssData, ioReadData, ioWriteData, durationData, tickFailed) {
|
||||
var normalColor = "rgba(0, 166, 89, .8)";
|
||||
var failedColor = "#dd4b39";
|
||||
|
||||
@@ -75,15 +96,30 @@ function renderResourceHistoryCharts(labels, cpuData, rssData, ioReadData, ioWri
|
||||
|
||||
var commonScales = {
|
||||
yAxes: [{
|
||||
ticks: { beginAtZero: true, fontColor: '#A0A0A0' },
|
||||
gridLines: { color: "rgba(0, 0, 0, 0)" },
|
||||
// maxTicksLimit caps how many labels Chart.js draws - without it, a
|
||||
// short/fixed-height chart crams in enough ticks that adjacent labels
|
||||
// visually overlap.
|
||||
ticks: { beginAtZero: true, fontColor: '#A0A0A0', maxTicksLimit: 5 },
|
||||
// Faint gridlines only at the (few, capped) main ticks - easier to
|
||||
// read a value off the chart without making it visually noisy.
|
||||
gridLines: { color: "rgba(160, 160, 160, 0.15)", zeroLineColor: "rgba(160, 160, 160, 0.3)" },
|
||||
}],
|
||||
xAxes: [{
|
||||
ticks: { fontColor: '#A0A0A0' },
|
||||
gridLines: { color: "rgba(0, 0, 0, 0)" },
|
||||
ticks: { fontColor: '#A0A0A0', maxTicksLimit: 10, autoSkip: true },
|
||||
gridLines: { color: "rgba(160, 160, 160, 0.15)", zeroLineColor: "rgba(160, 160, 160, 0.3)" },
|
||||
}],
|
||||
};
|
||||
|
||||
// Axis labels are time-only (CHART_TIMESTAMP_OPTIONS_AXIS); show the full
|
||||
// date (including year) on hover instead, via fullLabels.
|
||||
var commonTooltips = {
|
||||
callbacks: {
|
||||
title: function (tooltipItems) {
|
||||
return fullLabels[tooltipItems[0].index];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
destroyIfExists('cpu');
|
||||
resourceHistoryChartInstances.cpu = new Chart("ResourceCpuChart", {
|
||||
type: "line",
|
||||
@@ -98,7 +134,7 @@ function renderResourceHistoryCharts(labels, cpuData, rssData, ioReadData, ioWri
|
||||
fill: true,
|
||||
}],
|
||||
},
|
||||
options: { legend: { display: true }, scales: commonScales, maintainAspectRatio: false, responsive: true },
|
||||
options: { legend: { display: true }, scales: commonScales, tooltips: commonTooltips, maintainAspectRatio: false, responsive: true },
|
||||
});
|
||||
|
||||
destroyIfExists('rss');
|
||||
@@ -115,7 +151,7 @@ function renderResourceHistoryCharts(labels, cpuData, rssData, ioReadData, ioWri
|
||||
fill: true,
|
||||
}],
|
||||
},
|
||||
options: { legend: { display: true }, scales: commonScales, maintainAspectRatio: false, responsive: true },
|
||||
options: { legend: { display: true }, scales: commonScales, tooltips: commonTooltips, maintainAspectRatio: false, responsive: true },
|
||||
});
|
||||
|
||||
destroyIfExists('io');
|
||||
@@ -140,7 +176,7 @@ function renderResourceHistoryCharts(labels, cpuData, rssData, ioReadData, ioWri
|
||||
},
|
||||
],
|
||||
},
|
||||
options: { legend: { display: true }, scales: commonScales, maintainAspectRatio: false, responsive: true },
|
||||
options: { legend: { display: true }, scales: commonScales, tooltips: commonTooltips, maintainAspectRatio: false, responsive: true },
|
||||
});
|
||||
|
||||
destroyIfExists('duration');
|
||||
@@ -157,6 +193,6 @@ function renderResourceHistoryCharts(labels, cpuData, rssData, ioReadData, ioWri
|
||||
fill: true,
|
||||
}],
|
||||
},
|
||||
options: { legend: { display: true }, scales: commonScales, maintainAspectRatio: false, responsive: true },
|
||||
options: { legend: { display: true }, scales: commonScales, tooltips: commonTooltips, maintainAspectRatio: false, responsive: true },
|
||||
});
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
<div class="box box-solid">
|
||||
<div class="box-header">
|
||||
<h3 class="box-title sysinfo_headline"><i class="fa fa-chart-line"></i> <?= lang('Systeminfo_Performance');?>
|
||||
<a href="https://docs.netalertx.com/PERFORMANCE" target="_blank"><i class="fa fa-circle-question"></i></a>
|
||||
<a href="https://docs.netalertx.com/PERFORMANCE" target="_blank"><i class="fa fa-circle-question" style="font-size: 14px;"></i></a>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
@@ -28,17 +28,17 @@
|
||||
</div>
|
||||
|
||||
<div id="resourceHistoryCharts">
|
||||
<div style="position: relative; height: 150px; width: 100%; margin-bottom: 25px;">
|
||||
<div style="position: relative; height: 220px; width: 100%; margin-bottom: 25px;">
|
||||
<canvas id="ResourceCpuChart"></canvas>
|
||||
</div>
|
||||
<div style="position: relative; height: 150px; width: 100%; margin-bottom: 25px;">
|
||||
<div style="position: relative; height: 220px; width: 100%; margin-bottom: 25px;">
|
||||
<canvas id="ResourceRssChart"></canvas>
|
||||
</div>
|
||||
<div style="position: relative; height: 150px; width: 100%; margin-bottom: 5px;">
|
||||
<div style="position: relative; height: 220px; width: 100%; margin-bottom: 5px;">
|
||||
<canvas id="ResourceIoChart"></canvas>
|
||||
</div>
|
||||
<p class="text-muted" style="font-size: 12px; margin-bottom: 25px;"><?= lang('Systeminfo_Performance_IO_Caption');?></p>
|
||||
<div style="position: relative; height: 150px; width: 100%; margin-bottom: 15px;">
|
||||
<div style="position: relative; height: 220px; width: 100%; margin-bottom: 15px;">
|
||||
<canvas id="ResourceDurationChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user