From c0dadcc8a97b4104a8ae4a96ba12b748780e102d Mon Sep 17 00:00:00 2001 From: seo Date: Sat, 1 Aug 2026 11:32:15 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9B=90=EA=B2=A9=20syslog=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 +-- bin/control_ws.php | 64 +------------ public/api.php | 173 ---------------------------------- public/assets/app.js | 220 ------------------------------------------- public/index.php | 18 ---- 5 files changed, 4 insertions(+), 482 deletions(-) diff --git a/README.md b/README.md index 6c6dcf0..b194fa5 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를 - process CPU/MEM 후보는 프로세스 상세 접힘 영역에서 표시 - `/etc/systemd/system/*.service` 기준 사용자 생성 서비스의 서비스명, 현재 상태, enable 상태, PID, restart 횟수, 최근 journal 로그를 진단 접힘 영역에서 표시 - 사용자 서비스 로그는 서비스별 최근 500줄까지 조회하고, 사용자가 서비스 목록을 스크롤하는 동안에는 자동 갱신이 화면 위치를 되돌리지 않습니다. -- 라즈베리파이와 시놀로지 사이 원격 syslog 송수신 상태, 영구 journal, 커널 크래시 보존 상태를 진단 접힘 영역에서 표시 +- 영구 journal과 커널 크래시 보존 상태를 진단 접힘 영역에서 표시 - 시놀로지에서 라즈베리파이로 들어온 원격 로그와 dmesg 로그는 진단 접힘 영역에서 필요할 때 열람 - WakeLock 버튼으로 대시보드 화면 꺼짐 방지 - Reboot 버튼으로 2단계 확인 후 시스템 재부팅 요청 @@ -52,7 +52,6 @@ Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를 - `public/api.php?action=settings_reset`: 설정 모달 값을 기본값으로 초기화 - `public/api.php?action=touch_display_save`: `/boot/firmware/config.txt`, `/boot/firmware/cmdline.txt`에 DSI 터치 디스플레이 부팅 설정 저장 - `public/api.php?action=touch_display_runtime_save`: DSI 터치 디스플레이 백라이트 밝기와 백라이트 전원 즉시 적용 -- `public/api.php?action=synology_log`: 라즈베리파이에 저장된 시놀로지 원격 로그를 표시용 필터로 걸러 최근 500줄 조회 - `public/api.php?action=dmesg`: dmesg 로그 조회 - `public/api.php?action=reboot`: 확인 단어와 관리자 암호 재검증 후 sudo reboot 실행 @@ -94,11 +93,7 @@ Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를 - `/home/seo/secret/control.php`: 앱 비밀번호, DB 설정, 선택적 배터리 설정, WOL 전용 API 토큰 - UPS/배터리 기능은 `/home/seo/secret/control.php`의 `battery.enabled`가 명시적으로 true일 때만 동작합니다. 현재 운영 기준은 UPS 제거 상태이므로 기본값은 false입니다. -## 원격 로그 - -라즈베리파이는 `rsyslog`와 `rsyslog-gnutls`로 로컬 journal/syslog를 시놀로지 Log Center에 TCP/TLS 6514로 보냅니다. 전송 대상은 `chaegeon.com:6514`이며, 네트워크가 끊기면 `/var/spool/rsyslog/control_synology_fwd*` 큐에 남았다가 재시도합니다. - -시놀로지는 DSM `syslog-ng`에서 라즈베리파이 `121.157.202.229:6514`로 TCP/TLS syslog를 보냅니다. 라즈베리파이 수신 로그는 `/var/log/remote/synology/*.log`에 저장하고 `/etc/logrotate.d/control-remote-syslog`가 매일 회전합니다. Control 진단 패널의 시놀로지 로그 뷰어는 `/var/log/remote/synology/chaegeon.log` 최근 500줄을 최신순으로 보여주며, WebSocket 또는 HTTP fallback으로 1초마다 갱신합니다. 사용자가 로그 영역을 스크롤하는 동안에는 자동 갱신을 잠깐 멈춰 화면 위치가 튀지 않게 합니다. +## 로그 보존 커널 패닉이나 강제 재부팅 분석을 위해 `systemd-journald`는 `/var/log/journal`에 영구 저장합니다. `dtoverlay=ramoops` 기반 pstore는 부팅 직후 `control-pstore-collect.service`가 `/var/log/pstore`로 복사합니다. 현재 pstore에 남은 크래시 조각이 없으면 이 서비스는 조건 불충족으로 `inactive`일 수 있으며 정상입니다. @@ -313,4 +308,4 @@ control-wifi-observe.service - 저전압/스로틀링이 `N/A`로 보이면 웹 서버 실행 계정의 `/dev/vcio` 접근 권한과 `/usr/bin/vcgencmd get_throttled` sudoers 허용 여부를 확인합니다. - 언어/테마 표시가 예상과 다르면 브라우저 localStorage의 `controlLang`, `controlTheme` 값을 확인합니다. - 시놀로지 운영 상태 확인은 NFS 경로가 아니라 SSH와 HTTPS API를 기준으로 합니다. Control 런타임에서 필요한 공용 HA 설정은 `/home/seo/secret/control.php`의 `common` 항목에 둡니다. -- smartban 판단 로그는 로컬 `logger -t smartban`으로 남기고 rsyslog/TLS가 시놀로지 Log Center로 전달합니다. +- smartban 판단 로그는 로컬 `logger -t smartban`으로 남깁니다. diff --git a/bin/control_ws.php b/bin/control_ws.php index 560da48..3edb1c6 100644 --- a/bin/control_ws.php +++ b/bin/control_ws.php @@ -16,12 +16,11 @@ require_once __DIR__ . '/../public/api.php'; final class ControlWebSocket implements MessageComponentInterface { - /** @var SplObjectStorage */ + /** @var SplObjectStorage */ private SplObjectStorage $clients; private bool $statusBusy = false; private bool $dmesgBusy = false; - private bool $synologyLogBusy = false; public function __construct() { @@ -48,7 +47,6 @@ final class ControlWebSocket implements MessageComponentInterface $this->clients[$conn] = [ 'dmesg' => false, - 'synology_log' => false, 'ip' => $ip, ]; $this->sendStatus($conn); @@ -63,7 +61,6 @@ final class ControlWebSocket implements MessageComponentInterface $state = $this->clients[$from] ?? [ 'dmesg' => false, - 'synology_log' => false, 'ip' => '127.0.0.1', ]; @@ -76,15 +73,6 @@ final class ControlWebSocket implements MessageComponentInterface return; } - if (($data['type'] ?? '') === 'synology_log') { - $state['synology_log'] = !empty($data['open']); - $this->clients[$from] = $state; - if ($state['synology_log']) { - $this->sendSynologyLog($from); - } - return; - } - if (($data['type'] ?? '') === 'status_refresh') { $this->sendStatus($from); } @@ -159,40 +147,6 @@ final class ControlWebSocket implements MessageComponentInterface } } - public function broadcastSynologyLog(): void - { - if ($this->clients->count() === 0 || $this->synologyLogBusy) { - return; - } - - $targets = []; - foreach ($this->clients as $client) { - $state = $this->clients[$client]; - if (!empty($state['synology_log'])) { - $targets[] = $client; - } - } - - if ($targets === []) { - return; - } - - $this->synologyLogBusy = true; - try { - $payload = $this->json([ - 'type' => 'synology_log', - 'data' => synology_remote_log(), - ]); - foreach ($targets as $client) { - $client->send($payload); - } - } catch (Throwable $e) { - $this->broadcastError($e); - } finally { - $this->synologyLogBusy = false; - } - } - private function sendStatus(ConnectionInterface $conn): void { try { @@ -220,21 +174,6 @@ final class ControlWebSocket implements MessageComponentInterface } } - private function sendSynologyLog(ConnectionInterface $conn): void - { - try { - $conn->send($this->json([ - 'type' => 'synology_log', - 'data' => synology_remote_log(), - ])); - } catch (Throwable $e) { - $conn->send($this->json([ - 'type' => 'error', - 'message' => $e->getMessage(), - ])); - } - } - private function statusPayload(): string { try { @@ -341,7 +280,6 @@ $startedSignature = $watchSignature($watchFiles); $loop->addPeriodicTimer(1.0, static fn() => $app->broadcastStatus()); $loop->addPeriodicTimer(1.0, static fn() => $app->broadcastDmesg()); -$loop->addPeriodicTimer(1.0, static fn() => $app->broadcastSynologyLog()); $loop->addPeriodicTimer(15.0, static function () use ($watchFiles, $watchSignature, $startedSignature): void { if ($watchSignature($watchFiles) === $startedSignature) { return; diff --git a/public/api.php b/public/api.php index b54a147..aea4402 100644 --- a/public/api.php +++ b/public/api.php @@ -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, diff --git a/public/assets/app.js b/public/assets/app.js index 037edd8..893dc2c 100644 --- a/public/assets/app.js +++ b/public/assets/app.js @@ -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 => { diff --git a/public/index.php b/public/index.php index 19eea27..a1a0abb 100644 --- a/public/index.php +++ b/public/index.php @@ -384,24 +384,6 @@ html[data-theme="light"] .details-panel{background:#edf3fa;border-color:#b8c7da} -
-
-

Synology Log

- -
- -
/var/log/remote/synology/chaegeon.log
- -
-

dmesg