Files
FabledSteward/docs/core/monitors.md
T
bvandeusen 230b542015 feat: rename to FabledScryer, multi-dashboard system, plugin management, branding
- Rename package fablednetmon → fabledscryer throughout
- Multi-dashboard: ownership, per-user defaults, HTMX edit (add/remove/reorder)
- Read-only share tokens scoped to individual dashboards
- Dashboard edit is HTMX-driven (no page reloads)
- Plugin management system: remote catalog, download/install, hot-reload, in-app restart
- plugin_index.py: fetch/cache remote index.yaml; default URL → bvandeusen/fabledscryer-plugins
- plugin_manager.py: download_and_install_plugin, hot_reload_plugin, restart_app
  - ZIP extraction handles GitHub archive formats (name-v1.0.0/, name-main/)
- Settings split into tabbed sections: General, Notifications, Ansible, Plugins
- Plugins tab: catalog browser (HTMX), install/activate/update/restart actions
- UI/branding: dark palette (#07071a), crystal ball SVG logo, animated star field,
  Libertinus Serif applied to headings, nav, labels, and section titles
- Widget registry (core/widgets.py) for dashboard plugin integration
- UPS widget.html (dashboard card) and settings/_tabs.html include
- Migrations 0005–0008: dashboards, is_default, ownership, share tokens
- docs/plugins/: writing-a-plugin.md updated with publishing guide,
  index.yaml.example template for fabledscryer-plugins repo

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-22 18:27:56 -04:00

105 lines
4.1 KiB
Markdown

# Core Monitors
Fabled Scryer ships two built-in monitors: Ping and DNS. Both run as asyncio scheduled tasks on the same event loop as the web server, with no separate processes.
---
## Ping Monitor
**Source:** `fabledscryer/monitors/ping.py`
**Scheduler task:** `ping_monitor` in `fabledscryer/app.py`
**Interval:** `monitors.poll_interval_seconds` (default 60s), runs on startup
### How It Works
On each tick, the scheduler fetches all hosts with `ping_enabled = true` and calls `ping_check(host, session)` for each.
`ping_check()` probes the host using:
- **ICMP** if `host.probe_type == "icmp"` — uses the system `ping` binary (`/bin/ping` or equivalent). Requires `iputils-ping` in Docker.
- **TCP** if `host.probe_type == "tcp"` (default) — attempts an async TCP connection to `host.address:host.probe_port` (default port 80).
Each probe writes a `PingResult` row and calls `record_metric()`:
| `source_module` | `resource_name` | `metric_name` | `value` |
|---|---|---|---|
| `ping` | `host.name` | `response_time_ms` | measured latency, or `0.0` if down |
| `ping` | `host.name` | `up` | `1.0` if up, `0.0` if down |
**Alert rule note:** Because `response_time_ms` is recorded as `0.0` when a host is down, a latency rule (e.g. `response_time_ms > 500`) will not fire on complete outages. Use a separate rule on `up == 0.0` to detect host down events.
### Data Model
`ping_results` table (defined in `fabledscryer/models/monitors.py`):
| Column | Type | Description |
|---|---|---|
| `id` | UUID | Primary key |
| `host_id` | FK → hosts | |
| `probed_at` | timestamp UTC | When the probe ran |
| `status` | enum `up`/`down` | Result |
| `response_time_ms` | float | Null if down |
Old rows are pruned by the `data_cleanup` task (default: 90 days).
### UI
- **Dashboard widget** — live-updating via HTMX polling (`/ping/rows`)
- **`/ping/` page** — full page with 30-pill history per host and threshold settings form
- **Hosts list** — shows latest ping status dot and latency
---
## DNS Monitor
**Source:** `fabledscryer/monitors/dns.py`
**Scheduler task:** `dns_monitor` in `fabledscryer/app.py`
**Interval:** `monitors.poll_interval_seconds` (default 60s), runs on startup
### How It Works
On each tick, the scheduler fetches all hosts with `dns_enabled = true` and calls `dns_check(host, session)` for each.
`dns_check()` resolves `host.address` using the system resolver. If `host.dns_expected_ip` is set, the check passes only if at least one returned A/AAAA record exactly matches that string. If `dns_expected_ip` is null, any successful resolution counts as a pass.
Each check writes a `DnsResult` row and calls `record_metric()`:
| `source_module` | `resource_name` | `metric_name` | `value` |
|---|---|---|---|
| `dns` | `host.name` | `resolved` | `1.0` if resolved, `0.0` if failed |
| `dns` | `host.name` | `ip_changed` | `1.0` if IP changed from last successful result, `0.0` otherwise |
### Data Model
`dns_results` table (defined in `fabledscryer/models/monitors.py`):
| Column | Type | Description |
|---|---|---|
| `id` | UUID | Primary key |
| `host_id` | FK → hosts | |
| `resolved_at` | timestamp UTC | When the check ran |
| `status` | enum `resolved`/`failed` | Result |
| `resolved_ip` | str | First returned A/AAAA record; null if failed |
`ip_changed` is computed by comparing `resolved_ip` of the current result against the most recent prior `resolved` result for the same host.
### UI
- **Dashboard widget** — live-updating via HTMX polling (`/dns/rows`)
- **`/dns/` page** — full page showing all DNS-enabled hosts with status, resolved IP, and timestamp
- **Hosts list** — shows latest DNS status dot
---
## Host Configuration
Hosts are managed at `/hosts/`. Both monitors are configured per-host:
| Field | Description |
|---|---|
| `ping_enabled` | Enable ping probing for this host |
| `probe_type` | `tcp` (default) or `icmp` |
| `probe_port` | TCP port to connect to (default 80; ignored for ICMP) |
| `dns_enabled` | Enable DNS resolution checks |
| `dns_expected_ip` | If set, the resolved IP must match this string exactly |
| `poll_interval_seconds` | Per-host override for the global poll interval; null uses global |