feat: страница логов /ui/logs с SSE real-time потоком
Some checks failed
CI / test (push) Successful in 39s
Deploy / deploy (push) Failing after 15s

- log_buffer: RingBufferHandler, кольцевой буфер 600 записей, fan-out SSE
- ui_logs: GET /ui/logs (HTML), GET /ui/logs/stream (EventSource)
- main: install_log_handler при старте, подключён router логов
- nav_rail: ссылка Логи, root_html: кнопка-ссылка Логи
- Исправлено: NaN/Inf/NUL в теле вебхука → 500 от PostgreSQL jsonb
- Тесты: test_log_buffer, test_json_sanitize; 51 passed

Made-with: Cursor
This commit is contained in:
Alexandr
2026-04-03 15:56:58 +03:00
parent 18ba48e8d0
commit 80645713a0
12 changed files with 465 additions and 12 deletions

View File

@ -46,6 +46,7 @@ APP_SHELL_CSS = """
.gc-subtable th, .gc-subtable td { border: 1px solid #e4e4e7; padding: 0.3rem 0.45rem; }
.gc-subtable th { background: #fafafa; }
.gc-orphan { margin-top: 1rem; padding: 0.75rem; background: #fffbeb; border: 1px solid #fcd34d; border-radius: 8px; font-size: 0.88rem; }
.rail-item--util { border-top: 1px solid #e4e4e7; margin-top: 0.4rem; padding-top: 0.4rem; }
"""
@ -72,6 +73,11 @@ def nav_rail_html(current_slug: str | None = None) -> str:
items.append(
f'<li class="{licls}"><a href="{html.escape(href)}"{cur}>{html.escape(m.title)}</a></li>'
)
logs_active = current_slug == "__logs__"
items.append(
'<li class="rail-item rail-item--util' + (" is-active" if logs_active else "") + '">'
'<a href="/ui/logs"' + (' aria-current="page"' if logs_active else "") + ">📋 Логи</a></li>"
)
lis = "".join(items)
return (
'<aside class="app-rail" role="navigation" aria-label="Разделы приложения">'