luci-app: updated log.

This commit is contained in:
gSpot
2023-12-02 01:17:40 +03:00
parent 25e681055e
commit 81a27975e8
9 changed files with 296 additions and 169 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ LUCI_APP=1
OWRT_VERSION="current" OWRT_VERSION="current"
RUAB_VERSION="1.3-1" RUAB_VERSION="1.3-1"
RUAB_MOD_LUA_VERSION="1.3-2" RUAB_MOD_LUA_VERSION="1.3-2"
RUAB_LUCI_APP_VERSION="1.3-4" RUAB_LUCI_APP_VERSION="1.3-5"
BASE_URL="https://raw.githubusercontent.com/gSpotx2f/packages-openwrt/master" BASE_URL="https://raw.githubusercontent.com/gSpotx2f/packages-openwrt/master"
PKG_DIR="/tmp" PKG_DIR="/tmp"
+1 -1
View File
@@ -4,7 +4,7 @@
include $(TOPDIR)/rules.mk include $(TOPDIR)/rules.mk
PKG_VERSION:=1.3-4 PKG_VERSION:=1.3-5
LUCI_TITLE:=LuCI support for ruantiblock LUCI_TITLE:=LuCI support for ruantiblock
LUCI_DEPENDS:=+ruantiblock LUCI_DEPENDS:=+ruantiblock
LUCI_PKGARCH:=all LUCI_PKGARCH:=all
@@ -152,14 +152,16 @@ return baseclass.extend({
view: view.extend({ view: view.extend({
/** /**
* View name (for local storage and downloads). * View name (for local storage and downloads).
* Must be overridden by a subclass! *
*/ * @property {string} viewName
*/
viewName : null, viewName : null,
/** /**
* Page title. * Page title.
* Must be overridden by a subclass! *
*/ * @property {string} title
*/
title : null, title : null,
pollInterval : L.env.pollinterval, pollInterval : L.env.pollinterval,
@@ -208,6 +210,8 @@ return baseclass.extend({
timeFilterValue : null, timeFilterValue : null,
timeFilterReValue : false,
hostFilterValue : [], hostFilterValue : [],
facilityFilterValue : [], facilityFilterValue : [],
@@ -216,10 +220,14 @@ return baseclass.extend({
msgFilterValue : null, msgFilterValue : null,
msgFilterReValue : false,
logSortingValue : 'asc', logSortingValue : 'asc',
autoRefreshValue : true, autoRefreshValue : true,
isAutorefresh : true,
isHosts : false, isHosts : false,
isFacilities : false, isFacilities : false,
@@ -238,7 +246,7 @@ return baseclass.extend({
totalLogLines : 0, totalLogLines : 0,
lastBytes : null, lastHash : null,
actionButtons : [], actionButtons : [],
@@ -334,9 +342,32 @@ return baseclass.extend({
); );
}, },
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'
);
},
setFilterSettings() { setFilterSettings() {
this.tailValue = this.checkZeroValue(this.tailInput.value); this.tailValue = this.checkZeroValue(this.tailInput.value);
this.timeFilterValue = this.timeFilter.value; this.timeFilterValue = this.timeFilter.value;
this.timeFilterReValue = this.timeFilterRe.checked;
if(this.isHosts) { if(this.isHosts) {
this.hostFilterValue = this.logHostsDropdown.getValue(); this.hostFilterValue = this.logHostsDropdown.getValue();
}; };
@@ -347,20 +378,24 @@ return baseclass.extend({
this.levelFilterValue = this.logLevelsDropdown.getValue(); this.levelFilterValue = this.logLevelsDropdown.getValue();
}; };
this.msgFilterValue = this.msgFilter.value; this.msgFilterValue = this.msgFilter.value;
this.msgFilterReValue = this.msgFilterRe.checked;
this.logSortingValue = this.logSorting.value; this.logSortingValue = this.logSorting.value;
this.autoRefreshValue = this.autoRefresh.checked; this.autoRefreshValue = this.autoRefresh.checked;
if(this.autoRefreshValue) { if(this.isAutorefresh) {
poll.add(this.pollFuncWrapper, this.pollInterval); if(this.autoRefreshValue) {
this.refreshBtn.style.visibility = 'hidden'; poll.add(this.pollFuncWrapper, this.pollInterval);
} else { this.refreshBtn.style.visibility = 'hidden';
poll.remove(this.pollFuncWrapper); } else {
this.refreshBtn.style.visibility = 'visible'; poll.remove(this.pollFuncWrapper);
this.refreshBtn.style.visibility = 'visible';
};
}; };
}, },
resetFormValues() { resetFormValues() {
this.tailInput.value = this.tailValue; this.tailInput.value = this.tailValue;
this.timeFilter.value = this.timeFilterValue; this.timeFilter.value = this.timeFilterValue;
this.timeFilterRe.checked = this.timeFilterReValue;
if(this.isHosts) { if(this.isHosts) {
this.logHostsDropdown.setValue(this.hostFilterValue); this.logHostsDropdown.setValue(this.hostFilterValue);
}; };
@@ -371,55 +406,78 @@ return baseclass.extend({
this.logLevelsDropdown.setValue(this.levelFilterValue); this.logLevelsDropdown.setValue(this.levelFilterValue);
}; };
this.msgFilter.value = this.msgFilterValue; this.msgFilter.value = this.msgFilterValue;
this.msgFilterRe.checked = this.msgFilterReValue;
this.logSorting.value = this.logSortingValue; this.logSorting.value = this.logSortingValue;
this.autoRefresh.checked = this.autoRefreshValue; this.autoRefresh.checked = this.autoRefreshValue;
}, },
/** /**
* Receives raw log data. * Receives raw log data.
* Abstract method, must be overridden by a subclass! * Abstract method, must be overridden by a subclass!
* *
* @param {number} tail * @instance
* @returns {string} * @abstract
* Returns the raw content of the log. *
*/ * @param {number} tail
* @returns {string}
* Returns the raw content of the log.
*/
getLogData(tail) { getLogData(tail) {
throw new Error('getLogData must be overridden by a subclass'); throw new Error('getLogData must be overridden by a subclass');
}, },
/** /**
* Parses log data. * Parses log data.
* Abstract method, must be overridden by a subclass! * Abstract method, must be overridden by a subclass!
* *
* @param {string} logdata * @instance
* @param {number} tail * @abstract
* @returns {Array<number, string|null, string|null, string|null, string|null, string|null>} *
* Returns an array of values: [ #, Timestamp, Host, Level, Facility, Message ]. * @param {string} logdata
*/ * @param {number} tail
* @returns {Array<number, string|null, string|null, string|null, string|null, string|null>}
* Returns an array of values: [ #, Timestamp, Host, Level, Facility, Message ].
*/
parseLogData(logdata, tail) { parseLogData(logdata, tail) {
throw new Error('parseLogData must be overridden by a subclass'); throw new Error('parseLogData must be overridden by a subclass');
}, },
/** /**
* Highlight the result of a regular expression. * Highlight the result of a regular expression.
* Abstract method, must be overridden by a subclass! * Abstract method, must be overridden by a subclass!
* *
* @param {string} logdata * @instance
* @returns {string} * @abstract
* Returns a string with the highlighted part. *
*/ * @param {string} logdata
regexpFilterHighlightFunc(match) { * @returns {string}
throw new Error('regexpFilterHighlightFunc must be overridden by a subclass'); * Returns a string with the highlighted part.
*/
filterHighlightFunc(match) {
throw new Error('filterHighlightFunc must be overridden by a subclass');
}, },
setRegexpFilter(entriesArray, fieldNum, pattern) { setStringFilter(entriesArray, fieldNum, pattern) {
let fArr = [];
entriesArray.forEach((e, i) => {
if(e[fieldNum] !== null && e[fieldNum].includes(pattern)) {
if(this.filterHighlightFunc) {
e[fieldNum] = e[fieldNum].replace(pattern, this.filterHighlightFunc);
};
fArr.push(e);
};
});
return fArr;
},
setRegexpFilter(entriesArray, fieldNum, pattern, formElem) {
let fArr = []; let fArr = [];
try { try {
let regExp = new RegExp(pattern, 'giu'); let regExp = new RegExp(pattern, 'giu');
entriesArray.forEach((e, i) => { entriesArray.forEach((e, i) => {
if(e[fieldNum] !== null && regExp.test(e[fieldNum])) { if(e[fieldNum] !== null && regExp.test(e[fieldNum])) {
if(this.regexpFilterHighlightFunc) { if(this.filterHighlightFunc) {
e[fieldNum] = e[fieldNum].replace(regExp, this.regexpFilterHighlightFunc); e[fieldNum] = e[fieldNum].replace(regExp, this.filterHighlightFunc);
}; };
fArr.push(e); fArr.push(e);
}; };
@@ -437,12 +495,14 @@ return baseclass.extend({
return fArr; return fArr;
}, },
setDateFilter(entriesArray) { setTimeFilter(entriesArray) {
let fPattern = this.timeFilterValue; let fPattern = this.timeFilterValue;
if(!fPattern) { if(!fPattern) {
return entriesArray; return entriesArray;
}; };
return this.setRegexpFilter(entriesArray, 1, fPattern); return (this.timeFilterReValue) ?
this.setRegexpFilter(entriesArray, 1, fPattern, this.timeFilter) :
this.setStringFilter(entriesArray, 1, fPattern);
}, },
setHostFilter(entriesArray) { setHostFilter(entriesArray) {
@@ -484,17 +544,22 @@ return baseclass.extend({
if(!fPattern) { if(!fPattern) {
return entriesArray; return entriesArray;
}; };
return this.setRegexpFilter(entriesArray, 5, fPattern); return (this.msgFilterReValue) ?
this.setRegexpFilter(entriesArray, 5, fPattern, this.msgFilter) :
this.setStringFilter(entriesArray, 5, fPattern);
}, },
/** /**
* Creates the contents of the log area. * Creates the contents of the log area.
* Abstract method, must be overridden by a subclass! * Abstract method, must be overridden by a subclass!
* *
* @param {Array<number, string|null, string|null, string|null, string|null, string|null>} logdataArray * @instance
* @returns {Node} * @abstract
* Returns a DOM node containing the log area. *
*/ * @param {Array<number, string|null, string|null, string|null, string|null, string|null>} logdataArray
* @returns {Node}
* Returns a DOM node containing the log area.
*/
makeLogArea(logdataArray) { makeLogArea(logdataArray) {
throw new Error('makeLogArea must be overridden by a subclass'); throw new Error('makeLogArea must be overridden by a subclass');
}, },
@@ -524,7 +589,7 @@ return baseclass.extend({
}); });
link.click(); link.click();
URL.revokeObjectURL(link.href); URL.revokeObjectURL(link.href);
}).catch(() => { }).catch(err => {
ui.addNotification(null, ui.addNotification(null,
E('p', {}, _('Download error') + ': ' + err.message)); E('p', {}, _('Download error') + ': ' + err.message));
}).finally(() => { }).finally(() => {
@@ -541,9 +606,11 @@ return baseclass.extend({
if(logSortingLocal) { if(logSortingLocal) {
this.logSortingValue = logSortingLocal; this.logSortingValue = logSortingLocal;
}; };
let autoRefreshLocal = localStorage.getItem(`luci-app-${this.viewName}-autoRefreshValue`); if(this.isAutorefresh) {
if(autoRefreshLocal) { let autoRefreshLocal = localStorage.getItem(`luci-app-${this.viewName}-autoRefreshValue`);
this.autoRefreshValue = Boolean(Number(autoRefreshLocal)); if(autoRefreshLocal) {
this.autoRefreshValue = Boolean(Number(autoRefreshLocal));
};
}; };
}, },
@@ -557,9 +624,11 @@ return baseclass.extend({
localStorage.setItem( localStorage.setItem(
`luci-app-${this.viewName}-logSortingValue`, logSortingValue); `luci-app-${this.viewName}-logSortingValue`, logSortingValue);
}; };
if(this.autoRefreshValue != autoRefreshValue) { if(this.isAutorefresh) {
localStorage.setItem( if(this.autoRefreshValue != autoRefreshValue) {
`luci-app-${this.viewName}-autoRefreshValue`, String(Number(autoRefreshValue))); localStorage.setItem(
`luci-app-${this.viewName}-autoRefreshValue`, String(Number(autoRefreshValue)));
};
}; };
}, },
@@ -578,7 +647,7 @@ return baseclass.extend({
this.setFacilityFilter( this.setFacilityFilter(
this.setLevelFilter( this.setLevelFilter(
this.setHostFilter( this.setHostFilter(
this.setDateFilter( this.setTimeFilter(
this.parseLogData(logdata, tail) this.parseLogData(logdata, tail)
) )
) )
@@ -598,13 +667,16 @@ return baseclass.extend({
this.logHostsDropdownElem = this.makeLogHostsDropdownSection(); this.logHostsDropdownElem = this.makeLogHostsDropdownSection();
}; };
}; };
if(!autorefresh) {
poll.start();
};
}).finally(() => { }).finally(() => {
if(modal) { if(modal) {
ui.hideModal(); ui.hideModal();
}; };
if(!autorefresh) { if(!autorefresh) {
this.enableFormElems(); this.enableFormElems();
poll.start();
}; };
}); });
}, },
@@ -619,16 +691,51 @@ return baseclass.extend({
'class': 'cbi-value-title', 'class': 'cbi-value-title',
'for' : 'tailInput', 'for' : 'tailInput',
}, _('Last entries')), }, _('Last entries')),
E('div', { 'class': 'cbi-value-field' }, E('div', { 'class': 'cbi-value-field' }, [
this.tailInput 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),
}, '&#9003;'),
]),
]), ]),
E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value' }, [
E('label', { E('label', {
'class': 'cbi-value-title', 'class': 'cbi-value-title',
'for' : 'timeFilter', 'for' : 'timeFilter',
}, _('Timestamp filter')), }, _('Timestamp filter')),
E('div', { 'class': 'cbi-value-field' }, this.timeFilter), 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),
}, '&#9003;'),
]),
]),
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')
),
]),
]), ]),
this.logHostsDropdownElem, this.logHostsDropdownElem,
this.logFacilitiesDropdownElem, this.logFacilitiesDropdownElem,
@@ -638,9 +745,34 @@ return baseclass.extend({
'class': 'cbi-value-title', 'class': 'cbi-value-title',
'for' : 'msgFilter', 'for' : 'msgFilter',
}, _('Message filter')), }, _('Message filter')),
E('div', { 'class': 'cbi-value-field' }, this.msgFilter), 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),
}, '&#9003;'),
]),
]),
E('div', { 'class': 'cbi-value' }, [
E('label', {
'class': 'cbi-value-title',
'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')
),
]),
]), ]),
E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value' }, [
E('label', { E('label', {
'class': 'cbi-value-title', 'class': 'cbi-value-title',
@@ -648,19 +780,19 @@ return baseclass.extend({
}, _('Sorting entries')), }, _('Sorting entries')),
E('div', { 'class': 'cbi-value-field' }, this.logSorting), E('div', { 'class': 'cbi-value-field' }, this.logSorting),
]), ]),
((this.isAutorefresh) ?
E('div', { 'class': 'cbi-value' }, [ E('div', { 'class': 'cbi-value' }, [
E('label', { E('label', {
'class': 'cbi-value-title', 'class': 'cbi-value-title',
'for' : 'autoRefresh', 'for' : 'autoRefresh',
}, _('Auto refresh')), }, _('Auto refresh')),
E('div', { 'class': 'cbi-value-field' }, E('div', { 'class': 'cbi-value-field' },
E('div', { 'class': 'cbi-checkbox' }, [ E('div', { 'class': 'cbi-checkbox' }, [
this.autoRefresh, this.autoRefresh,
E('label', {}) E('label', {}),
]) ])
), ),
]), ]) : ''),
]), ]),
]), ]),
]), ]),
@@ -670,8 +802,10 @@ return baseclass.extend({
'class': 'btn', 'class': 'btn',
'click': ev => { 'click': ev => {
ev.target.blur(); ev.target.blur();
ui.hideModal();
this.resetFormValues(); this.resetFormValues();
this.timeFilter.focus();
this.msgFilter.focus();
ui.hideModal();
}, },
}, _('Dismiss')), }, _('Dismiss')),
' ', ' ',
@@ -696,20 +830,27 @@ return baseclass.extend({
}, },
/** /**
* Creates a promise for the RPC request. * Creates a promise for the RPC request.
* Abstract method, must be overridden by a subclass! * Abstract method, must be overridden by a subclass!
* *
* @returns {Promise} * To completely disable the auto log refresh option, views extending
* Returns a promise that returns the size of the log in bytes. * this base class should overwrite the `getLogHash` function
*/ * with `null`.
getLogSize() { *
throw new Error('getLogSize must be overridden by a subclass'); * @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');
}, },
async pollFunc() { async pollFunc() {
await this.getLogSize().then(async bytes => { await this.getLogHash().then(async hash => {
if(this.lastBytes != bytes) { if(this.lastHash !== hash) {
this.lastBytes = bytes; this.lastHash = hash;
return await this.updateLog(true); return await this.updateLog(true);
}; };
}); });
@@ -725,6 +866,10 @@ return baseclass.extend({
load() { load() {
this.restoreSettingsFromLocalStorage(); this.restoreSettingsFromLocalStorage();
if(typeof(this.getLogHash) != 'function') {
this.isAutorefresh = false;
this.autoRefreshValue = false;
};
return this.getLogData(this.tailValue); return this.getLogData(this.tailValue);
}, },
@@ -769,18 +914,38 @@ return baseclass.extend({
'type' : 'text', 'type' : 'text',
'form' : 'logFilterForm', 'form' : 'logFilterForm',
'class' : 'cbi-input-text', 'class' : 'cbi-input-text',
'placeholder': _('Type an expression...'), 'placeholder': _('Type a search pattern...'),
}); });
this.timeFilterRe = E('input', {
'id' : 'timeFilterRe',
'name' : 'timeFilterRe',
'type' : 'checkbox',
'form' : 'logFilterForm',
'change': ev => this.timeFilter.focus(),
});
this.setRegexpValidator(this.timeFilter, this.timeFilterRe);
this.msgFilter = E('input', { this.msgFilter = E('input', {
'id' : 'msgFilter', 'id' : 'msgFilter',
'name' : 'msgFilter', 'name' : 'msgFilter',
'type' : 'text', 'type' : 'text',
'form' : 'logFilterForm', 'form' : 'logFilterForm',
'class' : 'cbi-input-text', 'class' : 'cbi-input-text',
'placeholder': _('Type an expression...'), 'placeholder': _('Type a search pattern...'),
}); });
this.msgFilterRe = E('input', {
'id' : 'msgFilterRe',
'name' : 'msgFilterRe',
'type' : 'checkbox',
'form' : 'logFilterForm',
'change': ev => this.msgFilter.focus(),
});
this.setRegexpValidator(this.msgFilter, this.msgFilterRe);
this.logSorting = E('select', { this.logSorting = E('select', {
'id' : 'logSorting', 'id' : 'logSorting',
'name' : 'logSorting', 'name' : 'logSorting',
@@ -823,7 +988,7 @@ return baseclass.extend({
this.refreshBtn = E('button', { this.refreshBtn = E('button', {
'title' : _('Refresh log'), 'title' : _('Refresh log'),
'class' : 'btn log-side-btn', 'class' : 'cbi-button btn log-side-btn',
'style' : `visibility:${(this.autoRefreshValue) ? 'hidden' : 'visible'}`, 'style' : `visibility:${(this.autoRefreshValue) ? 'hidden' : 'visible'}`,
'click' : ui.createHandlerFn(this, function(ev) { 'click' : ui.createHandlerFn(this, function(ev) {
ev.target.blur(); ev.target.blur();
@@ -833,7 +998,7 @@ return baseclass.extend({
this.moreEntriesBtn = E('button', { this.moreEntriesBtn = E('button', {
'title': _('Get more entries'), 'title': _('Get more entries'),
'class': 'btn log-side-btn', 'class': 'cbi-button btn log-side-btn',
'style': 'margin-top:1px !important', 'style': 'margin-top:1px !important',
'click': ui.createHandlerFn(this, function(ev) { 'click': ui.createHandlerFn(this, function(ev) {
ev.target.blur(); ev.target.blur();
@@ -849,7 +1014,7 @@ return baseclass.extend({
this.allEntriesBtn = E('button', { this.allEntriesBtn = E('button', {
'title': _('Get all entries'), 'title': _('Get all entries'),
'class': 'btn log-side-btn', 'class': 'cbi-button btn log-side-btn',
'style': 'margin-top:1px !important', 'style': 'margin-top:1px !important',
'click': ui.createHandlerFn(this, function(ev) { 'click': ui.createHandlerFn(this, function(ev) {
ev.target.blur(); ev.target.blur();
@@ -860,7 +1025,7 @@ return baseclass.extend({
this.filterModalBtn = E('button', { this.filterModalBtn = E('button', {
'title': _('Filter settings'), 'title': _('Filter settings'),
'class': 'btn log-side-btn', 'class': 'cbi-button btn log-side-btn',
'style': 'margin-top:10px !important', 'style': 'margin-top:10px !important',
'click': ev => { 'click': ev => {
ev.target.blur(); ev.target.blur();
@@ -883,7 +1048,7 @@ return baseclass.extend({
this.allEntriesBtn, this.allEntriesBtn,
this.filterModalBtn, this.filterModalBtn,
E('button', { E('button', {
'class': 'btn log-side-btn', 'class': 'cbi-button btn log-side-btn',
'style': 'margin-top:10px !important', 'style': 'margin-top:10px !important',
'click': ev => { 'click': ev => {
document.getElementById('logTitle').scrollIntoView(true); document.getElementById('logTitle').scrollIntoView(true);
@@ -891,7 +1056,7 @@ return baseclass.extend({
}, },
}, '&#8593;'), }, '&#8593;'),
E('button', { E('button', {
'class': 'btn log-side-btn', 'class': 'cbi-button btn log-side-btn',
'style': 'margin-top:1px !important', 'style': 'margin-top:1px !important',
'click': ev => { 'click': ev => {
this.logWrapper.scrollIntoView(false); this.logWrapper.scrollIntoView(false);
@@ -901,7 +1066,7 @@ return baseclass.extend({
]) ])
); );
if(this.autoRefreshValue) { if(this.isAutorefresh && this.autoRefreshValue) {
poll.add(this.pollFuncWrapper, this.pollInterval); poll.add(this.pollFuncWrapper, this.pollInterval);
}; };
@@ -38,7 +38,7 @@ document.head.append(E('style', {'type': 'text/css'},
return baseclass.extend({ return baseclass.extend({
view: abc.view.extend({ view: abc.view.extend({
regexpFilterHighlightFunc(match) { filterHighlightFunc(match) {
return `<span class="log-highlight-item">${match}</span>`; return `<span class="log-highlight-item">${match}</span>`;
}, },
@@ -15,23 +15,7 @@ return abc.view.extend({
entriesHandler : null, entriesHandler : null,
lastBytes : 0, getLogHash : null,
callLogSize: rpc.declare({
object: 'luci.ruantiblock',
method: 'getLogSize',
expect: { '': {} }
}),
getLogSize() {
return this.callLogSize().then((data) => {
if(data.bytes) {
return Number(data.bytes);
} else {
throw new Error(_('An error occurred while trying to get the log size!'));
};
});
},
// logd // logd
logdHandler(strArray, lineNum) { logdHandler(strArray, lineNum) {
@@ -62,23 +46,34 @@ return abc.view.extend({
]; ];
}, },
getLogData(tail) { checkLogread() {
return Promise.all([ return Promise.all([
L.resolveDefault(fs.stat('/sbin/logread'), null), L.resolveDefault(fs.stat('/sbin/logread'), null),
L.resolveDefault(fs.stat('/usr/sbin/logread'), null), L.resolveDefault(fs.stat('/usr/sbin/logread'), null),
]).then(stat => { ]).then(stat => {
let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null; let logger = (stat[0]) ? stat[0].path : (stat[1]) ? stat[1].path : null;
if(logger) { if(logger) {
return fs.exec_direct(logger, [ '-e', tools.appName + ':' ], 'text').catch(err => { this.logger = logger;
ui.addNotification( } else {
null, E('p', {}, _('Unable to load log data:') + ' ' + err.message)); throw new Error(_('Logread not found'));
return '';
});
}; };
}); });
}, },
async getLogData(tail, extraTstamp=false) {
if(!this.logger) {
await this.checkLogread();
};
let loggerArgs = [];
loggerArgs.push('-e', tools.appName + ':');
if(extraTstamp) {
loggerArgs.push('-t');
};
return fs.exec_direct(this.logger, loggerArgs, 'text').catch(err => {
throw new Error(_('Unable to load log data:') + ' ' + err.message);
});
},
parseLogData(logdata, tail) { parseLogData(logdata, tail) {
if(!logdata) { if(!logdata) {
return []; return [];
@@ -127,11 +122,7 @@ return abc.view.extend({
}); });
if(unsupportedLog) { if(unsupportedLog) {
ui.addNotification( throw new Error(_('Unable to load log data:') + ' ' + _('Unsupported log format'));
null,
E('p', {}, _('Unable to load log data:') + ' ' + _('Unsupported log format'))
);
return [];
} else { } else {
if(this.logSortingValue === 'desc') { if(this.logSortingValue === 'desc') {
entriesArray.reverse(); entriesArray.reverse();
@@ -263,6 +263,9 @@ msgstr "Записывать события в лог"
msgid "Logging levels" msgid "Logging levels"
msgstr "Уровни логирования" msgstr "Уровни логирования"
msgid "Logread not found"
msgstr "Logread не найден"
msgid "Main settings" msgid "Main settings"
msgstr "Основные настройки" msgstr "Основные настройки"
@@ -244,6 +244,9 @@ msgstr ""
msgid "Logging levels" msgid "Logging levels"
msgstr "" msgstr ""
msgid "Logread not found"
msgstr ""
msgid "Main settings" msgid "Main settings"
msgstr "" msgstr ""
@@ -1,34 +0,0 @@
#!/bin/sh
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
readonly LOGREAD_CMD="logread -e ruantiblock:"
make_size_value() {
json_init
json_add_string 'bytes' "$1"
json_dump
json_cleanup
}
get_log_size() {
make_size_value "`$LOGREAD_CMD | wc -c`"
}
case "$1" in
list)
json_init
json_add_object "getLogSize"
json_close_object
json_dump
json_cleanup
;;
call)
case "$2" in
getLogSize)
get_log_size
;;
esac
;;
esac
@@ -18,8 +18,7 @@
}, },
"uci": [ "network", "ruantiblock" ], "uci": [ "network", "ruantiblock" ],
"ubus": { "ubus": {
"luci": [ "getInitList", "setInitAction" ], "luci": [ "getInitList", "setInitAction" ]
"luci.ruantiblock": [ "getLogSize" ]
} }
}, },
"write": { "write": {