사용자 서비스 로그 갱신 흐름 정리
This commit is contained in:
@@ -25,6 +25,7 @@ Control은 라즈베리파이/리눅스 호스트의 팬과 시스템 상태를
|
|||||||
- System Notice 최근 이력 표시
|
- System Notice 최근 이력 표시
|
||||||
- process CPU/MEM 후보는 프로세스 상세 접힘 영역에서 표시
|
- process CPU/MEM 후보는 프로세스 상세 접힘 영역에서 표시
|
||||||
- `/etc/systemd/system/*.service` 기준 사용자 생성 서비스의 서비스명, 현재 상태, enable 상태, PID, restart 횟수, 최근 journal 로그를 진단 접힘 영역에서 표시
|
- `/etc/systemd/system/*.service` 기준 사용자 생성 서비스의 서비스명, 현재 상태, enable 상태, PID, restart 횟수, 최근 journal 로그를 진단 접힘 영역에서 표시
|
||||||
|
- 사용자 서비스 로그는 서비스별 최근 500줄까지 조회하고, 사용자가 서비스 목록을 스크롤하는 동안에는 자동 갱신이 화면 위치를 되돌리지 않습니다.
|
||||||
- dmesg 로그는 진단 접힘 영역에서 필요할 때 열람
|
- dmesg 로그는 진단 접힘 영역에서 필요할 때 열람
|
||||||
- WakeLock 버튼으로 대시보드 화면 꺼짐 방지
|
- WakeLock 버튼으로 대시보드 화면 꺼짐 방지
|
||||||
- Reboot 버튼으로 2단계 확인 후 시스템 재부팅 요청
|
- Reboot 버튼으로 2단계 확인 후 시스템 재부팅 요청
|
||||||
@@ -230,8 +231,11 @@ control-wifi-observe.service
|
|||||||
- 센서 수집 주기와 DB 증가량을 확인합니다.
|
- 센서 수집 주기와 DB 증가량을 확인합니다.
|
||||||
- UPS/배터리를 다시 붙일 때는 `/home/seo/secret/control.php`의 `battery.enabled`와 용량값을 먼저 확인합니다.
|
- UPS/배터리를 다시 붙일 때는 `/home/seo/secret/control.php`의 `battery.enabled`와 용량값을 먼저 확인합니다.
|
||||||
- WiFi client 표는 갱신 중에도 가로 스크롤 위치를 보존합니다.
|
- WiFi client 표는 갱신 중에도 가로 스크롤 위치를 보존합니다.
|
||||||
|
- 사용자 서비스 목록은 갱신 중에도 스크롤 위치를 보존하고, 스크롤/터치/휠 조작 직후에는 DOM 교체를 잠시 미룹니다.
|
||||||
- 하드웨어 또는 OS 변경 후 fan sysfs 경로를 확인합니다.
|
- 하드웨어 또는 OS 변경 후 fan sysfs 경로를 확인합니다.
|
||||||
|
- AP 국가는 `PA`로 두고, `router-performance.service`가 `wlan0`, `wlan1` power save를 끄고 출력 요청값을 `3600`으로 넣습니다. 실제 출력은 무선 모듈/드라이버가 허용하는 값에서 멈추며 현재 두 AP 모두 `31.00 dBm`으로 표시됩니다.
|
||||||
- 2.4G 내장 WiFi는 `hostapd-24g.service` 개별 restart 직후 일부 IoT 단말이 WPA/EAPOL 재협상 루프에 들어갈 수 있으므로, 안정화된 상태에서는 개별 restart를 피하고 필요 시 전체 reboot 또는 채널 변경으로 재초기화합니다.
|
- 2.4G 내장 WiFi는 `hostapd-24g.service` 개별 restart 직후 일부 IoT 단말이 WPA/EAPOL 재협상 루프에 들어갈 수 있으므로, 안정화된 상태에서는 개별 restart를 피하고 필요 시 전체 reboot 또는 채널 변경으로 재초기화합니다.
|
||||||
|
- `hostapd-24g.service`, `hostapd-5g.service`는 종료 후 해당 `wlan` 인터페이스를 `br0`에서 떼도록 두어, 모듈이 빠졌다가 돌아온 뒤 hostapd가 다시 붙이는 흐름으로 정리합니다.
|
||||||
- 5G WiFi 연결 시간은 외부 모듈이 값을 제공하지 않을 때 서버가 처음 감지한 시각 기준으로 계산합니다. 현재 5G 목록에서 MAC이 사라지면 관측 세션을 즉시 종료하므로 재연결 시 0부터 다시 누적됩니다.
|
- 5G WiFi 연결 시간은 외부 모듈이 값을 제공하지 않을 때 서버가 처음 감지한 시각 기준으로 계산합니다. 현재 5G 목록에서 MAC이 사라지면 관측 세션을 즉시 종료하므로 재연결 시 0부터 다시 누적됩니다.
|
||||||
- `control-wifi-observe.timer`는 10초마다 `/var/www/control/bin/wifi_observe.php`를 실행해 사용자가 대시보드에 접속하지 않아도 5G 연결 시간 카운터를 시작하고 유지합니다.
|
- `control-wifi-observe.timer`는 10초마다 `/var/www/control/bin/wifi_observe.php`를 실행해 사용자가 대시보드에 접속하지 않아도 5G 연결 시간 카운터를 시작하고 유지합니다.
|
||||||
- WebSocket은 장기 실행 프로세스이므로 `public/api.php`, `config/config.php`, `bin/control_ws.php` 변경을 감지하면 15초 안에 종료되고 `control-websocket.service`가 새 프로세스로 재시작합니다.
|
- WebSocket은 장기 실행 프로세스이므로 `public/api.php`, `config/config.php`, `bin/control_ws.php` 변경을 감지하면 15초 안에 종료되고 `control-websocket.service`가 새 프로세스로 재시작합니다.
|
||||||
|
|||||||
+1
-1
@@ -170,7 +170,7 @@ function setting_definitions(): array
|
|||||||
'notice.log_interval_seconds' => ['group' => 'notice', 'label' => 'Alert 반복 기록 간격', 'type' => 'number', 'default' => 300, 'min' => 30, 'max' => 3600, 'step' => 30, 'unit' => '초'],
|
'notice.log_interval_seconds' => ['group' => 'notice', 'label' => 'Alert 반복 기록 간격', 'type' => 'number', 'default' => 300, 'min' => 30, 'max' => 3600, 'step' => 30, 'unit' => '초'],
|
||||||
'notice.downward_only_process_hide' => ['group' => 'notice', 'label' => '하강 변화 원인 후보 숨김', 'type' => 'boolean', 'default' => 1],
|
'notice.downward_only_process_hide' => ['group' => 'notice', 'label' => '하강 변화 원인 후보 숨김', 'type' => 'boolean', 'default' => 1],
|
||||||
'display.process_limit' => ['group' => 'display', 'label' => '프로세스 후보 표시 수', 'type' => 'number', 'default' => 6, 'min' => 1, 'max' => 30, 'step' => 1, 'unit' => '개'],
|
'display.process_limit' => ['group' => 'display', 'label' => '프로세스 후보 표시 수', 'type' => 'number', 'default' => 6, 'min' => 1, 'max' => 30, 'step' => 1, 'unit' => '개'],
|
||||||
'display.custom_service_log_lines' => ['group' => 'display', 'label' => '사용자 서비스 로그 줄 수', 'type' => 'number', 'default' => 12, 'min' => 1, 'max' => 50, 'step' => 1, 'unit' => '줄'],
|
'display.custom_service_log_lines' => ['group' => 'display', 'label' => '사용자 서비스 로그 줄 수', 'type' => 'number', 'default' => 500, 'min' => 1, 'max' => 500, 'step' => 10, 'unit' => '줄'],
|
||||||
'display.custom_service_cache_seconds' => ['group' => 'display', 'label' => '사용자 서비스 캐시 시간', 'type' => 'number', 'default' => 5, 'min' => 1, 'max' => 60, 'step' => 1, 'unit' => '초'],
|
'display.custom_service_cache_seconds' => ['group' => 'display', 'label' => '사용자 서비스 캐시 시간', 'type' => 'number', 'default' => 5, 'min' => 1, 'max' => 60, 'step' => 1, 'unit' => '초'],
|
||||||
'display.fan_notice_history_limit' => ['group' => 'display', 'label' => '팬 이상 이력 표시 수', 'type' => 'number', 'default' => 100, 'min' => 10, 'max' => 500, 'step' => 10, 'unit' => '개'],
|
'display.fan_notice_history_limit' => ['group' => 'display', 'label' => '팬 이상 이력 표시 수', 'type' => 'number', 'default' => 100, 'min' => 10, 'max' => 500, 'step' => 10, 'unit' => '개'],
|
||||||
'battery.trend_hours' => ['group' => 'battery', 'label' => '단기 배터리 학습 범위', 'type' => 'number', 'default' => 24, 'min' => 1, 'max' => 48, 'step' => 1, 'unit' => '시간'],
|
'battery.trend_hours' => ['group' => 'battery', 'label' => '단기 배터리 학습 범위', 'type' => 'number', 'default' => 24, 'min' => 1, 'max' => 48, 'step' => 1, 'unit' => '시간'],
|
||||||
|
|||||||
+1
-1
@@ -3065,7 +3065,7 @@ function parse_systemctl_show_records(string $out): array
|
|||||||
|
|
||||||
function systemd_service_logs(string $unit, int $limit = 12): array
|
function systemd_service_logs(string $unit, int $limit = 12): array
|
||||||
{
|
{
|
||||||
$limit = max(1, min(50, $limit));
|
$limit = max(1, min(500, $limit));
|
||||||
$cmd = [
|
$cmd = [
|
||||||
'/usr/bin/journalctl',
|
'/usr/bin/journalctl',
|
||||||
'-u',
|
'-u',
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
settingsPayload: null,
|
settingsPayload: null,
|
||||||
settingsOpen: false,
|
settingsOpen: false,
|
||||||
settingsDirty: false,
|
settingsDirty: false,
|
||||||
|
customServiceScrollHoldUntil: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const storageKeys = {
|
const storageKeys = {
|
||||||
@@ -1621,6 +1622,9 @@
|
|||||||
|
|
||||||
function renderCustomServices(rows = []) {
|
function renderCustomServices(rows = []) {
|
||||||
if (!els.customServiceList) return;
|
if (!els.customServiceList) return;
|
||||||
|
if (Date.now() < state.customServiceScrollHoldUntil) return;
|
||||||
|
|
||||||
|
const scrollTop = els.customServiceList.scrollTop;
|
||||||
|
|
||||||
els.customServiceList.innerHTML = rows.length
|
els.customServiceList.innerHTML = rows.length
|
||||||
? rows.map(row => {
|
? rows.map(row => {
|
||||||
@@ -1653,6 +1657,8 @@
|
|||||||
`;
|
`;
|
||||||
}).join('')
|
}).join('')
|
||||||
: `<div class="spike-log-empty">${escapeHtml(t('noCustomServices'))}</div>`;
|
: `<div class="spike-log-empty">${escapeHtml(t('noCustomServices'))}</div>`;
|
||||||
|
|
||||||
|
els.customServiceList.scrollTop = scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderFanCause(data) {
|
function renderFanCause(data) {
|
||||||
@@ -2214,6 +2220,12 @@
|
|||||||
els.dmesgToggle?.addEventListener('click', () => {
|
els.dmesgToggle?.addEventListener('click', () => {
|
||||||
setDmesgOpen(!state.dmesgOpen);
|
setDmesgOpen(!state.dmesgOpen);
|
||||||
});
|
});
|
||||||
|
const holdCustomServiceScroll = () => {
|
||||||
|
state.customServiceScrollHoldUntil = Date.now() + 4000;
|
||||||
|
};
|
||||||
|
['scroll', 'wheel', 'touchstart', 'touchmove', 'pointerdown'].forEach(eventName => {
|
||||||
|
els.customServiceList?.addEventListener(eventName, holdCustomServiceScroll, { passive: true });
|
||||||
|
});
|
||||||
els.wifiTable?.addEventListener('click', event => {
|
els.wifiTable?.addEventListener('click', event => {
|
||||||
const button = event.target?.closest?.('.wifi-host-edit');
|
const button = event.target?.closest?.('.wifi-host-edit');
|
||||||
if (!button) return;
|
if (!button) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user