Files
FabledSteward/plugins/syslog/__init__.py
T
bvandeusenandClaude Opus 5.5 8eae3d3825
CI / lint (push) Successful in 2s
CI / unit (push) Successful in 1m31s
CI / integration (push) Failing after 1m40s
CI / publish (push) Skipped
feat(syslog): pattern alerts: telling phrases counted per source each minute for alert rules, storage-trouble presets (#6001)
A pattern (phrases, a severity, a source, a window) is counted every minute
into plugin_metrics as lines_matching_<key> per added source, zero included,
so an ordinary alert rule fires on a match and clears once the window passes.
Each count reads only the lines stored since the last, by line id; a new or
changed pattern reads its window once.

Patterns page with ready-made storage-trouble presets and "Alert on it",
which opens the rule form aimed at the count. Source names are kept unique,
and a rename moves its counts and the rules on them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 06:22:54 -04:00

54 lines
1.6 KiB
Python

# plugins/syslog/__init__.py
from __future__ import annotations
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from quart import Quart
_app: "Quart | None" = None
def setup(app: "Quart") -> None:
global _app
_app = app
from .models import SyslogLine, SyslogPattern, SyslogSource # noqa: F401 — registers the tables
from .receiver import close
# The listener is bound by the receive task, so it follows the settings
# and starts on a live enable too; it is closed with the app.
app.after_serving(close)
def get_scheduled_tasks() -> list:
from .patterns import make_count_task
from .receiver import make_receive_task
from .retention import make_prune_task
return [make_receive_task(_app), make_prune_task(_app), make_count_task(_app)]
def get_blueprint():
from .routes import syslog_bp
return syslog_bp
def get_nav() -> list[dict]:
return [{"label": "Syslog", "href": "/plugins/syslog/"}]
def register_mcp_tools(register) -> None:
from .mcp_tools import register_tools
register_tools(register)
def get_alert_metrics() -> dict[str, list[str]]:
"""A pattern's count is named for the pattern (lines_matching_<key>), so
the list is empty here and the rule form offers the counts recorded so far."""
return {"syslog": []}
def get_audit_entities() -> dict:
"""Audit rows about a source or a pattern name it and link to its page."""
from .models import SyslogPattern, SyslogSource
return {"syslog_source": (SyslogSource, "/plugins/syslog/sources/{}"),
"syslog_pattern": (SyslogPattern, "/plugins/syslog/patterns/{}/edit")}