4b6817381b
Benchmark image — build + push to ECR (any adapter) / build + push (push) Waiting to run
CI / quality (ubuntu-latest) (push) Waiting to run
CI / test (tools-runtime) (push) Waiting to run
CI / test (e2e-general) (push) Waiting to run
CI / test (cli-runtime) (push) Waiting to run
CI / test (e2e-provider-and-openclaw) (push) Waiting to run
CI / test (integrations-and-misc) (push) Waiting to run
CI / coverage-report (push) Blocked by required conditions
CI / test-kubernetes (push) Waiting to run
CI / should-run-thorough (push) Waiting to run
CI / test-thorough (cloudwatch-demo) (push) Blocked by required conditions
CI / test-thorough (flink-ecs) (push) Blocked by required conditions
CI / test-thorough (upstream-lambda) (push) Blocked by required conditions
CI / test-thorough (prefect-ecs-fargate) (push) Blocked by required conditions
CodeQL / Analyze (python) (push) Waiting to run
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Blocked by required conditions
Release / publish-release (push) Blocked by required conditions
Release / publish-main-release (push) Blocked by required conditions
Release / prepare (push) Waiting to run
Release / verify (push) Blocked by required conditions
Release / build-python-dist (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Blocked by required conditions
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Blocked by required conditions
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Waiting to run
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Waiting to run
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
156 lines
9.4 KiB
Plaintext
156 lines
9.4 KiB
Plaintext
---
|
||
title: "Hermes log monitoring"
|
||
description: "Tail Hermes errors.log, classify incidents, alert on Telegram; run offline classifier regression tests, then try a local watch demo."
|
||
---
|
||
|
||
OpenSRE can **watch the log file written by a [Hermes](https://github.com/NousResearch/hermes-agent) deployment** (typically `errors.log`), turn new lines into structured incidents, optionally **deduplicate and escalate** them, and deliver alerts to **Telegram**. This page is about that **log tail + classifier + delivery** path — separate from OpenSRE’s own runtime logs.
|
||
|
||
Developer workflow: the **Hermes synthetic suite** under `tests/synthetic/hermes/` runs **offline** classifier checks (no LLM, no live infra); you can run that first, then **watch** a bundled scenario `errors.log` with `opensre hermes watch` as a small local demo. **Optional:** enable **`--investigate`** to attach the full OpenSRE RCA pipeline for **HIGH** / **CRITICAL** incidents ([quickstart](/quickstart)).
|
||
|
||
<Note>
|
||
Telegram delivery uses the same credential model as the rest of OpenSRE. Configure it once with `opensre integrations setup telegram` (or `opensre onboard`) — `hermes watch` resolves the token from the integration store, environment, or keyring. You can also set `TELEGRAM_BOT_TOKEN` / `TELEGRAM_DEFAULT_CHAT_ID` directly, or pass `--chat-id`. See [Telegram](/messaging/telegram).
|
||
</Note>
|
||
|
||
---
|
||
|
||
## Local demo: synthetic tests, then watch
|
||
|
||
**1 — Offline “investigation” of the classifier (pytest, no Telegram)**
|
||
The Hermes log-classifier synthetic suite feeds real-shaped `errors.log` slices through `IncidentClassifier` and asserts against `answer.yml`. This is the same regression loop documented in the repo’s [`tests/synthetic/hermes/README.md`](https://github.com/Tracer-Cloud/opensre/blob/main/tests/synthetic/hermes/README.md):
|
||
|
||
```bash
|
||
uv run pytest tests/synthetic/hermes -q
|
||
```
|
||
|
||
For incident-identification RCA fixtures (session topology, runtime hangs, cron delivery, KV cache drift), run the parallel suite:
|
||
|
||
```bash
|
||
uv run pytest tests/synthetic/hermes_rca -q
|
||
```
|
||
|
||
To run every synthetic-marked test under `tests/synthetic/` (includes Hermes and other packages):
|
||
|
||
```bash
|
||
make test-synthetic
|
||
```
|
||
|
||
**2 — Live watch on a fixture file (Telegram required)**
|
||
Use a scenario’s `errors.log` that emits incidents under **default** classifier settings (see **Quick check with a bundled fixture** under [CLI: live watch](#cli-live-watch) — the `002-gateway-systemd-crash-loop` example matches the screenshot there). From the repo root:
|
||
|
||
```bash
|
||
export TELEGRAM_BOT_TOKEN=…
|
||
export TELEGRAM_DEFAULT_CHAT_ID=…
|
||
uv run opensre hermes watch \
|
||
--log-path tests/synthetic/hermes/002-gateway-systemd-crash-loop/errors.log \
|
||
--from-start
|
||
```
|
||
|
||
`--from-start` **replays** the file then keeps tailing — good for a one-shot demo of classification → Telegram. By default, watch **only reads new lines**, so without `--from-start` a static fixture produces no events until more lines are appended (use a **writable** copy of the scenario log if you want to experiment without editing files under `tests/`). Omit **`--investigate`** for a lightweight demo (**`--investigate`** runs the investigation pipeline with an LLM for **HIGH** / **CRITICAL** only; see below).
|
||
|
||
---
|
||
|
||
## What gets monitored
|
||
|
||
| Item | Default |
|
||
|------|---------|
|
||
| Log file | `~/.hermes/logs/errors.log` |
|
||
| Override | Set `HERMES_LOG_PATH` to an absolute path if Hermes writes elsewhere |
|
||
|
||
The watcher uses a rotation-safe tailer: if the file is missing at startup, it waits until it appears. Use `--from-start` if you intentionally want to replay existing file contents before live-tailing (by default **only new lines** are considered so Telegram is not flooded on restart).
|
||
|
||
---
|
||
|
||
## CLI: live watch
|
||
|
||
Run from a machine that can read the Hermes log file and reach Telegram:
|
||
|
||
```bash
|
||
uv run opensre hermes watch
|
||
```
|
||
|
||
Stop with **Ctrl+C** or **SIGTERM** (e.g. under systemd).
|
||
|
||
### Quick check with a bundled fixture
|
||
|
||
From the repo root you can point `--log-path` at a synthetic `errors.log`. Prefer a scenario with **ERROR** / **CRITICAL** lines so incidents fire under the **default** classifier (the live watcher does **not** read per-scenario `scenario.yml` thresholds):
|
||
|
||
```bash
|
||
uv run opensre hermes watch \
|
||
--log-path tests/synthetic/hermes/002-gateway-systemd-crash-loop/errors.log \
|
||
--from-start
|
||
```
|
||
|
||
Example **Telegram** output when replaying that fixture (critical exit, traceback, crash loop, and systemd error):
|
||
|
||

|
||
|
||
**Why you might see no Telegram:** `warning_burst` needs **five** warnings from the same logger within **60 seconds** (`IncidentClassifier` defaults). Several synthetic scenarios set a lower threshold in `scenario.yml` for **pytest only**; the CLI watcher ignores that file. For example `000-telegram-polling-conflict` expects bursts of **three** warnings — the suite passes, but **`hermes watch` on that file emits no `warning_burst` incidents**, so nothing is sent. Use a log with hard errors (like `002-*`) or your real `errors.log` once Hermes is writing enough warnings.
|
||
|
||
Correlator **dedup** can also reduce multiple Telegram sends for the same fingerprint; check shutdown line `hermes-watch: correlator metrics delivered=…` — if `delivered=0`, the classifier did not emit any routable incidents for that run.
|
||
|
||
### Common options
|
||
|
||
| Flag | Purpose |
|
||
|------|---------|
|
||
| `--log-path PATH` | Hermes log file (defaults to `HERMES_LOG_PATH` expansion or `~/.hermes/logs/errors.log`) |
|
||
| `--chat-id ID` | Overrides `TELEGRAM_DEFAULT_CHAT_ID` for this run |
|
||
| `--cooldown-seconds N` | Per-fingerprint cooldown before the same incident is sent again (default `300`) |
|
||
| `--from-start` | Replay the file from the beginning, then tail |
|
||
| `--investigate` / `--no-investigate` | Run an OpenSRE RCA for `HIGH` / `CRITICAL` incidents and append the summary to Telegram |
|
||
| `--correlate` / `--no-correlate` | Route through the correlator (dedup, escalation, routing). Default: **on** |
|
||
| `--dedup-window-seconds` | Correlator dedup window when `--correlate` is on |
|
||
| `--escalation-threshold` / `--escalation-window-seconds` | Repeat-hit escalation knobs when `--correlate` is on |
|
||
|
||
### Environment variables
|
||
|
||
| Variable | Role |
|
||
|----------|------|
|
||
| `TELEGRAM_BOT_TOKEN` | Bot token, unless already configured via `opensre integrations setup telegram` / `onboard` (see [Telegram](/messaging/telegram)) |
|
||
| `TELEGRAM_DEFAULT_CHAT_ID` | Default destination when `--chat-id` is omitted |
|
||
| `HERMES_LOG_PATH` | Default log path when `--log-path` is omitted |
|
||
| `OPENSRE_HERMES_INVESTIGATE` | If set to `1` / `true` / `yes` / `on`, enables investigation when the CLI does not pass `--investigate` / `--no-investigate` |
|
||
|
||
---
|
||
|
||
## Watch with full OpenSRE RCA (`--investigate`)
|
||
|
||
For production on-call, you normally run **one long-lived watcher** with the RCA bridge when you want LLM-backed summaries on serious incidents:
|
||
|
||
```bash
|
||
uv run opensre hermes watch --investigate
|
||
```
|
||
|
||
Configure **LLM + integrations** as for any OpenSRE investigation ([quickstart](/quickstart)). When the classifier emits **HIGH** or **CRITICAL** incidents, each qualifying incident triggers **`run_investigation`** via the Telegram sink. Work runs on a **bounded thread pool** with a **timeout** so log tailing stays responsive; **MEDIUM** and lower stay on a lighter notification path by default.
|
||
|
||
For **ad hoc** Hermes log context during **another** investigation (for example Grafana-driven RCA), use **`get_hermes_logs`** below — it samples the log and does not replace a long-running **`opensre hermes watch`** for continuous classification.
|
||
|
||
---
|
||
|
||
## Agent tool: `get_hermes_logs`
|
||
|
||
During an OpenSRE investigation, the planner can call **`get_hermes_logs`** to read the same Hermes log in two modes:
|
||
|
||
- **`op="scan"`** — one-shot window of the last *N* lines; returns parsed records and incidents the classifier would emit on that window.
|
||
- **`op="tail"`** — incremental, cursor-based reads for “what’s new since last poll?”.
|
||
|
||
The tool only allows paths under permitted directories (by default `~/.hermes` and the parent of `HERMES_LOG_PATH` when set) so arbitrary file reads are blocked.
|
||
|
||
<Warning>
|
||
**Classifier state is not persisted between `tail` calls.** Each tool invocation uses a fresh classifier, so burst windows and traceback continuation state reset between calls. For accurate ongoing detection, use **`opensre hermes watch`** (long-lived classifier) rather than many separate `tail` calls.
|
||
</Warning>
|
||
|
||
---
|
||
|
||
## Synthetic regression suite
|
||
|
||
Contributors add scenarios under `tests/synthetic/hermes/` (fixtures, `scenario.yml`, `answer.yml`). Layout, schema, and “adding a new scenario” steps are in [`tests/synthetic/hermes/README.md`](https://github.com/Tracer-Cloud/opensre/blob/main/tests/synthetic/hermes/README.md).
|
||
|
||
---
|
||
|
||
## Further reading
|
||
|
||
- Implementation lives under `integrations/hermes/` in the OpenSRE repository (tailer, parser, classifier, correlator, sinks, CLI wiring).
|
||
- Surface-attribution evaluation workflow for contributors: [`docs/hermes_runbook.mdx`](https://github.com/Tracer-Cloud/opensre/blob/main/docs/hermes_runbook.mdx) in the repo (not on the public docs nav).
|
||
- If you also run [OpenClaw](/openclaw) alongside Hermes, that page covers the OpenClaw bridge (context lookup and RCA write-back).
|
||
- For false-positive risks when rules match both `message` and raw line text, see [issue #1874](https://github.com/Tracer-Cloud/opensre/issues/1874).
|