Notice 조건과 원격 로그 필터 보강

This commit is contained in:
seo
2026-07-26 01:36:07 +09:00
parent 58a81420d1
commit a42b6d7df7
5 changed files with 191 additions and 10 deletions
+93 -4
View File
@@ -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;
};