원격 syslog 기능 제거
This commit is contained in:
1 parent
95a4750137
commit
c0dadcc8a9
5 files changed
+4
-482
No files matched your search
-173
@@ -177,76 +177,6 @@ function text_log_tail(string $path, string $label, int $limit = 500, ?callable
|
||||
];
|
||||
}
|
||||
|
||||
function synology_remote_log_visible(string $line): bool
|
||||
{
|
||||
if (str_contains($line, 'Last message ') && str_contains($line, 'suppressed by syslog-ng')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/\ssynotifyd\[\d+\]\s/', $line)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (preg_match('/\ssynoelasticd\[\d+\]\s/', $line)) {
|
||||
$noise = [
|
||||
'(UpsertByID)',
|
||||
'(SetByID)',
|
||||
'(DelByID)',
|
||||
'(DelByQuery)',
|
||||
'(Commit) Commit: fileindex_',
|
||||
];
|
||||
foreach ($noise as $needle) {
|
||||
if (str_contains($line, $needle)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/\sfileindexd\[\d+\]\s/', $line)) {
|
||||
$noise = [
|
||||
'ProcessOP BEGIN: IndexUpsert',
|
||||
'ProcessOP DONE!: IndexUpsert',
|
||||
'ProcessOP SKIPPED: IndexUpsert',
|
||||
'ProcessOP BEGIN: IndexReindex',
|
||||
'ProcessOP DONE!: IndexReindex',
|
||||
'ProcessOP SKIPPED: IndexReindex',
|
||||
'(Process) Worker<',
|
||||
'PrepareTmpOPtree',
|
||||
'CheckClearOldTmpOPtree',
|
||||
'BuildTree',
|
||||
'Commit [fileindex_',
|
||||
];
|
||||
foreach ($noise as $needle) {
|
||||
if (str_contains($line, $needle)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('/\sscemd\[\d+\]\s/', $line)) {
|
||||
$noise = [
|
||||
'Could not open file `/dev/i2c-1',
|
||||
'Could not open file `/dev/i2c/1',
|
||||
'Fail to initLedBrightnessConfig',
|
||||
'No brightness setting',
|
||||
'Fail to init config list',
|
||||
'Fail to set led brightness.',
|
||||
];
|
||||
foreach ($noise as $needle) {
|
||||
if (str_contains($line, $needle)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function synology_remote_log(): array
|
||||
{
|
||||
return text_log_tail('/var/log/remote/synology/chaegeon.log', 'synology remote', 5000, 'synology_remote_log_visible');
|
||||
}
|
||||
|
||||
function command_first_line(array $cmd, bool $root = false, int $timeout = 3): string
|
||||
{
|
||||
$result = sh($cmd, $root, $timeout);
|
||||
@@ -258,112 +188,16 @@ function command_first_line(array $cmd, bool $root = false, int $timeout = 3): s
|
||||
return (int)$result['code'] === 0 && $lines ? (string)$lines[0] : '';
|
||||
}
|
||||
|
||||
function remote_log_file_status(string $dir): array
|
||||
{
|
||||
$files = [];
|
||||
$totalBytes = 0;
|
||||
$newest = null;
|
||||
|
||||
foreach (glob(rtrim($dir, '/') . '/*.log') ?: [] as $path) {
|
||||
$size = filesize($path) ?: 0;
|
||||
$mtime = filemtime($path) ?: 0;
|
||||
$totalBytes += $size;
|
||||
|
||||
$row = [
|
||||
'name' => basename($path),
|
||||
'path' => $path,
|
||||
'size_bytes' => $size,
|
||||
'size' => bytes_human($size),
|
||||
'updated_at' => $mtime > 0 ? date('Y-m-d H:i:s', $mtime) : null,
|
||||
'age_seconds' => $mtime > 0 ? max(0, time() - $mtime) : null,
|
||||
];
|
||||
$files[] = $row;
|
||||
|
||||
if ($newest === null || (int)$row['age_seconds'] < (int)($newest['age_seconds'] ?? PHP_INT_MAX)) {
|
||||
$newest = $row;
|
||||
}
|
||||
}
|
||||
|
||||
usort($files, static fn($a, $b): int => (int)($a['age_seconds'] ?? PHP_INT_MAX) <=> (int)($b['age_seconds'] ?? PHP_INT_MAX));
|
||||
|
||||
return [
|
||||
'path' => $dir,
|
||||
'available' => is_dir($dir),
|
||||
'file_count' => count($files),
|
||||
'total_bytes' => $totalBytes,
|
||||
'total_size' => bytes_human($totalBytes),
|
||||
'newest' => $newest,
|
||||
'files' => array_slice($files, 0, 5),
|
||||
];
|
||||
}
|
||||
|
||||
function remote_log_queue_status(): array
|
||||
{
|
||||
$result = sh([
|
||||
'/usr/bin/find',
|
||||
'/var/spool/rsyslog',
|
||||
'-maxdepth',
|
||||
'1',
|
||||
'-name',
|
||||
'control_synology_fwd*',
|
||||
'-printf',
|
||||
'%s\n',
|
||||
], true, 3);
|
||||
|
||||
if ((int)$result['code'] !== 0) {
|
||||
return [
|
||||
'available' => false,
|
||||
'file_count' => null,
|
||||
'total_bytes' => null,
|
||||
'total_size' => '-',
|
||||
];
|
||||
}
|
||||
|
||||
$sizes = array_values(array_filter(
|
||||
array_map('trim', preg_split('/\R/', trim((string)$result['out'])) ?: []),
|
||||
static fn($line): bool => $line !== ''
|
||||
));
|
||||
$total = array_sum(array_map('intval', $sizes));
|
||||
|
||||
return [
|
||||
'available' => true,
|
||||
'file_count' => count($sizes),
|
||||
'total_bytes' => $total,
|
||||
'total_size' => bytes_human($total),
|
||||
];
|
||||
}
|
||||
|
||||
function remote_log_status(): array
|
||||
{
|
||||
$journalDir = '/var/log/journal';
|
||||
$journalDisk = command_first_line(['/usr/bin/journalctl', '--disk-usage', '--no-pager'], false, 3);
|
||||
$journalBoots = command_first_line(['/usr/bin/bash', '-lc', 'journalctl --list-boots --no-pager 2>/dev/null | wc -l'], false, 3);
|
||||
$rsyslogActive = command_first_line(['/usr/bin/systemctl', 'is-active', 'rsyslog'], false, 3) ?: 'unknown';
|
||||
$rsyslogEnabled = command_first_line(['/usr/bin/systemctl', 'is-enabled', 'rsyslog'], false, 3) ?: 'unknown';
|
||||
$pstoreActive = command_first_line(['/usr/bin/systemctl', 'is-active', 'control-pstore-collect.service'], false, 3) ?: 'inactive';
|
||||
$listener = sh(['/usr/bin/ss', '-lnt', 'sport', '=', ':6514'], false, 3);
|
||||
$listenerOk = (int)$listener['code'] === 0 && str_contains((string)$listener['out'], ':6514');
|
||||
$remoteFiles = remote_log_file_status('/var/log/remote/synology');
|
||||
$queue = remote_log_queue_status();
|
||||
$savedCrashFiles = glob('/var/log/pstore/*') ?: [];
|
||||
$pstoreFiles = glob('/sys/fs/pstore/*') ?: [];
|
||||
|
||||
return [
|
||||
'raspberry_to_synology' => [
|
||||
'target' => 'chaegeon.com:6514',
|
||||
'transport' => 'TCP/TLS',
|
||||
'rsyslog_active' => $rsyslogActive,
|
||||
'rsyslog_enabled' => $rsyslogEnabled,
|
||||
'queue' => $queue,
|
||||
'ok' => $rsyslogActive === 'active',
|
||||
],
|
||||
'synology_to_raspberry' => [
|
||||
'listen_port' => 6514,
|
||||
'transport' => 'TCP/TLS',
|
||||
'listener' => $listenerOk,
|
||||
'logs' => $remoteFiles,
|
||||
'ok' => $listenerOk && $remoteFiles['file_count'] > 0,
|
||||
],
|
||||
'journal' => [
|
||||
'path' => $journalDir,
|
||||
'persistent' => is_dir($journalDir),
|
||||
@@ -4877,13 +4711,6 @@ function control_api_dispatch(): void
|
||||
]);
|
||||
}
|
||||
|
||||
if ($action === 'synology_log') {
|
||||
json_out([
|
||||
'ok' => true,
|
||||
'data' => synology_remote_log(),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($action === 'status') {
|
||||
json_out([
|
||||
'ok' => true,
|
||||
|
||||
@@ -60,10 +60,6 @@
|
||||
dmesgToggle: $('#dmesgToggle'),
|
||||
dmesgOutput: $('#dmesgOutput'),
|
||||
dmesgMeta: $('#dmesgMeta'),
|
||||
synologyLogToggle: $('#synologyLogToggle'),
|
||||
synologyLogFilters: $('#synologyLogFilters'),
|
||||
synologyLogOutput: $('#synologyLogOutput'),
|
||||
synologyLogMeta: $('#synologyLogMeta'),
|
||||
processDetails: $('#processDetails'),
|
||||
diagnosticDetails: $('#diagnosticDetails'),
|
||||
};
|
||||
@@ -83,12 +79,6 @@
|
||||
dmesgOpen: false,
|
||||
dmesgTimer: null,
|
||||
dmesgLatestKey: null,
|
||||
synologyLogOpen: false,
|
||||
synologyLogTimer: null,
|
||||
synologyLogLatestKey: null,
|
||||
synologyLogScrollHoldUntil: 0,
|
||||
synologyLogFilter: 'all',
|
||||
synologyLogData: null,
|
||||
ws: null,
|
||||
wsConnected: false,
|
||||
wsFallbackTimer: null,
|
||||
@@ -331,9 +321,6 @@
|
||||
fanUpdateFailed: 'fan update failed',
|
||||
dmesgUnavailable: 'dmesg log is not available yet.',
|
||||
dmesgRefreshFailed: 'dmesg refresh failed',
|
||||
synologyLog: 'Synology Log',
|
||||
synologyLogUnavailable: 'Synology log is not available yet.',
|
||||
synologyLogRefreshFailed: 'Synology log refresh failed',
|
||||
rebootPrompt: 'Type reboot below to continue.',
|
||||
rebootPhrase: 'reboot',
|
||||
rebootTitle: 'System Reboot',
|
||||
@@ -566,9 +553,6 @@
|
||||
fanUpdateFailed: '팬 갱신 실패',
|
||||
dmesgUnavailable: 'dmesg 로그를 아직 사용할 수 없습니다.',
|
||||
dmesgRefreshFailed: 'dmesg 갱신 실패',
|
||||
synologyLog: '시놀로지 로그',
|
||||
synologyLogUnavailable: '시놀로지 로그를 아직 사용할 수 없습니다.',
|
||||
synologyLogRefreshFailed: '시놀로지 로그 갱신 실패',
|
||||
rebootPrompt: '재부팅을 계속하려면 아래에 재부팅을 입력하세요.',
|
||||
rebootPhrase: '재부팅',
|
||||
rebootTitle: '시스템 재부팅',
|
||||
@@ -623,10 +607,6 @@
|
||||
if (els.dmesgToggle) {
|
||||
els.dmesgToggle.textContent = state.dmesgOpen ? t('hide') : t('show');
|
||||
}
|
||||
if (els.synologyLogToggle) {
|
||||
els.synologyLogToggle.textContent = state.synologyLogOpen ? t('hide') : t('show');
|
||||
}
|
||||
updateSynologyLogFilters();
|
||||
}
|
||||
|
||||
function initPreferences() {
|
||||
@@ -1263,10 +1243,6 @@
|
||||
stopDmesgFallback();
|
||||
sendWs({ type: 'dmesg', open: true });
|
||||
}
|
||||
if (state.synologyLogOpen) {
|
||||
stopSynologyLogFallback();
|
||||
sendWs({ type: 'synology_log', open: true });
|
||||
}
|
||||
});
|
||||
|
||||
state.ws.addEventListener('message', event => {
|
||||
@@ -1288,11 +1264,6 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if (message?.type === 'synology_log') {
|
||||
renderSynologyLog(message.data || {});
|
||||
return;
|
||||
}
|
||||
|
||||
if (message?.type === 'error') {
|
||||
console.error(message.message || 'websocket error');
|
||||
}
|
||||
@@ -1304,9 +1275,6 @@
|
||||
if (state.dmesgOpen) {
|
||||
startDmesgFallback();
|
||||
}
|
||||
if (state.synologyLogOpen) {
|
||||
startSynologyLogFallback();
|
||||
}
|
||||
const delay = state.wsReconnectDelay;
|
||||
state.wsReconnectDelay = Math.min(15000, state.wsReconnectDelay * 1.7);
|
||||
state.wsReconnectTimer = setTimeout(connectControlSocket, delay);
|
||||
@@ -2139,49 +2107,12 @@
|
||||
.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 || '-',
|
||||
@@ -2961,134 +2892,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
function scrollSynologyLogToTop() {
|
||||
if (!els.synologyLogOutput) return;
|
||||
if (els.synologyLogOutput.hidden) return;
|
||||
if (Date.now() < state.synologyLogScrollHoldUntil) return;
|
||||
|
||||
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');
|
||||
els.synologyLogMeta.textContent = '/var/log/remote/synology/chaegeon.log unavailable';
|
||||
return;
|
||||
}
|
||||
|
||||
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.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;
|
||||
|
||||
if (hasNewLine) {
|
||||
requestAnimationFrame(scrollSynologyLogToTop);
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshSynologyLog() {
|
||||
if (!state.synologyLogOpen) return;
|
||||
|
||||
try {
|
||||
renderSynologyLog(await api('synology_log'));
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (els.synologyLogOutput) {
|
||||
els.synologyLogOutput.textContent = e.message || t('synologyLogRefreshFailed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function stopSynologyLogFallback() {
|
||||
clearInterval(state.synologyLogTimer);
|
||||
state.synologyLogTimer = null;
|
||||
}
|
||||
|
||||
function startSynologyLogFallback() {
|
||||
if (state.synologyLogTimer) return;
|
||||
|
||||
refreshSynologyLog();
|
||||
state.synologyLogTimer = setInterval(refreshSynologyLog, 1000);
|
||||
}
|
||||
|
||||
function setSynologyLogOpen(open) {
|
||||
state.synologyLogOpen = open;
|
||||
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) {
|
||||
if (!sendWs({ type: 'synology_log', open: true })) {
|
||||
startSynologyLogFallback();
|
||||
}
|
||||
} else {
|
||||
sendWs({ type: 'synology_log', open: false });
|
||||
}
|
||||
}
|
||||
|
||||
async function refreshStatus() {
|
||||
if (state.loading) return;
|
||||
state.loading = true;
|
||||
@@ -3232,26 +3035,6 @@
|
||||
els.dmesgToggle?.addEventListener('click', () => {
|
||||
setDmesgOpen(!state.dmesgOpen);
|
||||
});
|
||||
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;
|
||||
};
|
||||
['scroll', 'wheel', 'touchstart', 'touchmove', 'pointerdown'].forEach(eventName => {
|
||||
els.synologyLogOutput?.addEventListener(eventName, holdSynologyLogScroll, { passive: true });
|
||||
});
|
||||
const holdCustomServiceScroll = () => {
|
||||
state.customServiceScrollHoldUntil = Date.now() + 4000;
|
||||
};
|
||||
@@ -3331,9 +3114,6 @@
|
||||
if (state.dmesgOpen && !sendWs({ type: 'dmesg', open: true })) {
|
||||
refreshDmesg();
|
||||
}
|
||||
if (state.synologyLogOpen && !sendWs({ type: 'synology_log', open: true })) {
|
||||
refreshSynologyLog();
|
||||
}
|
||||
}
|
||||
});
|
||||
document.addEventListener('keydown', event => {
|
||||
|
||||
@@ -384,24 +384,6 @@ html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="spike-log-box">
|
||||
<div class="dmesg-head">
|
||||
<h3 data-i18n="synologyLog">Synology Log</h3>
|
||||
<button class="btn secondary" id="synologyLogToggle" type="button" data-i18n="show">Show</button>
|
||||
</div>
|
||||
<div class="log-filter-bar" id="synologyLogFilters" hidden>
|
||||
<button class="btn secondary log-filter" type="button" data-log-filter="all" data-active="1">All</button>
|
||||
<button class="btn secondary log-filter" type="button" data-log-filter="important">Important</button>
|
||||
<button class="btn secondary log-filter" type="button" data-log-filter="error">Error</button>
|
||||
<button class="btn secondary log-filter" type="button" data-log-filter="failed">Failed</button>
|
||||
<button class="btn secondary log-filter" type="button" data-log-filter="blocked">Blocked</button>
|
||||
<button class="btn secondary log-filter" type="button" data-log-filter="connection">Connection</button>
|
||||
<button class="btn secondary log-filter" type="button" data-log-filter="system">System</button>
|
||||
</div>
|
||||
<div class="dmesg-meta" id="synologyLogMeta">/var/log/remote/synology/chaegeon.log</div>
|
||||
<pre class="dmesg-log" id="synologyLogOutput" hidden></pre>
|
||||
</div>
|
||||
|
||||
<div class="spike-log-box">
|
||||
<div class="dmesg-head">
|
||||
<h3>dmesg</h3>
|
||||
|
||||
Reference in new issue
Block a user