I built the on-call log review I used to do by hand into a service. It reads Loki logs across five hosts, writes a prioritized incident report through Claude, and — the part that makes it more than a summarizer — remembers open issues across runs so every report tells me what's new, still ongoing, or newly resolved.
A single-file FastAPI service (ai-sre-api) sitting between Grafana Loki and the Anthropic Messages API. Logs from five sources ship into one Loki instance; the service pulls the relevant lines with LogQL and asks a Claude model to interpret them as a Site Reliability Engineer would. The whole stack — Loki, Promtail, and the API — is three containers defined by one docker-compose.yml, running on a 4 GB Proxmox VM.
POST /report — a balanced multi-host infrastructure report: high-priority issues first, per-host health (🟢/🟡/🔴/⚪), security observations, recommendations.POST /ask — a free-form natural-language question against any log source (or raw LogQL) for ad-hoc investigation.Log ingestion is deliberately heterogeneous, because real infrastructure is: Promtail on the Linux hosts, OPNsense via remote syslog to a receiver, Proxmox via journald→Promtail, and the nginx box shipping parsed access logs. It all lands in Loki under a coarse, queryable label scheme.
An LLM summarizing a time window is stateless — run it twice and it re-reports the same disk warning as if it were new every time. That's noise, and noise gets ignored. So each scheduled run carries a persistent issue-ledger:
NEW, ONGOING since <date>, or RESOLVED.os.replace) and are skipped entirely when a response is an error, empty, or a parse-miss — so a bad run can never clobber a good ledger.<!-- SRE-LEDGER-BEGIN -->
| id | host | first_seen | last_seen | status | priority | summary
| pve-smart-drive-degradation | pve | 2026-07-01 | 2026-07-05 | ONGOING | P2 | /dev/sdc SMART prefailure escalating
<!-- SRE-LEDGER-END -->
This is context engineering applied to observability: state persisted between otherwise-stateless calls so the reports build on each other instead of analyzing every window cold.
Most of the hard work was making a language model behave like a trustworthy monitor instead of an anxious one. Each of these fixes a specific failure I watched it make:
Raw_Read_Error_Rate / Seek_Error_Rate churn is benign — only reallocated/pending/uncorrectable sectors or an explicit FAILED verdict count. This killed a recurring false disk-failure P1.SUMMARY: first line; the script parses it and raises ntfy notification priority to high whenever a P1 is present.zoneinfo, with a UTC fallback.Everyone in 2026 can point an LLM at a log file. The leverage is in the parts that make it operable: memory so alerts aren't repeated, guards so it doesn't cry wolf, budgets so it doesn't cost a fortune, and schedules so it runs whether or not I'm watching. That's twenty years of build/release discipline aimed at a new tool — and it's the same shape as the AI pipelines I run at work, just on infrastructure I can show you.