feat: GET /api/0/log — paged, filtered events journal API
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,6 +20,7 @@ from . import users as users_mod
|
|||||||
from . import oauth as oauth_mod
|
from . import oauth as oauth_mod
|
||||||
from . import ws as ws_mod
|
from . import ws as ws_mod
|
||||||
from . import configio as configio_mod
|
from . import configio as configio_mod
|
||||||
|
from . import journal as journal_mod
|
||||||
from . import config_access
|
from . import config_access
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -362,6 +363,46 @@ async def start(
|
|||||||
lst = data.msgs[-30:]
|
lst = data.msgs[-30:]
|
||||||
return web.json_response(lst)
|
return web.json_response(lst)
|
||||||
|
|
||||||
|
async def api_log(request):
|
||||||
|
"""Paged, filtered read of the events journal (newest first)."""
|
||||||
|
user, err = _require_auth(request)
|
||||||
|
if err:
|
||||||
|
return err
|
||||||
|
qa = request.rel_url.query
|
||||||
|
try:
|
||||||
|
limit = max(1, min(int(qa.get("limit", "100")), 1000))
|
||||||
|
except ValueError:
|
||||||
|
limit = 100
|
||||||
|
before = None
|
||||||
|
if qa.get("before"):
|
||||||
|
try:
|
||||||
|
before = float(qa["before"])
|
||||||
|
except ValueError:
|
||||||
|
return web.json_response({"error": "invalid before"}, status=400)
|
||||||
|
host_f = qa.get("host") or None
|
||||||
|
level_f = qa.get("level") or None
|
||||||
|
q_f = qa.get("q") or None
|
||||||
|
|
||||||
|
def visible(ev):
|
||||||
|
h = ev.get("host")
|
||||||
|
return not h or ws_mod._user_can_see_host(user, h)
|
||||||
|
|
||||||
|
ej = journal_mod.get_events_journal(config)
|
||||||
|
if ej.enabled and ej.journal_path.is_file():
|
||||||
|
events, more = journal_mod.read_events(
|
||||||
|
ej.journal_dir, ej.journal_file,
|
||||||
|
limit=limit, before=before, host=host_f, level=level_f, q=q_f,
|
||||||
|
predicate=visible,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# Journal disabled or not yet written: serve the in-memory ring
|
||||||
|
events, more = journal_mod.filter_events(
|
||||||
|
reversed(data.msgs),
|
||||||
|
limit=limit, before=before, host=host_f, level=level_f, q=q_f,
|
||||||
|
predicate=visible,
|
||||||
|
)
|
||||||
|
return web.json_response({"events": events, "more": more})
|
||||||
|
|
||||||
async def cmd(request):
|
async def cmd(request):
|
||||||
user, err = _require_auth(request)
|
user, err = _require_auth(request)
|
||||||
if err:
|
if err:
|
||||||
@@ -1779,6 +1820,7 @@ async def start(
|
|||||||
web.get("/api/0/hosts", api_hosts),
|
web.get("/api/0/hosts", api_hosts),
|
||||||
web.get("/api/0/alert_summary", api_alert_summary),
|
web.get("/api/0/alert_summary", api_alert_summary),
|
||||||
web.get("/api/0/messages", api_messages),
|
web.get("/api/0/messages", api_messages),
|
||||||
|
web.get("/api/0/log", api_log),
|
||||||
web.get("/api/0/hosts/{hostname}/plugins", api_host_plugins),
|
web.get("/api/0/hosts/{hostname}/plugins", api_host_plugins),
|
||||||
web.get("/api/0/hosts/{hostname}/plugins/{plugin_name}", api_host_plugin_detail),
|
web.get("/api/0/hosts/{hostname}/plugins/{plugin_name}", api_host_plugin_detail),
|
||||||
web.get("/api/0/hosts/{hostname}/alerts", api_host_alerts),
|
web.get("/api/0/hosts/{hostname}/alerts", api_host_alerts),
|
||||||
|
|||||||
Reference in New Issue
Block a user