원격 로그 상태 진단 추가
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
statusBatteryRemaining: $('#statusBatteryRemaining'),
|
||||
batteryRuntimeTooltip: $('#batteryRuntimeTooltip'),
|
||||
spikeLogList: $('#spikeLogList'),
|
||||
remoteLogList: $('#remoteLogList'),
|
||||
customServiceList: $('#customServiceList'),
|
||||
noticeBaseline: $('#noticeBaseline'),
|
||||
rebootBtn: $('#rebootBtn'),
|
||||
@@ -179,6 +180,24 @@
|
||||
noNoticeHistory: 'No system notice history.',
|
||||
customServices: 'Custom Services',
|
||||
noCustomServices: 'No custom services.',
|
||||
remoteLogs: 'Remote Logs',
|
||||
remoteLogsLoading: 'Remote log status loading...',
|
||||
remotePiToSynology: 'Raspberry -> Synology',
|
||||
remoteSynologyToPi: 'Synology -> Raspberry',
|
||||
remotePersistentJournal: 'Persistent Journal',
|
||||
remoteCrashLogs: 'Crash Logs',
|
||||
remoteOk: 'OK',
|
||||
remoteWarn: 'Check',
|
||||
remoteTarget: 'Target',
|
||||
remoteTransport: 'Transport',
|
||||
remoteQueue: 'Queue',
|
||||
remoteListener: 'Listener',
|
||||
remoteLatest: 'Latest',
|
||||
remoteFiles: 'Files',
|
||||
remoteUsage: 'Usage',
|
||||
remoteBoots: 'Boots',
|
||||
remoteSaved: 'Saved',
|
||||
remotePending: 'Pending',
|
||||
serviceLogs: 'Logs',
|
||||
serviceEnabled: 'enabled',
|
||||
servicePid: 'pid',
|
||||
@@ -353,6 +372,24 @@
|
||||
noNoticeHistory: '시스템 알림 이력이 없습니다.',
|
||||
customServices: '사용자 서비스',
|
||||
noCustomServices: '사용자 생성 서비스가 없습니다.',
|
||||
remoteLogs: '원격 로그',
|
||||
remoteLogsLoading: '원격 로그 상태 확인 중...',
|
||||
remotePiToSynology: '라즈베리파이 -> 시놀로지',
|
||||
remoteSynologyToPi: '시놀로지 -> 라즈베리파이',
|
||||
remotePersistentJournal: '영구 저널',
|
||||
remoteCrashLogs: '커널 크래시',
|
||||
remoteOk: '정상',
|
||||
remoteWarn: '확인',
|
||||
remoteTarget: '대상',
|
||||
remoteTransport: '전송',
|
||||
remoteQueue: '대기열',
|
||||
remoteListener: '수신',
|
||||
remoteLatest: '최근',
|
||||
remoteFiles: '파일',
|
||||
remoteUsage: '사용량',
|
||||
remoteBoots: '부팅 이력',
|
||||
remoteSaved: '저장',
|
||||
remotePending: '대기',
|
||||
serviceLogs: '로그',
|
||||
serviceEnabled: '활성화',
|
||||
servicePid: 'PID',
|
||||
@@ -1957,6 +1994,106 @@
|
||||
: `<div class="spike-log-empty">${escapeHtml(t('noNoticeHistory'))}</div>`;
|
||||
}
|
||||
|
||||
function remoteState(ok, warn = false) {
|
||||
if (ok) {
|
||||
return {
|
||||
className: 'active',
|
||||
label: t('remoteOk'),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
className: warn ? 'warning' : 'failed',
|
||||
label: t('remoteWarn'),
|
||||
};
|
||||
}
|
||||
|
||||
function remoteMeta(items) {
|
||||
return items
|
||||
.filter(item => item.value !== null && item.value !== undefined && item.value !== '')
|
||||
.map(item => `${item.label}: ${item.value}`)
|
||||
.join(' · ') || '-';
|
||||
}
|
||||
|
||||
function remoteAge(row) {
|
||||
if (!row || row.age_seconds === null || row.age_seconds === undefined) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
const formatted = formatDhms(Number(row.age_seconds));
|
||||
return formatted ? `${formatted} ${t('ago')}` : '-';
|
||||
}
|
||||
|
||||
function renderRemoteLogs(data = {}) {
|
||||
if (!els.remoteLogList) return;
|
||||
|
||||
const piToSynology = data.raspberry_to_synology || {};
|
||||
const synologyToPi = data.synology_to_raspberry || {};
|
||||
const journal = data.journal || {};
|
||||
const pstore = data.pstore || {};
|
||||
const newest = synologyToPi.logs?.newest || null;
|
||||
const queue = piToSynology.queue || {};
|
||||
const rows = [
|
||||
{
|
||||
title: t('remotePiToSynology'),
|
||||
desc: remoteMeta([
|
||||
{ label: t('remoteTarget'), value: piToSynology.target || '-' },
|
||||
{ label: t('remoteTransport'), value: piToSynology.transport || '-' },
|
||||
]),
|
||||
meta: remoteMeta([
|
||||
{ label: 'rsyslog', value: `${piToSynology.rsyslog_active || '-'} / ${piToSynology.rsyslog_enabled || '-'}` },
|
||||
{ label: t('remoteQueue'), value: queue.available === false ? '-' : `${Number(queue.file_count || 0).toLocaleString()} / ${queue.total_size || '-'}` },
|
||||
]),
|
||||
state: remoteState(Boolean(piToSynology.ok), true),
|
||||
},
|
||||
{
|
||||
title: t('remoteSynologyToPi'),
|
||||
desc: remoteMeta([
|
||||
{ label: t('remoteListener'), value: synologyToPi.listener ? `:${synologyToPi.listen_port || 6514}` : '-' },
|
||||
{ label: t('remoteTransport'), value: synologyToPi.transport || '-' },
|
||||
]),
|
||||
meta: remoteMeta([
|
||||
{ label: t('remoteLatest'), value: newest ? `${newest.name || '-'} / ${remoteAge(newest)}` : '-' },
|
||||
{ label: t('remoteFiles'), value: `${Number(synologyToPi.logs?.file_count || 0).toLocaleString()} / ${synologyToPi.logs?.total_size || '-'}` },
|
||||
]),
|
||||
state: remoteState(Boolean(synologyToPi.ok), true),
|
||||
},
|
||||
{
|
||||
title: t('remotePersistentJournal'),
|
||||
desc: journal.path || '-',
|
||||
meta: remoteMeta([
|
||||
{ label: t('remoteUsage'), value: journal.disk_usage || '-' },
|
||||
{ label: t('remoteBoots'), value: journal.boot_count === null || journal.boot_count === undefined ? '-' : Number(journal.boot_count).toLocaleString() },
|
||||
]),
|
||||
state: remoteState(Boolean(journal.ok), true),
|
||||
},
|
||||
{
|
||||
title: t('remoteCrashLogs'),
|
||||
desc: pstore.saved_path || '-',
|
||||
meta: remoteMeta([
|
||||
{ label: 'pstore', value: pstore.mounted ? 'mounted' : '-' },
|
||||
{ label: 'collector', value: pstore.collector_active || '-' },
|
||||
{ label: t('remoteSaved'), value: Number(pstore.saved_files || 0).toLocaleString() },
|
||||
{ label: t('remotePending'), value: Number(pstore.pending_files || 0).toLocaleString() },
|
||||
]),
|
||||
state: remoteState(Boolean(pstore.ok), true),
|
||||
},
|
||||
];
|
||||
|
||||
els.remoteLogList.innerHTML = rows.map(row => `
|
||||
<div class="service-item">
|
||||
<div class="service-head">
|
||||
<div class="service-title">
|
||||
<div class="service-name">${escapeHtml(row.title)}</div>
|
||||
<div class="service-desc">${escapeHtml(row.desc)}</div>
|
||||
</div>
|
||||
<div class="service-state ${row.state.className}">${escapeHtml(row.state.label)}</div>
|
||||
</div>
|
||||
<div class="service-meta">${escapeHtml(row.meta)}</div>
|
||||
</div>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function renderCustomServices(rows = []) {
|
||||
if (!els.customServiceList) return;
|
||||
if (Date.now() < state.customServiceScrollHoldUntil) return;
|
||||
@@ -2011,6 +2148,7 @@
|
||||
? `${baselineTemp.toFixed(1)}°C / ${Math.round(baselineRpm).toLocaleString()} RPM · ${stateText}`
|
||||
: stateText;
|
||||
renderSpikeHistory(data.fan_spike_history || []);
|
||||
renderRemoteLogs(data.remote_logs || {});
|
||||
renderCustomServices(data.custom_services || []);
|
||||
setText(els.noticeBaseline, baselineText);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user