feat: страница логов /ui/logs с SSE real-time потоком
- 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:
@ -1,3 +1,4 @@
|
||||
import asyncio
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
@ -5,14 +6,16 @@ from fastapi import FastAPI, Request
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from starlette.responses import HTMLResponse, Response
|
||||
|
||||
from onguard24 import __version__ as app_version
|
||||
from onguard24.config import get_settings
|
||||
from onguard24.db import create_pool
|
||||
from onguard24.domain.events import InMemoryEventBus
|
||||
from onguard24.ingress import grafana as grafana_ingress
|
||||
from onguard24.log_buffer import install_log_handler
|
||||
from onguard24.modules.registry import MODULE_MOUNTS, register_module_events
|
||||
from onguard24.root_html import render_root_page
|
||||
from onguard24.status_snapshot import build as build_status
|
||||
from onguard24 import __version__ as app_version
|
||||
from onguard24.ui_logs import router as logs_router
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logging.getLogger("httpx").setLevel(logging.WARNING)
|
||||
@ -31,6 +34,7 @@ def parse_addr(http_addr: str) -> tuple[str, int]:
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
install_log_handler(asyncio.get_event_loop())
|
||||
settings = get_settings()
|
||||
pool = await create_pool(settings)
|
||||
bus = InMemoryEventBus()
|
||||
@ -38,7 +42,7 @@ async def lifespan(app: FastAPI):
|
||||
app.state.pool = pool
|
||||
app.state.settings = settings
|
||||
app.state.event_bus = bus
|
||||
log.info("onGuard24 started, db=%s", "ok" if pool else "disabled")
|
||||
log.info("onGuard24 started v%s, db=%s", app_version, "ok" if pool else "disabled")
|
||||
yield
|
||||
if pool:
|
||||
await pool.close()
|
||||
@ -82,6 +86,7 @@ def create_app() -> FastAPI:
|
||||
return await build_status(request)
|
||||
|
||||
app.include_router(grafana_ingress.router, prefix="/api/v1")
|
||||
app.include_router(logs_router)
|
||||
for mount in MODULE_MOUNTS:
|
||||
app.include_router(mount.router, prefix=mount.url_prefix)
|
||||
if mount.ui_router is not None:
|
||||
|
||||
Reference in New Issue
Block a user