2021-03-11 18:24:24 +03:00
|
|
|
'use strict';
|
2023-11-26 16:49:59 +03:00
|
|
|
'require poll';
|
2021-12-05 19:18:32 +03:00
|
|
|
'require baseclass';
|
2021-03-11 18:24:24 +03:00
|
|
|
'require ui';
|
2021-12-05 19:18:32 +03:00
|
|
|
'require view';
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2021-03-26 23:49:38 +03:00
|
|
|
document.head.append(E('style', {'type': 'text/css'},
|
|
|
|
|
`
|
2021-10-05 20:48:58 +03:00
|
|
|
:root {
|
|
|
|
|
--app-log-dark-font-color: #2e2e2e;
|
|
|
|
|
--app-log-light-font-color: #fff;
|
|
|
|
|
--app-log-debug-font-color: #737373;
|
2022-09-20 16:33:28 +03:00
|
|
|
--app-log-emerg-color: #a93734;
|
|
|
|
|
--app-log-alert: #ff7968;
|
|
|
|
|
--app-log-crit: #fcc3bf;
|
|
|
|
|
--app-log-err: #ffe9e8;
|
|
|
|
|
--app-log-warn: #fff7e2;
|
|
|
|
|
--app-log-notice: #e3ffec;
|
|
|
|
|
--app-log-info: rgba(0,0,0,0);
|
|
|
|
|
--app-log-debug: #ebf6ff;
|
2023-11-10 02:39:58 +03:00
|
|
|
--app-log-entries-count-border: #ccc;
|
2022-09-20 16:33:28 +03:00
|
|
|
}
|
|
|
|
|
:root[data-darkmode="true"] {
|
|
|
|
|
--app-log-dark-font-color: #fff;
|
|
|
|
|
--app-log-light-font-color: #fff;
|
|
|
|
|
--app-log-debug-font-color: #e7e7e7;
|
|
|
|
|
--app-log-emerg-color: #a93734;
|
|
|
|
|
--app-log-alert: #eb5050;
|
|
|
|
|
--app-log-crit: #dc7f79;
|
|
|
|
|
--app-log-err: #c89593;
|
|
|
|
|
--app-log-warn: #8d7000;
|
|
|
|
|
--app-log-notice: #007627;
|
|
|
|
|
--app-log-info: rgba(0,0,0,0);
|
|
|
|
|
--app-log-debug: #5986b1;
|
2023-11-10 02:39:58 +03:00
|
|
|
--app-log-entries-count-border: #555;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
2024-02-27 17:31:44 +03:00
|
|
|
#logWrapper {
|
|
|
|
|
overflow: auto !important;
|
|
|
|
|
width: 100%;
|
|
|
|
|
min-height: 20em';
|
|
|
|
|
}
|
2021-03-26 23:49:38 +03:00
|
|
|
.log-empty {
|
|
|
|
|
}
|
|
|
|
|
.log-emerg {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-emerg-color) !important;
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-light-font-color);
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
log-emerg .td {
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-light-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
log-emerg td {
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-light-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-alert {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-alert) !important;
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-light-font-color);
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-alert .td {
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-light-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-alert td {
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-light-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-crit {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-crit) !important;
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-crit .td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-crit td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-err {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-err) !important;
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-err .td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-err td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-warn {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-warn) !important;
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-warn .td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-warn td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-notice {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-notice) !important;
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-notice .td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-notice td {
|
|
|
|
|
color: var(--app-log-dark-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-info {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-info) !important;
|
2023-11-10 02:39:58 +03:00
|
|
|
/*color: var(--app-log-dark-font-color) !important;*/
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-debug {
|
2022-09-20 16:33:28 +03:00
|
|
|
background-color: var(--app-log-debug) !important;
|
2021-10-05 20:48:58 +03:00
|
|
|
color: var(--app-log-debug-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-debug .td {
|
|
|
|
|
color: var(--app-log-debug-font-color) !important;
|
|
|
|
|
}
|
|
|
|
|
.log-debug td {
|
|
|
|
|
color: var(--app-log-debug-font-color) !important;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-highlight-item {
|
|
|
|
|
background-color: #ffef00;
|
2022-09-20 16:33:28 +03:00
|
|
|
color: #2e2e2e;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-entries-count {
|
|
|
|
|
margin: 0 0 5px 5px;
|
|
|
|
|
font-weight: bold;
|
2021-10-05 20:48:58 +03:00
|
|
|
opacity: 0.7;
|
2021-03-26 23:49:38 +03:00
|
|
|
}
|
|
|
|
|
.log-entries-count-level {
|
|
|
|
|
display: inline-block !important;
|
|
|
|
|
margin: 0 0 0 5px;
|
|
|
|
|
padding: 0 4px;
|
|
|
|
|
-webkit-border-radius: 3px;
|
|
|
|
|
-moz-border-radius: 3px;
|
|
|
|
|
border-radius: 3px;
|
2023-11-10 02:39:58 +03:00
|
|
|
border: 1px solid var(--app-log-entries-count-border);
|
2021-03-26 23:49:38 +03:00
|
|
|
font-weight: normal;
|
|
|
|
|
}
|
|
|
|
|
.log-host-dropdown-item {
|
|
|
|
|
}
|
2023-11-01 19:48:59 +03:00
|
|
|
.log-facility-dropdown-item {
|
|
|
|
|
}
|
2023-11-21 18:16:55 +03:00
|
|
|
.log-side-block {
|
2023-11-10 02:39:58 +03:00
|
|
|
position: fixed;
|
2024-06-10 16:59:23 +03:00
|
|
|
z-index: 200 !important;
|
2023-11-10 02:39:58 +03:00
|
|
|
opacity: 0.7;
|
2024-02-27 17:31:44 +03:00
|
|
|
right: 1px;
|
|
|
|
|
top: 40vh;
|
2023-11-10 02:39:58 +03:00
|
|
|
}
|
2023-11-21 18:16:55 +03:00
|
|
|
.log-side-btn {
|
2023-11-10 02:39:58 +03:00
|
|
|
position: relative;
|
|
|
|
|
display: block;
|
|
|
|
|
left: 1px;
|
|
|
|
|
top: 1px;
|
2023-11-21 18:16:55 +03:00
|
|
|
margin: 0 !important;
|
|
|
|
|
min-width: 3.2em;
|
2023-11-10 02:39:58 +03:00
|
|
|
}
|
2021-03-26 23:49:38 +03:00
|
|
|
`));
|
|
|
|
|
|
2021-12-05 19:18:32 +03:00
|
|
|
return baseclass.extend({
|
|
|
|
|
view: view.extend({
|
2021-03-27 18:35:35 +03:00
|
|
|
/**
|
2021-04-09 18:10:55 +03:00
|
|
|
* View name (for local storage and downloads).
|
2023-12-02 01:17:40 +03:00
|
|
|
*
|
|
|
|
|
* @property {string} viewName
|
|
|
|
|
*/
|
2021-11-04 18:57:08 +03:00
|
|
|
viewName : null,
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2021-03-27 18:35:35 +03:00
|
|
|
/**
|
|
|
|
|
* Page title.
|
2023-12-02 01:17:40 +03:00
|
|
|
*
|
|
|
|
|
* @property {string} title
|
|
|
|
|
*/
|
2021-11-04 18:57:08 +03:00
|
|
|
title : null,
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2024-05-12 18:50:13 +03:00
|
|
|
/**
|
|
|
|
|
* Enable auto refresh log.
|
|
|
|
|
*
|
|
|
|
|
* @property {bool} autoRefresh
|
|
|
|
|
*/
|
|
|
|
|
autoRefresh : false,
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
pollInterval : L.env.pollinterval,
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
logFacilities : {
|
|
|
|
|
'kern' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'kern')),
|
|
|
|
|
'user' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'user')),
|
|
|
|
|
'mail' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'mail')),
|
|
|
|
|
'daemon' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'daemon')),
|
|
|
|
|
'auth' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'auth')),
|
|
|
|
|
'syslog' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'syslog')),
|
|
|
|
|
'lpr' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'lpr')),
|
|
|
|
|
'news' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'news')),
|
|
|
|
|
'uucp' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'uucp')),
|
|
|
|
|
'authpriv': E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'authpriv')),
|
|
|
|
|
'ftp' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'ftp')),
|
|
|
|
|
'ntp' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'ntp')),
|
|
|
|
|
'log' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'log')),
|
|
|
|
|
'clock' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'clock')),
|
|
|
|
|
'local0' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local0')),
|
|
|
|
|
'local1' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local1')),
|
|
|
|
|
'local2' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local2')),
|
|
|
|
|
'local3' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local3')),
|
|
|
|
|
'local4' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local4')),
|
|
|
|
|
'local5' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local5')),
|
|
|
|
|
'local6' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local6')),
|
|
|
|
|
'local7' : E('span', { 'class': 'zonebadge log-facility-dropdown-item' }, E('strong', 'local7')),
|
|
|
|
|
},
|
|
|
|
|
|
2021-11-04 18:57:08 +03:00
|
|
|
logLevels : {
|
2024-11-14 00:18:04 +03:00
|
|
|
'emerg' : E('span', { 'class': 'zonebadge log-emerg' }, E('strong', 'Emergency')),
|
|
|
|
|
'alert' : E('span', { 'class': 'zonebadge log-alert' }, E('strong', 'Alert')),
|
|
|
|
|
'crit' : E('span', { 'class': 'zonebadge log-crit' }, E('strong', 'Critical')),
|
|
|
|
|
'err' : E('span', { 'class': 'zonebadge log-err' }, E('strong', 'Error')),
|
|
|
|
|
'warn' : E('span', { 'class': 'zonebadge log-warn' }, E('strong', 'Warning')),
|
|
|
|
|
'notice': E('span', { 'class': 'zonebadge log-notice' }, E('strong', 'Notice')),
|
|
|
|
|
'info' : E('span', { 'class': 'zonebadge log-info' }, E('strong', 'Info')),
|
|
|
|
|
'debug' : E('span', { 'class': 'zonebadge log-debug' }, E('strong', 'Debug')),
|
2021-03-11 18:24:24 +03:00
|
|
|
},
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
tailValue : 25,
|
|
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
fastTailIncrement : 50,
|
|
|
|
|
|
|
|
|
|
fastTailValue : null,
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
timeFilterValue : null,
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
timeFilterReValue : false,
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
hostFilterValue : [],
|
|
|
|
|
|
|
|
|
|
facilityFilterValue : [],
|
|
|
|
|
|
|
|
|
|
levelFilterValue : [],
|
|
|
|
|
|
|
|
|
|
msgFilterValue : null,
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
msgFilterReValue : false,
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
logSortingValue : 'asc',
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
autoRefreshValue : true,
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
isAutorefresh : true,
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
isHosts : false,
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
isFacilities : false,
|
2021-03-27 18:35:35 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
isLevels : false,
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
logHosts : {},
|
2021-03-26 23:49:38 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
logLevelsStat : {},
|
2021-03-27 18:35:35 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
logHostsDropdown : null,
|
2021-03-26 23:49:38 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
logFacilitiesDropdown: null,
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
logLevelsDropdown : null,
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
totalLogLines : 0,
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
lastHash : null,
|
2023-11-26 16:49:59 +03:00
|
|
|
|
|
|
|
|
actionButtons : [],
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
htmlEntities(str) {
|
2021-03-11 18:24:24 +03:00
|
|
|
return String(str).replace(
|
|
|
|
|
/&/g, '&').replace(
|
|
|
|
|
/</g, '<').replace(
|
|
|
|
|
/>/g, '>').replace(
|
2021-03-15 21:02:38 +03:00
|
|
|
/"/g, '"').replace(
|
|
|
|
|
/'/g, ''');
|
2021-03-11 18:24:24 +03:00
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
checkZeroValue(value) {
|
|
|
|
|
return (/^[0-9]+$/.test(value)) ? value : 0
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
makeLogHostsDropdownItem(host) {
|
2021-03-26 23:49:38 +03:00
|
|
|
return E(
|
|
|
|
|
'span',
|
|
|
|
|
{ 'class': 'zonebadge log-host-dropdown-item' },
|
|
|
|
|
E('strong', host)
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
makeLogHostsDropdownSection() {
|
2021-03-27 18:35:35 +03:00
|
|
|
this.logHostsDropdown = new ui.Dropdown(
|
|
|
|
|
null,
|
|
|
|
|
this.logHosts,
|
|
|
|
|
{
|
2021-12-05 19:18:32 +03:00
|
|
|
id : 'logHostsDropdown',
|
|
|
|
|
multiple : true,
|
2021-03-27 18:35:35 +03:00
|
|
|
select_placeholder: _('All'),
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
return E(
|
|
|
|
|
'div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
2021-12-05 19:18:32 +03:00
|
|
|
'for' : 'logHostsDropdown',
|
2021-03-27 18:35:35 +03:00
|
|
|
}, _('Hosts')),
|
|
|
|
|
E('div', { 'class': 'cbi-value-field' },
|
|
|
|
|
this.logHostsDropdown.render()
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
makeLogFacilitiesDropdownSection() {
|
2023-11-01 19:48:59 +03:00
|
|
|
this.logFacilitiesDropdown = new ui.Dropdown(
|
|
|
|
|
null,
|
|
|
|
|
this.logFacilities,
|
|
|
|
|
{
|
|
|
|
|
id : 'logFacilitiesDropdown',
|
|
|
|
|
sort : Object.keys(this.logFacilities),
|
|
|
|
|
multiple : true,
|
|
|
|
|
select_placeholder: _('All'),
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
return E(
|
|
|
|
|
'div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
|
|
|
|
'for' : 'logFacilitiesDropdown',
|
|
|
|
|
}, _('Facilities')),
|
|
|
|
|
E('div', { 'class': 'cbi-value-field' },
|
|
|
|
|
this.logFacilitiesDropdown.render()
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
makeLogLevelsDropdownSection() {
|
2021-03-27 18:35:35 +03:00
|
|
|
this.logLevelsDropdown = new ui.Dropdown(
|
|
|
|
|
null,
|
|
|
|
|
this.logLevels,
|
|
|
|
|
{
|
2021-12-05 19:18:32 +03:00
|
|
|
id : 'logLevelsDropdown',
|
|
|
|
|
sort : Object.keys(this.logLevels),
|
|
|
|
|
multiple : true,
|
2021-03-27 18:35:35 +03:00
|
|
|
select_placeholder: _('All'),
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
return E(
|
|
|
|
|
'div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
2021-12-05 19:18:32 +03:00
|
|
|
'for' : 'logLevelsDropdown',
|
2021-03-27 18:35:35 +03:00
|
|
|
}, _('Logging levels')),
|
|
|
|
|
E('div', { 'class': 'cbi-value-field' },
|
|
|
|
|
this.logLevelsDropdown.render()
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
setRegexpValidator(elem, flag) {
|
|
|
|
|
ui.addValidator(
|
|
|
|
|
elem,
|
|
|
|
|
'string',
|
|
|
|
|
true,
|
|
|
|
|
v => {
|
|
|
|
|
if(!flag.checked) {
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
try {
|
|
|
|
|
new RegExp(v, 'giu');
|
|
|
|
|
return true;
|
|
|
|
|
} catch(err) {
|
|
|
|
|
return _('Invalid regular expression') + ':\n' + err.message;
|
|
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
'blur',
|
|
|
|
|
'focus',
|
|
|
|
|
'input'
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
setFilterSettings() {
|
2023-12-02 01:17:40 +03:00
|
|
|
this.tailValue = this.checkZeroValue(this.tailInput.value);
|
|
|
|
|
this.timeFilterValue = this.timeFilter.value;
|
|
|
|
|
this.timeFilterReValue = this.timeFilterRe.checked;
|
2023-11-26 16:49:59 +03:00
|
|
|
if(this.isHosts) {
|
|
|
|
|
this.hostFilterValue = this.logHostsDropdown.getValue();
|
|
|
|
|
};
|
|
|
|
|
if(this.isFacilities) {
|
|
|
|
|
this.facilityFilterValue = this.logFacilitiesDropdown.getValue();
|
|
|
|
|
};
|
|
|
|
|
if(this.isLevels) {
|
|
|
|
|
this.levelFilterValue = this.logLevelsDropdown.getValue();
|
|
|
|
|
};
|
|
|
|
|
this.msgFilterValue = this.msgFilter.value;
|
2023-12-02 01:17:40 +03:00
|
|
|
this.msgFilterReValue = this.msgFilterRe.checked;
|
2023-11-26 16:49:59 +03:00
|
|
|
this.logSortingValue = this.logSorting.value;
|
|
|
|
|
this.autoRefreshValue = this.autoRefresh.checked;
|
2023-12-02 01:17:40 +03:00
|
|
|
if(this.isAutorefresh) {
|
|
|
|
|
if(this.autoRefreshValue) {
|
|
|
|
|
poll.add(this.pollFuncWrapper, this.pollInterval);
|
|
|
|
|
this.refreshBtn.style.visibility = 'hidden';
|
|
|
|
|
} else {
|
|
|
|
|
poll.remove(this.pollFuncWrapper);
|
|
|
|
|
this.refreshBtn.style.visibility = 'visible';
|
|
|
|
|
};
|
2023-11-26 16:49:59 +03:00
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
resetFormValues() {
|
2023-12-02 01:17:40 +03:00
|
|
|
this.tailInput.value = this.tailValue;
|
|
|
|
|
this.timeFilter.value = this.timeFilterValue;
|
|
|
|
|
this.timeFilterRe.checked = this.timeFilterReValue;
|
2023-11-26 16:49:59 +03:00
|
|
|
if(this.isHosts) {
|
|
|
|
|
this.logHostsDropdown.setValue(this.hostFilterValue);
|
|
|
|
|
};
|
|
|
|
|
if(this.isFacilities) {
|
|
|
|
|
this.logFacilitiesDropdown.setValue(this.facilityFilterValue);
|
|
|
|
|
};
|
|
|
|
|
if(this.isLevels) {
|
|
|
|
|
this.logLevelsDropdown.setValue(this.levelFilterValue);
|
|
|
|
|
};
|
|
|
|
|
this.msgFilter.value = this.msgFilterValue;
|
2023-12-02 01:17:40 +03:00
|
|
|
this.msgFilterRe.checked = this.msgFilterReValue;
|
2023-11-26 16:49:59 +03:00
|
|
|
this.logSorting.value = this.logSortingValue;
|
|
|
|
|
this.autoRefresh.checked = this.autoRefreshValue;
|
|
|
|
|
},
|
|
|
|
|
|
2021-03-11 18:24:24 +03:00
|
|
|
/**
|
2023-12-02 01:17:40 +03:00
|
|
|
* Receives raw log data.
|
|
|
|
|
* Abstract method, must be overridden by a subclass!
|
|
|
|
|
*
|
|
|
|
|
* @instance
|
|
|
|
|
* @abstract
|
|
|
|
|
*
|
|
|
|
|
* @param {number} tail
|
|
|
|
|
* @returns {string}
|
|
|
|
|
* Returns the raw content of the log.
|
|
|
|
|
*/
|
2023-11-01 19:48:59 +03:00
|
|
|
getLogData(tail) {
|
2021-03-26 23:49:38 +03:00
|
|
|
throw new Error('getLogData must be overridden by a subclass');
|
2021-03-11 18:24:24 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2023-12-02 01:17:40 +03:00
|
|
|
* Parses log data.
|
|
|
|
|
* Abstract method, must be overridden by a subclass!
|
|
|
|
|
*
|
|
|
|
|
* @instance
|
|
|
|
|
* @abstract
|
|
|
|
|
*
|
|
|
|
|
* @param {string} logdata
|
|
|
|
|
* @param {number} tail
|
|
|
|
|
* @returns {Array<number, string|null, string|null, string|null, string|null, string|null>}
|
2024-05-12 18:50:13 +03:00
|
|
|
* Returns an array of values: [ #, Timestamp, Host, Facility, Level, Message ].
|
2023-12-02 01:17:40 +03:00
|
|
|
*/
|
2023-11-01 19:48:59 +03:00
|
|
|
parseLogData(logdata, tail) {
|
2021-03-26 23:49:38 +03:00
|
|
|
throw new Error('parseLogData must be overridden by a subclass');
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-10 02:39:58 +03:00
|
|
|
/**
|
2023-12-02 17:08:14 +03:00
|
|
|
* Highlights the search result for a pattern.
|
2023-12-02 01:17:40 +03:00
|
|
|
* Abstract method, must be overridden by a subclass!
|
|
|
|
|
*
|
2023-12-02 17:08:14 +03:00
|
|
|
* To disable the highlight option, views extending
|
|
|
|
|
* this base class should overwrite the `filterHighlightFunc`
|
|
|
|
|
* function with `null`.
|
|
|
|
|
*
|
2023-12-02 01:17:40 +03:00
|
|
|
* @instance
|
|
|
|
|
* @abstract
|
|
|
|
|
*
|
|
|
|
|
* @param {string} logdata
|
|
|
|
|
* @returns {string}
|
|
|
|
|
* Returns a string with the highlighted part.
|
|
|
|
|
*/
|
|
|
|
|
filterHighlightFunc(match) {
|
|
|
|
|
throw new Error('filterHighlightFunc must be overridden by a subclass');
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setStringFilter(entriesArray, fieldNum, pattern) {
|
|
|
|
|
let fArr = [];
|
|
|
|
|
entriesArray.forEach((e, i) => {
|
|
|
|
|
if(e[fieldNum] !== null && e[fieldNum].includes(pattern)) {
|
2023-12-02 17:08:14 +03:00
|
|
|
if(typeof(this.filterHighlightFunc) == 'function') {
|
2023-12-02 01:17:40 +03:00
|
|
|
e[fieldNum] = e[fieldNum].replace(pattern, this.filterHighlightFunc);
|
|
|
|
|
};
|
|
|
|
|
fArr.push(e);
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
return fArr;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setRegexpFilter(entriesArray, fieldNum, pattern, formElem) {
|
2023-11-10 02:39:58 +03:00
|
|
|
let fArr = [];
|
|
|
|
|
try {
|
|
|
|
|
let regExp = new RegExp(pattern, 'giu');
|
|
|
|
|
entriesArray.forEach((e, i) => {
|
|
|
|
|
if(e[fieldNum] !== null && regExp.test(e[fieldNum])) {
|
2023-12-02 01:17:40 +03:00
|
|
|
if(this.filterHighlightFunc) {
|
|
|
|
|
e[fieldNum] = e[fieldNum].replace(regExp, this.filterHighlightFunc);
|
2023-11-10 02:39:58 +03:00
|
|
|
};
|
|
|
|
|
fArr.push(e);
|
|
|
|
|
};
|
|
|
|
|
regExp.lastIndex = 0;
|
|
|
|
|
});
|
|
|
|
|
} catch(err) {
|
|
|
|
|
if(err.name === 'SyntaxError') {
|
|
|
|
|
ui.addNotification(null,
|
|
|
|
|
E('p', {}, _('Invalid regular expression') + ': ' + err.message));
|
|
|
|
|
return entriesArray;
|
|
|
|
|
} else {
|
|
|
|
|
throw err;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
return fArr;
|
|
|
|
|
},
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
setTimeFilter(entriesArray) {
|
2023-11-26 16:49:59 +03:00
|
|
|
let fPattern = this.timeFilterValue;
|
2023-11-01 19:48:59 +03:00
|
|
|
if(!fPattern) {
|
|
|
|
|
return entriesArray;
|
|
|
|
|
};
|
2023-12-02 01:17:40 +03:00
|
|
|
return (this.timeFilterReValue) ?
|
|
|
|
|
this.setRegexpFilter(entriesArray, 1, fPattern, this.timeFilter) :
|
|
|
|
|
this.setStringFilter(entriesArray, 1, fPattern);
|
2023-11-01 19:48:59 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setHostFilter(entriesArray) {
|
2021-03-26 23:49:38 +03:00
|
|
|
let logHostsKeys = Object.keys(this.logHosts);
|
2021-03-27 18:35:35 +03:00
|
|
|
if(logHostsKeys.length > 0 && this.logHostsDropdown) {
|
|
|
|
|
this.logHostsDropdown.addChoices(logHostsKeys, this.logHosts);
|
2023-11-26 16:49:59 +03:00
|
|
|
if(this.hostFilterValue.length === 0 || logHostsKeys.length === this.hostFilterValue.length) {
|
2023-11-01 19:48:59 +03:00
|
|
|
return entriesArray;
|
2021-03-26 23:49:38 +03:00
|
|
|
};
|
2023-11-26 16:49:59 +03:00
|
|
|
return entriesArray.filter(e => this.hostFilterValue.includes(e[2]));
|
2021-03-26 23:49:38 +03:00
|
|
|
};
|
2023-11-01 19:48:59 +03:00
|
|
|
return entriesArray;
|
2021-03-11 18:24:24 +03:00
|
|
|
},
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
setFacilityFilter(entriesArray) {
|
|
|
|
|
let logFacilitiesKeys = Object.keys(this.logFacilities);
|
|
|
|
|
if(logFacilitiesKeys.length > 0 && this.logFacilitiesDropdown) {
|
2023-11-26 16:49:59 +03:00
|
|
|
if(this.facilityFilterValue.length === 0 || logFacilitiesKeys.length === this.facilityFilterValue.length) {
|
2023-11-01 19:48:59 +03:00
|
|
|
return entriesArray;
|
|
|
|
|
};
|
2023-11-26 16:49:59 +03:00
|
|
|
return entriesArray.filter(e => this.facilityFilterValue.includes(e[3]));
|
2023-11-01 19:48:59 +03:00
|
|
|
};
|
|
|
|
|
return entriesArray;
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
setLevelFilter(entriesArray) {
|
2021-03-15 21:02:38 +03:00
|
|
|
let logLevelsKeys = Object.keys(this.logLevels);
|
2021-03-27 18:35:35 +03:00
|
|
|
if(logLevelsKeys.length > 0 && this.logLevelsDropdown) {
|
2023-11-26 16:49:59 +03:00
|
|
|
if(this.levelFilterValue.length === 0 || logLevelsKeys.length === this.levelFilterValue.length) {
|
2023-11-01 19:48:59 +03:00
|
|
|
return entriesArray;
|
2021-03-15 21:02:38 +03:00
|
|
|
};
|
2023-11-26 16:49:59 +03:00
|
|
|
return entriesArray.filter(e => this.levelFilterValue.includes(e[4]));
|
2021-03-15 21:02:38 +03:00
|
|
|
};
|
2023-11-01 19:48:59 +03:00
|
|
|
return entriesArray;
|
2021-03-15 21:02:38 +03:00
|
|
|
},
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
setMsgFilter(entriesArray) {
|
2023-11-26 16:49:59 +03:00
|
|
|
let fPattern = this.msgFilterValue;
|
2023-11-01 19:48:59 +03:00
|
|
|
if(!fPattern) {
|
|
|
|
|
return entriesArray;
|
|
|
|
|
};
|
2023-12-02 01:17:40 +03:00
|
|
|
return (this.msgFilterReValue) ?
|
|
|
|
|
this.setRegexpFilter(entriesArray, 5, fPattern, this.msgFilter) :
|
|
|
|
|
this.setStringFilter(entriesArray, 5, fPattern);
|
2023-11-01 19:48:59 +03:00
|
|
|
},
|
|
|
|
|
|
2023-11-10 02:39:58 +03:00
|
|
|
/**
|
2023-12-02 01:17:40 +03:00
|
|
|
* Creates the contents of the log area.
|
|
|
|
|
* Abstract method, must be overridden by a subclass!
|
|
|
|
|
*
|
|
|
|
|
* @instance
|
|
|
|
|
* @abstract
|
|
|
|
|
*
|
|
|
|
|
* @param {Array<number, string|null, string|null, string|null, string|null, string|null>} logdataArray
|
|
|
|
|
* @returns {Node}
|
|
|
|
|
* Returns a DOM node containing the log area.
|
|
|
|
|
*/
|
2023-11-01 19:48:59 +03:00
|
|
|
makeLogArea(logdataArray) {
|
2023-11-11 19:42:54 +03:00
|
|
|
throw new Error('makeLogArea must be overridden by a subclass');
|
2021-03-11 18:24:24 +03:00
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
disableFormElems() {
|
|
|
|
|
Array.from(this.logFilterForm.elements).forEach(
|
|
|
|
|
e => e.disabled = true
|
|
|
|
|
);
|
|
|
|
|
this.actionButtons.forEach(e => e.disabled = true);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
enableFormElems() {
|
|
|
|
|
Array.from(this.logFilterForm.elements).forEach(
|
|
|
|
|
e => e.disabled = false
|
|
|
|
|
);
|
|
|
|
|
this.actionButtons.forEach(e => e.disabled = false);
|
|
|
|
|
},
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
downloadLog(ev) {
|
|
|
|
|
this.disableFormElems();
|
2021-03-11 18:24:24 +03:00
|
|
|
return this.getLogData(0).then(logdata => {
|
|
|
|
|
logdata = logdata || '';
|
|
|
|
|
let link = E('a', {
|
2021-03-15 21:02:38 +03:00
|
|
|
'download': this.viewName + '.log',
|
2023-11-01 19:48:59 +03:00
|
|
|
'href' : URL.createObjectURL(
|
2021-03-11 18:24:24 +03:00
|
|
|
new Blob([ logdata ], { type: 'text/plain' })),
|
|
|
|
|
});
|
|
|
|
|
link.click();
|
|
|
|
|
URL.revokeObjectURL(link.href);
|
2023-12-02 01:17:40 +03:00
|
|
|
}).catch(err => {
|
2021-03-11 18:24:24 +03:00
|
|
|
ui.addNotification(null,
|
|
|
|
|
E('p', {}, _('Download error') + ': ' + err.message));
|
|
|
|
|
}).finally(() => {
|
2023-11-26 16:49:59 +03:00
|
|
|
this.enableFormElems();
|
2021-03-11 18:24:24 +03:00
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
restoreSettingsFromLocalStorage() {
|
2021-03-11 18:24:24 +03:00
|
|
|
let tailValueLocal = localStorage.getItem(`luci-app-${this.viewName}-tailValue`);
|
|
|
|
|
if(tailValueLocal) {
|
|
|
|
|
this.tailValue = Number(tailValueLocal);
|
|
|
|
|
};
|
2023-11-26 16:49:59 +03:00
|
|
|
let logSortingLocal = localStorage.getItem(`luci-app-${this.viewName}-logSortingValue`);
|
2021-03-11 18:24:24 +03:00
|
|
|
if(logSortingLocal) {
|
|
|
|
|
this.logSortingValue = logSortingLocal;
|
|
|
|
|
};
|
2023-12-02 01:17:40 +03:00
|
|
|
if(this.isAutorefresh) {
|
|
|
|
|
let autoRefreshLocal = localStorage.getItem(`luci-app-${this.viewName}-autoRefreshValue`);
|
|
|
|
|
if(autoRefreshLocal) {
|
|
|
|
|
this.autoRefreshValue = Boolean(Number(autoRefreshLocal));
|
|
|
|
|
};
|
2023-11-26 16:49:59 +03:00
|
|
|
};
|
2023-11-21 18:16:55 +03:00
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
saveSettingsToLocalStorage(tailValue, logSortingValue, autoRefreshValue) {
|
|
|
|
|
tailValue = this.checkZeroValue(tailValue);
|
2023-11-21 18:16:55 +03:00
|
|
|
if(this.tailValue != tailValue) {
|
|
|
|
|
localStorage.setItem(
|
2023-11-26 16:49:59 +03:00
|
|
|
`luci-app-${this.viewName}-tailValue`, String(tailValue));
|
2023-11-21 18:16:55 +03:00
|
|
|
};
|
|
|
|
|
if(this.logSortingValue != logSortingValue) {
|
|
|
|
|
localStorage.setItem(
|
2023-11-26 16:49:59 +03:00
|
|
|
`luci-app-${this.viewName}-logSortingValue`, logSortingValue);
|
|
|
|
|
};
|
2023-12-02 01:17:40 +03:00
|
|
|
if(this.isAutorefresh) {
|
|
|
|
|
if(this.autoRefreshValue != autoRefreshValue) {
|
|
|
|
|
localStorage.setItem(
|
|
|
|
|
`luci-app-${this.viewName}-autoRefreshValue`, String(Number(autoRefreshValue)));
|
|
|
|
|
};
|
2023-11-21 18:16:55 +03:00
|
|
|
};
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
reloadLog(tail, modal=false, autorefresh=false) {
|
2023-11-21 18:16:55 +03:00
|
|
|
tail = (tail && tail > 0) ? tail : 0;
|
2023-11-26 16:49:59 +03:00
|
|
|
if(!autorefresh) {
|
|
|
|
|
this.disableFormElems();
|
|
|
|
|
poll.stop();
|
|
|
|
|
};
|
2023-11-21 18:16:55 +03:00
|
|
|
return this.getLogData(tail).then(logdata => {
|
|
|
|
|
logdata = logdata || '';
|
|
|
|
|
this.logWrapper.innerHTML = '';
|
|
|
|
|
this.logWrapper.append(
|
|
|
|
|
this.makeLogArea(
|
|
|
|
|
this.setMsgFilter(
|
|
|
|
|
this.setFacilityFilter(
|
|
|
|
|
this.setLevelFilter(
|
|
|
|
|
this.setHostFilter(
|
2023-12-02 01:17:40 +03:00
|
|
|
this.setTimeFilter(
|
2023-11-21 18:16:55 +03:00
|
|
|
this.parseLogData(logdata, tail)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
if(logdata && logdata !== '') {
|
|
|
|
|
if(this.isFacilities && !this.logFacilitiesDropdown) {
|
|
|
|
|
this.logFacilitiesDropdownElem = this.makeLogFacilitiesDropdownSection();
|
|
|
|
|
};
|
|
|
|
|
if(this.isLevels && !this.logLevelsDropdown) {
|
|
|
|
|
this.logLevelsDropdownElem = this.makeLogLevelsDropdownSection();
|
|
|
|
|
};
|
|
|
|
|
if(this.isHosts && !this.logHostsDropdown) {
|
|
|
|
|
this.logHostsDropdownElem = this.makeLogHostsDropdownSection();
|
|
|
|
|
};
|
|
|
|
|
};
|
2023-12-02 01:17:40 +03:00
|
|
|
|
|
|
|
|
if(!autorefresh) {
|
|
|
|
|
poll.start();
|
|
|
|
|
};
|
2023-11-21 18:16:55 +03:00
|
|
|
}).finally(() => {
|
2023-11-26 16:49:59 +03:00
|
|
|
if(modal) {
|
|
|
|
|
ui.hideModal();
|
|
|
|
|
};
|
|
|
|
|
if(!autorefresh) {
|
|
|
|
|
this.enableFormElems();
|
|
|
|
|
};
|
2023-11-21 18:16:55 +03:00
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
filterSettingsModal() {
|
|
|
|
|
return ui.showModal(_('Filter settings'), [
|
|
|
|
|
E('div', { 'class': 'cbi-map' }, [
|
|
|
|
|
E('div', { 'class': 'cbi-section' }, [
|
|
|
|
|
E('div', { 'class': 'cbi-section-node' }, [
|
|
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
|
|
|
|
'for' : 'tailInput',
|
|
|
|
|
}, _('Last entries')),
|
2023-12-02 01:17:40 +03:00
|
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
|
|
|
this.tailInput,
|
|
|
|
|
E('button', {
|
|
|
|
|
'class': 'cbi-button btn',
|
|
|
|
|
'click': L.bind(ev => {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
this.tailInput.value = 0;
|
|
|
|
|
this.tailInput.focus();
|
|
|
|
|
}, this),
|
|
|
|
|
}, '⌫'),
|
|
|
|
|
]),
|
2023-11-21 18:16:55 +03:00
|
|
|
]),
|
|
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
|
|
|
|
'for' : 'timeFilter',
|
|
|
|
|
}, _('Timestamp filter')),
|
2023-12-02 01:17:40 +03:00
|
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
|
|
|
this.timeFilter,
|
|
|
|
|
E('button', {
|
|
|
|
|
'class': 'cbi-button btn',
|
|
|
|
|
'click': L.bind(ev => {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
this.timeFilter.value = null;
|
|
|
|
|
this.timeFilter.focus();
|
|
|
|
|
}, this),
|
|
|
|
|
}, '⌫'),
|
|
|
|
|
]),
|
|
|
|
|
]),
|
|
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
|
|
|
|
'for' : 'timeFilterRe',
|
|
|
|
|
}, _('Filter is regexp')),
|
|
|
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
|
|
|
E('div', { 'class': 'cbi-checkbox' }, [
|
|
|
|
|
this.timeFilterRe,
|
|
|
|
|
E('label', {}),
|
|
|
|
|
]),
|
|
|
|
|
E('div', { 'class': 'cbi-value-description' },
|
|
|
|
|
_('Apply timestamp filter as regular expression')
|
|
|
|
|
),
|
|
|
|
|
]),
|
2023-11-21 18:16:55 +03:00
|
|
|
]),
|
|
|
|
|
this.logHostsDropdownElem,
|
|
|
|
|
this.logFacilitiesDropdownElem,
|
|
|
|
|
this.logLevelsDropdownElem,
|
|
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
|
|
|
|
'for' : 'msgFilter',
|
|
|
|
|
}, _('Message filter')),
|
2023-12-02 01:17:40 +03:00
|
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
|
|
|
this.msgFilter,
|
|
|
|
|
E('button', {
|
|
|
|
|
'class': 'cbi-button btn',
|
|
|
|
|
'click': L.bind(ev => {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
this.msgFilter.value = null;
|
|
|
|
|
this.msgFilter.focus();
|
|
|
|
|
}, this),
|
|
|
|
|
}, '⌫'),
|
|
|
|
|
]),
|
2023-11-21 18:16:55 +03:00
|
|
|
]),
|
|
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
2023-12-02 01:17:40 +03:00
|
|
|
'for' : 'msgFilterRe',
|
|
|
|
|
}, _('Filter is regexp')),
|
|
|
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
|
|
|
|
E('div', { 'class': 'cbi-checkbox' }, [
|
|
|
|
|
this.msgFilterRe,
|
|
|
|
|
E('label', {}),
|
|
|
|
|
]),
|
|
|
|
|
E('div', { 'class': 'cbi-value-description' },
|
|
|
|
|
_('Apply message filter as regular expression')
|
|
|
|
|
),
|
|
|
|
|
]),
|
2023-11-21 18:16:55 +03:00
|
|
|
]),
|
2023-11-26 16:49:59 +03:00
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
2023-12-02 01:17:40 +03:00
|
|
|
'for' : 'logSorting',
|
|
|
|
|
}, _('Sorting entries')),
|
|
|
|
|
E('div', { 'class': 'cbi-value-field' }, this.logSorting),
|
2023-11-26 16:49:59 +03:00
|
|
|
]),
|
2023-12-02 01:17:40 +03:00
|
|
|
((this.isAutorefresh) ?
|
|
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
|
|
|
|
'for' : 'autoRefresh',
|
|
|
|
|
}, _('Auto refresh')),
|
|
|
|
|
E('div', { 'class': 'cbi-value-field' },
|
|
|
|
|
E('div', { 'class': 'cbi-checkbox' }, [
|
|
|
|
|
this.autoRefresh,
|
|
|
|
|
E('label', {}),
|
|
|
|
|
])
|
|
|
|
|
),
|
|
|
|
|
]) : ''),
|
2023-11-21 18:16:55 +03:00
|
|
|
]),
|
|
|
|
|
]),
|
|
|
|
|
]),
|
|
|
|
|
E('div', { 'class': 'right' }, [
|
2023-11-26 16:49:59 +03:00
|
|
|
this.logFilterForm,
|
2023-11-21 18:16:55 +03:00
|
|
|
E('button', {
|
|
|
|
|
'class': 'btn',
|
2023-11-26 16:49:59 +03:00
|
|
|
'click': ev => {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
this.resetFormValues();
|
2023-12-02 01:17:40 +03:00
|
|
|
this.timeFilter.focus();
|
|
|
|
|
this.msgFilter.focus();
|
|
|
|
|
ui.hideModal();
|
2023-11-26 16:49:59 +03:00
|
|
|
},
|
|
|
|
|
}, _('Dismiss')),
|
|
|
|
|
' ',
|
|
|
|
|
E('button', {
|
|
|
|
|
'type' : 'submit',
|
|
|
|
|
'form' : 'logFilterForm',
|
|
|
|
|
'class': 'btn cbi-button-positive important',
|
|
|
|
|
'click': ui.createHandlerFn(this, function(ev) {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
return this.onSubmitFilter();
|
|
|
|
|
}),
|
|
|
|
|
}, _('Apply')),
|
2023-11-21 18:16:55 +03:00
|
|
|
]),
|
|
|
|
|
], 'cbi-modal');
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
updateLog(autorefresh=false) {
|
|
|
|
|
let tail = (Number(this.tailValue) == 0 || Number(this.fastTailValue) == 0)
|
|
|
|
|
? 0 : Math.max(Number(this.tailValue), this.fastTailValue)
|
|
|
|
|
return this.reloadLog(tail, false, autorefresh);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
/**
|
2023-12-02 01:17:40 +03:00
|
|
|
* Creates a promise for the RPC request.
|
|
|
|
|
* Abstract method, must be overridden by a subclass!
|
|
|
|
|
*
|
|
|
|
|
* To completely disable the auto log refresh option, views extending
|
|
|
|
|
* this base class should overwrite the `getLogHash` function
|
|
|
|
|
* with `null`.
|
|
|
|
|
*
|
|
|
|
|
* @instance
|
|
|
|
|
* @abstract
|
|
|
|
|
*
|
|
|
|
|
* @returns {Promise}
|
|
|
|
|
* Returns a promise that returns the unique value for the current log state.
|
|
|
|
|
*/
|
|
|
|
|
getLogHash() {
|
|
|
|
|
throw new Error('getLogHash must be overridden by a subclass');
|
2023-11-26 16:49:59 +03:00
|
|
|
},
|
|
|
|
|
|
|
|
|
|
async pollFunc() {
|
2023-12-02 01:17:40 +03:00
|
|
|
await this.getLogHash().then(async hash => {
|
|
|
|
|
if(this.lastHash !== hash) {
|
|
|
|
|
this.lastHash = hash;
|
2023-11-26 16:49:59 +03:00
|
|
|
return await this.updateLog(true);
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
onSubmitFilter() {
|
|
|
|
|
this.saveSettingsToLocalStorage(
|
|
|
|
|
this.tailInput.value, this.logSorting.value, this.autoRefresh.checked);
|
|
|
|
|
this.setFilterSettings();
|
|
|
|
|
this.fastTailValue = Number(this.tailValue);
|
|
|
|
|
return this.reloadLog(Number(this.tailValue), true);
|
|
|
|
|
},
|
|
|
|
|
|
2024-03-07 01:06:28 +03:00
|
|
|
scrollToTop() {
|
|
|
|
|
this.logWrapper.scrollIntoView(true);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
scrollToBottom() {
|
|
|
|
|
this.logWrapper.scrollIntoView(false);
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
load() {
|
2023-11-26 16:49:59 +03:00
|
|
|
this.restoreSettingsFromLocalStorage();
|
2024-05-12 18:50:13 +03:00
|
|
|
if(!this.autoRefresh || typeof(this.getLogHash) != 'function') {
|
2023-12-02 01:17:40 +03:00
|
|
|
this.isAutorefresh = false;
|
|
|
|
|
this.autoRefreshValue = false;
|
|
|
|
|
};
|
2021-03-11 18:24:24 +03:00
|
|
|
return this.getLogData(this.tailValue);
|
|
|
|
|
},
|
|
|
|
|
|
2023-11-01 19:48:59 +03:00
|
|
|
render(logdata) {
|
2023-11-26 16:49:59 +03:00
|
|
|
this.pollFuncWrapper = L.bind(this.pollFunc, this);
|
|
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logWrapper = E('div', {
|
2024-02-27 17:31:44 +03:00
|
|
|
'id': 'logWrapper',
|
2021-03-11 18:24:24 +03:00
|
|
|
}, this.makeLogArea(this.parseLogData(logdata, this.tailValue)));
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
this.fastTailValue = this.tailValue
|
2023-11-21 18:16:55 +03:00
|
|
|
|
|
|
|
|
this.tailInput = E('input', {
|
2021-12-05 19:18:32 +03:00
|
|
|
'id' : 'tailInput',
|
|
|
|
|
'name' : 'tailInput',
|
|
|
|
|
'type' : 'text',
|
2023-11-26 16:49:59 +03:00
|
|
|
'form' : 'logFilterForm',
|
2021-12-05 19:18:32 +03:00
|
|
|
'class' : 'cbi-input-text',
|
|
|
|
|
'style' : 'width:4em !important; min-width:4em !important',
|
2021-03-11 18:24:24 +03:00
|
|
|
'maxlength': 5,
|
|
|
|
|
});
|
2023-11-26 16:49:59 +03:00
|
|
|
this.tailInput.value = this.tailValue;
|
2023-11-21 18:16:55 +03:00
|
|
|
ui.addValidator(this.tailInput, 'uinteger', true);
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logHostsDropdownElem = '';
|
|
|
|
|
this.logFacilitiesDropdownElem = '';
|
|
|
|
|
this.logLevelsDropdownElem = '';
|
2021-03-27 18:35:35 +03:00
|
|
|
if(this.isLevels) {
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logLevelsDropdownElem = this.makeLogLevelsDropdownSection();
|
2021-03-27 18:35:35 +03:00
|
|
|
};
|
2023-11-01 19:48:59 +03:00
|
|
|
if(this.isFacilities) {
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logFacilitiesDropdownElem = this.makeLogFacilitiesDropdownSection();
|
2023-11-01 19:48:59 +03:00
|
|
|
};
|
2021-03-27 18:35:35 +03:00
|
|
|
if(this.isHosts) {
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logHostsDropdownElem = this.makeLogHostsDropdownSection();
|
2021-03-11 18:24:24 +03:00
|
|
|
};
|
|
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
this.timeFilter = E('input', {
|
2023-11-01 19:48:59 +03:00
|
|
|
'id' : 'timeFilter',
|
|
|
|
|
'name' : 'timeFilter',
|
|
|
|
|
'type' : 'text',
|
2023-11-26 16:49:59 +03:00
|
|
|
'form' : 'logFilterForm',
|
2023-11-01 19:48:59 +03:00
|
|
|
'class' : 'cbi-input-text',
|
2023-12-02 01:17:40 +03:00
|
|
|
'placeholder': _('Type a search pattern...'),
|
2023-11-01 19:48:59 +03:00
|
|
|
});
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
this.timeFilterRe = E('input', {
|
|
|
|
|
'id' : 'timeFilterRe',
|
|
|
|
|
'name' : 'timeFilterRe',
|
|
|
|
|
'type' : 'checkbox',
|
|
|
|
|
'form' : 'logFilterForm',
|
|
|
|
|
'change': ev => this.timeFilter.focus(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.setRegexpValidator(this.timeFilter, this.timeFilterRe);
|
|
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
this.msgFilter = E('input', {
|
2023-11-01 19:48:59 +03:00
|
|
|
'id' : 'msgFilter',
|
|
|
|
|
'name' : 'msgFilter',
|
2021-11-04 18:57:08 +03:00
|
|
|
'type' : 'text',
|
2023-11-26 16:49:59 +03:00
|
|
|
'form' : 'logFilterForm',
|
2021-11-04 18:57:08 +03:00
|
|
|
'class' : 'cbi-input-text',
|
2023-12-02 01:17:40 +03:00
|
|
|
'placeholder': _('Type a search pattern...'),
|
2021-03-11 18:24:24 +03:00
|
|
|
});
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
this.msgFilterRe = E('input', {
|
|
|
|
|
'id' : 'msgFilterRe',
|
|
|
|
|
'name' : 'msgFilterRe',
|
|
|
|
|
'type' : 'checkbox',
|
|
|
|
|
'form' : 'logFilterForm',
|
|
|
|
|
'change': ev => this.msgFilter.focus(),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.setRegexpValidator(this.msgFilter, this.msgFilterRe);
|
|
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logSorting = E('select', {
|
2021-11-04 18:57:08 +03:00
|
|
|
'id' : 'logSorting',
|
|
|
|
|
'name' : 'logSorting',
|
2023-11-26 16:49:59 +03:00
|
|
|
'form' : 'logFilterForm',
|
2021-03-11 18:24:24 +03:00
|
|
|
'class': "cbi-input-select",
|
|
|
|
|
}, [
|
|
|
|
|
E('option', { 'value': 'asc' }, _('ascending')),
|
|
|
|
|
E('option', { 'value': 'desc' }, _('descending')),
|
|
|
|
|
]);
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logSorting.value = this.logSortingValue;
|
2021-03-11 18:24:24 +03:00
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
this.autoRefresh = E('input', {
|
|
|
|
|
'id' : 'autoRefresh',
|
|
|
|
|
'name' : 'autoRefresh',
|
|
|
|
|
'type' : 'checkbox',
|
|
|
|
|
'form' : 'logFilterForm',
|
|
|
|
|
});
|
|
|
|
|
this.autoRefresh.checked = this.autoRefreshValue;
|
|
|
|
|
|
|
|
|
|
this.filterEditsBtn = E('button', {
|
|
|
|
|
'class': 'cbi-button btn cbi-button-action',
|
|
|
|
|
'click': L.bind(this.filterSettingsModal, this),
|
|
|
|
|
}, _('Edit'));
|
|
|
|
|
|
|
|
|
|
this.logFilterForm = E('form', {
|
|
|
|
|
'id' : 'logFilterForm',
|
|
|
|
|
'name' : 'logFilterForm',
|
|
|
|
|
'submit': ev => {
|
|
|
|
|
ev.preventDefault();
|
|
|
|
|
return this.onSubmitFilter();
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logDownloadBtn = E('button', {
|
2021-11-04 18:57:08 +03:00
|
|
|
'id' : 'logDownloadBtn',
|
|
|
|
|
'name' : 'logDownloadBtn',
|
2021-03-11 18:24:24 +03:00
|
|
|
'class': 'cbi-button btn',
|
|
|
|
|
'click': ui.createHandlerFn(this, this.downloadLog),
|
|
|
|
|
}, _('Download log'));
|
|
|
|
|
|
2023-11-26 16:49:59 +03:00
|
|
|
this.refreshBtn = E('button', {
|
2024-03-07 01:06:28 +03:00
|
|
|
'title': _('Refresh log'),
|
|
|
|
|
'class': 'cbi-button btn log-side-btn',
|
|
|
|
|
'style': `visibility:${(this.autoRefreshValue) ? 'hidden' : 'visible'}`,
|
|
|
|
|
'click': ui.createHandlerFn(this, function(ev) {
|
2023-11-26 16:49:59 +03:00
|
|
|
ev.target.blur();
|
|
|
|
|
return this.updateLog();
|
|
|
|
|
}),
|
|
|
|
|
}, '⟳');
|
|
|
|
|
|
|
|
|
|
this.moreEntriesBtn = E('button', {
|
|
|
|
|
'title': _('Get more entries'),
|
2023-12-02 01:17:40 +03:00
|
|
|
'class': 'cbi-button btn log-side-btn',
|
2023-11-26 16:49:59 +03:00
|
|
|
'style': 'margin-top:1px !important',
|
|
|
|
|
'click': ui.createHandlerFn(this, function(ev) {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
if(this.fastTailValue === null) {
|
|
|
|
|
this.fastTailValue = Number(this.tailValue);
|
|
|
|
|
}
|
|
|
|
|
if(this.fastTailValue > 0) {
|
|
|
|
|
this.fastTailValue += this.fastTailIncrement;
|
|
|
|
|
};
|
2024-05-12 18:50:13 +03:00
|
|
|
return this.reloadLog(this.fastTailValue);
|
2023-11-26 16:49:59 +03:00
|
|
|
}),
|
|
|
|
|
}, `+${this.fastTailIncrement}`);
|
|
|
|
|
|
|
|
|
|
this.allEntriesBtn = E('button', {
|
|
|
|
|
'title': _('Get all entries'),
|
2023-12-02 01:17:40 +03:00
|
|
|
'class': 'cbi-button btn log-side-btn',
|
2023-11-26 16:49:59 +03:00
|
|
|
'style': 'margin-top:1px !important',
|
|
|
|
|
'click': ui.createHandlerFn(this, function(ev) {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
this.fastTailValue = 0;
|
|
|
|
|
return this.reloadLog(0);
|
2023-11-21 18:16:55 +03:00
|
|
|
}),
|
2023-11-26 16:49:59 +03:00
|
|
|
}, _('All'));
|
|
|
|
|
|
|
|
|
|
this.filterModalBtn = E('button', {
|
|
|
|
|
'title': _('Filter settings'),
|
2023-12-02 01:17:40 +03:00
|
|
|
'class': 'cbi-button btn log-side-btn',
|
2023-11-26 16:49:59 +03:00
|
|
|
'style': 'margin-top:10px !important',
|
|
|
|
|
'click': ev => {
|
|
|
|
|
ev.target.blur();
|
|
|
|
|
this.filterSettingsModal();
|
|
|
|
|
},
|
|
|
|
|
}, '▢');
|
|
|
|
|
|
|
|
|
|
this.actionButtons.push(this.filterEditsBtn, this.logDownloadBtn,
|
|
|
|
|
this.refreshBtn,this.moreEntriesBtn,
|
|
|
|
|
this.allEntriesBtn, this.filterModalBtn);
|
2023-11-01 19:48:59 +03:00
|
|
|
|
2023-11-10 02:39:58 +03:00
|
|
|
document.body.append(
|
|
|
|
|
E('div', {
|
2023-11-21 18:16:55 +03:00
|
|
|
'align': 'right',
|
|
|
|
|
'class': 'log-side-block',
|
2023-11-10 02:39:58 +03:00
|
|
|
}, [
|
2023-11-26 16:49:59 +03:00
|
|
|
this.refreshBtn,
|
|
|
|
|
this.moreEntriesBtn,
|
|
|
|
|
this.allEntriesBtn,
|
|
|
|
|
this.filterModalBtn,
|
2023-11-21 18:16:55 +03:00
|
|
|
E('button', {
|
2023-12-02 01:17:40 +03:00
|
|
|
'class': 'cbi-button btn log-side-btn',
|
2023-11-21 18:16:55 +03:00
|
|
|
'style': 'margin-top:10px !important',
|
2023-11-10 02:39:58 +03:00
|
|
|
'click': ev => {
|
2024-03-07 01:06:28 +03:00
|
|
|
this.scrollToTop();
|
2023-11-10 02:39:58 +03:00
|
|
|
ev.target.blur();
|
|
|
|
|
},
|
|
|
|
|
}, '↑'),
|
|
|
|
|
E('button', {
|
2023-12-02 01:17:40 +03:00
|
|
|
'class': 'cbi-button btn log-side-btn',
|
2023-11-10 02:39:58 +03:00
|
|
|
'style': 'margin-top:1px !important',
|
|
|
|
|
'click': ev => {
|
2024-03-07 01:06:28 +03:00
|
|
|
this.scrollToBottom();
|
2023-11-10 02:39:58 +03:00
|
|
|
ev.target.blur();
|
|
|
|
|
},
|
|
|
|
|
}, '↓'),
|
|
|
|
|
])
|
|
|
|
|
);
|
|
|
|
|
|
2023-12-02 01:17:40 +03:00
|
|
|
if(this.isAutorefresh && this.autoRefreshValue) {
|
2023-11-26 16:49:59 +03:00
|
|
|
poll.add(this.pollFuncWrapper, this.pollInterval);
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-11 18:24:24 +03:00
|
|
|
return E([
|
|
|
|
|
E('h2', { 'id': 'logTitle', 'class': 'fade-in' }, this.title),
|
|
|
|
|
E('div', { 'class': 'cbi-section-descr fade-in' }),
|
|
|
|
|
E('div', { 'class': 'cbi-section fade-in' },
|
|
|
|
|
E('div', { 'class': 'cbi-section-node' }, [
|
|
|
|
|
E('div', { 'class': 'cbi-value' }, [
|
|
|
|
|
E('label', {
|
|
|
|
|
'class': 'cbi-value-title',
|
2023-11-21 18:16:55 +03:00
|
|
|
'for' : 'filterSettings',
|
|
|
|
|
}, _('Filter settings')),
|
2021-03-11 18:24:24 +03:00
|
|
|
E('div', { 'class': 'cbi-value-field' }, [
|
2023-11-26 16:49:59 +03:00
|
|
|
E('div', {}, this.filterEditsBtn),
|
2022-05-23 22:01:50 +03:00
|
|
|
E('input', {
|
2023-11-21 18:16:55 +03:00
|
|
|
'id' : 'filterSettings',
|
2022-05-23 22:01:50 +03:00
|
|
|
'type': 'hidden',
|
|
|
|
|
}),
|
2021-03-11 18:24:24 +03:00
|
|
|
]),
|
|
|
|
|
]),
|
|
|
|
|
])
|
|
|
|
|
),
|
|
|
|
|
E('div', { 'class': 'cbi-section fade-in' },
|
2023-11-10 02:39:58 +03:00
|
|
|
E('div', { 'class': 'cbi-section-node' },
|
2023-11-21 18:16:55 +03:00
|
|
|
this.logWrapper
|
2023-11-10 02:39:58 +03:00
|
|
|
)
|
2021-03-11 18:24:24 +03:00
|
|
|
),
|
|
|
|
|
E('div', { 'class': 'cbi-section fade-in' },
|
|
|
|
|
E('div', { 'class': 'cbi-section-node' },
|
|
|
|
|
E('div', { 'class': 'cbi-value' },
|
2023-11-21 18:16:55 +03:00
|
|
|
E('div', {
|
|
|
|
|
'align': 'left',
|
|
|
|
|
'style': 'width:100%',
|
|
|
|
|
}, this.logDownloadBtn)
|
2021-03-15 21:02:38 +03:00
|
|
|
),
|
2021-03-11 18:24:24 +03:00
|
|
|
)
|
|
|
|
|
),
|
|
|
|
|
]);
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
handleSaveApply: null,
|
2021-12-05 19:18:32 +03:00
|
|
|
handleSave : null,
|
2021-11-04 18:57:08 +03:00
|
|
|
handleReset : null,
|
2021-03-11 18:24:24 +03:00
|
|
|
}),
|
|
|
|
|
})
|