Notice 조건과 원격 로그 필터 보강
This commit is contained in:
+93
-4
@@ -61,6 +61,7 @@
|
||||
dmesgOutput: $('#dmesgOutput'),
|
||||
dmesgMeta: $('#dmesgMeta'),
|
||||
synologyLogToggle: $('#synologyLogToggle'),
|
||||
synologyLogFilters: $('#synologyLogFilters'),
|
||||
synologyLogOutput: $('#synologyLogOutput'),
|
||||
synologyLogMeta: $('#synologyLogMeta'),
|
||||
processDetails: $('#processDetails'),
|
||||
@@ -86,6 +87,8 @@
|
||||
synologyLogTimer: null,
|
||||
synologyLogLatestKey: null,
|
||||
synologyLogScrollHoldUntil: 0,
|
||||
synologyLogFilter: 'all',
|
||||
synologyLogData: null,
|
||||
ws: null,
|
||||
wsConnected: false,
|
||||
wsFallbackTimer: null,
|
||||
@@ -225,6 +228,14 @@
|
||||
remoteFiles: 'Files',
|
||||
remoteUsage: 'Usage',
|
||||
remoteBoots: 'Boots',
|
||||
logFilterAll: 'All',
|
||||
logFilterImportant: 'Important',
|
||||
logFilterError: 'Error',
|
||||
logFilterFailed: 'Failed',
|
||||
logFilterBlocked: 'Blocked',
|
||||
logFilterConnection: 'Connection',
|
||||
logFilterSystem: 'System',
|
||||
logFilterNoLines: 'No log lines match this filter.',
|
||||
remoteSaved: 'Saved',
|
||||
remotePending: 'Pending',
|
||||
serviceLogs: 'Logs',
|
||||
@@ -448,6 +459,14 @@
|
||||
remoteFiles: '파일',
|
||||
remoteUsage: '사용량',
|
||||
remoteBoots: '부팅 이력',
|
||||
logFilterAll: '전체',
|
||||
logFilterImportant: '중요',
|
||||
logFilterError: '오류',
|
||||
logFilterFailed: '실패',
|
||||
logFilterBlocked: '차단',
|
||||
logFilterConnection: '연결',
|
||||
logFilterSystem: '시스템',
|
||||
logFilterNoLines: '필터에 맞는 로그가 없습니다.',
|
||||
remoteSaved: '저장',
|
||||
remotePending: '대기',
|
||||
serviceLogs: '로그',
|
||||
@@ -599,6 +618,7 @@
|
||||
if (els.synologyLogToggle) {
|
||||
els.synologyLogToggle.textContent = state.synologyLogOpen ? t('hide') : t('show');
|
||||
}
|
||||
updateSynologyLogFilters();
|
||||
}
|
||||
|
||||
function initPreferences() {
|
||||
@@ -2048,7 +2068,15 @@
|
||||
if (Math.abs(m.tempDelta) >= tempThreshold) reasons.push(t(m.tempDelta >= 0 ? 'tempHigher' : 'tempLower'));
|
||||
if (Math.abs(m.rpmDelta) >= rpmThreshold) reasons.push(t(m.rpmDelta >= 0 ? 'rpmHigher' : 'rpmLower'));
|
||||
|
||||
return `${t('recordedReason')}: ${reasons.length ? reasons.join(', ') : t('instantChange')}`;
|
||||
if (reasons.length) {
|
||||
return `${t('recordedReason')}: ${reasons.join(', ')}`;
|
||||
}
|
||||
|
||||
const summary = String(row.summary || '')
|
||||
.replace(/^System notice(?: active)?:\s*/i, '')
|
||||
.trim();
|
||||
|
||||
return `${t('recordedReason')}: ${summary || t('instantChange')}`;
|
||||
}
|
||||
|
||||
function noticePreviousText(row) {
|
||||
@@ -2878,11 +2906,56 @@
|
||||
els.synologyLogOutput.scrollTop = 0;
|
||||
}
|
||||
|
||||
function synologyLogFilterLabel(filter = state.synologyLogFilter) {
|
||||
const keys = {
|
||||
all: 'logFilterAll',
|
||||
important: 'logFilterImportant',
|
||||
error: 'logFilterError',
|
||||
failed: 'logFilterFailed',
|
||||
blocked: 'logFilterBlocked',
|
||||
connection: 'logFilterConnection',
|
||||
system: 'logFilterSystem',
|
||||
};
|
||||
|
||||
return t(keys[filter] || keys.important);
|
||||
}
|
||||
|
||||
function updateSynologyLogFilters() {
|
||||
if (!els.synologyLogFilters) return;
|
||||
|
||||
els.synologyLogFilters.querySelectorAll('[data-log-filter]').forEach(button => {
|
||||
const key = button.dataset.logFilter || 'all';
|
||||
button.textContent = synologyLogFilterLabel(key);
|
||||
button.dataset.active = key === state.synologyLogFilter ? '1' : '0';
|
||||
});
|
||||
}
|
||||
|
||||
function synologyLogLineMatches(line, filter) {
|
||||
if (filter === 'all') return true;
|
||||
|
||||
const value = String(line || '').toLowerCase();
|
||||
const patterns = {
|
||||
important: /(error|err|fail|failed|failure|denied|blocked|drop|reject|disconnect|timeout|oom|panic|critical|warn|warning|throttl|undervoltage)/i,
|
||||
error: /(error|err|exception|critical|panic|oom)/i,
|
||||
failed: /(fail|failed|failure|timeout|unreachable|cannot|could not)/i,
|
||||
blocked: /(blocked|denied|reject|drop|ban|iptables|nft|firewall)/i,
|
||||
connection: /(connect|disconnect|connection|ssh|tls|handshake|listen|socket)/i,
|
||||
system: /(systemd|kernel|docker|nginx|mariadb|rsyslog|syslog|journal)/i,
|
||||
};
|
||||
|
||||
return (patterns[filter] || patterns.important).test(value);
|
||||
}
|
||||
|
||||
function filteredSynologyLogLines(lines) {
|
||||
return (lines || []).filter(line => synologyLogLineMatches(line, state.synologyLogFilter));
|
||||
}
|
||||
|
||||
function renderSynologyLog(data) {
|
||||
if (!els.synologyLogOutput || !els.synologyLogMeta) return;
|
||||
if (Date.now() < state.synologyLogScrollHoldUntil) return;
|
||||
|
||||
const scrollTop = els.synologyLogOutput.scrollTop;
|
||||
state.synologyLogData = data || null;
|
||||
|
||||
if (!data?.available) {
|
||||
els.synologyLogOutput.textContent = data?.message || t('synologyLogUnavailable');
|
||||
@@ -2890,12 +2963,13 @@
|
||||
return;
|
||||
}
|
||||
|
||||
const lines = data.lines || [];
|
||||
const rawLines = data.lines || [];
|
||||
const lines = filteredSynologyLogLines(rawLines);
|
||||
const latestKey = `${data.line_count || 0}\n${lines[0] || ''}`;
|
||||
const hasNewLine = state.synologyLogLatestKey !== null && latestKey !== state.synologyLogLatestKey;
|
||||
|
||||
els.synologyLogOutput.textContent = lines.join('\n');
|
||||
els.synologyLogMeta.textContent = `${data.path || '/var/log/remote/synology/chaegeon.log'} · ${data.line_count || 0} lines · updated ${data.updated_at || '-'}`;
|
||||
els.synologyLogOutput.textContent = lines.length ? lines.join('\n') : t('logFilterNoLines');
|
||||
els.synologyLogMeta.textContent = `${data.path || '/var/log/remote/synology/chaegeon.log'} · ${lines.length} / ${data.line_count || 0} lines · ${synologyLogFilterLabel()} · updated ${data.updated_at || '-'}`;
|
||||
state.synologyLogLatestKey = latestKey;
|
||||
els.synologyLogOutput.scrollTop = Date.now() < state.synologyLogScrollHoldUntil ? scrollTop : 0;
|
||||
|
||||
@@ -2934,9 +3008,13 @@
|
||||
if (els.synologyLogOutput) {
|
||||
els.synologyLogOutput.hidden = !open;
|
||||
}
|
||||
if (els.synologyLogFilters) {
|
||||
els.synologyLogFilters.hidden = !open;
|
||||
}
|
||||
if (els.synologyLogToggle) {
|
||||
els.synologyLogToggle.textContent = open ? t('hide') : t('show');
|
||||
}
|
||||
updateSynologyLogFilters();
|
||||
|
||||
stopSynologyLogFallback();
|
||||
if (open) {
|
||||
@@ -3094,6 +3172,17 @@
|
||||
els.synologyLogToggle?.addEventListener('click', () => {
|
||||
setSynologyLogOpen(!state.synologyLogOpen);
|
||||
});
|
||||
els.synologyLogFilters?.addEventListener('click', event => {
|
||||
const button = event.target?.closest?.('[data-log-filter]');
|
||||
if (!button) return;
|
||||
|
||||
state.synologyLogFilter = button.dataset.logFilter || 'all';
|
||||
state.synologyLogScrollHoldUntil = 0;
|
||||
updateSynologyLogFilters();
|
||||
if (state.synologyLogData) {
|
||||
renderSynologyLog(state.synologyLogData);
|
||||
}
|
||||
});
|
||||
const holdSynologyLogScroll = () => {
|
||||
state.synologyLogScrollHoldUntil = Date.now() + 4000;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user