The loudest error is rarely the first one.
firstsignal reads your logs during an incident and tells you what went wrong, in what order, and which safe checks to run next. It remembers past incidents, so a repeat comes with what fixed it last time.
pip install git+https://github.com/AutoShiftOps/firstsignal
- systemd
- Docker
- Kubernetes
- files & stdin
- no account
- no agent
- Slow operations latencymedium
- Connection limit reached saturationhigh
- Timeouts latencyhigh
- HTTP 5xx responses errors · 5×high
- Rate limiting trafficmedium
- Out of memory saturationcritical
- Restart loop errorshigh
- Connection refused errorshigh
One command per source
Each collector only reads. External tools run with a fixed argument list and no shell, and anything that looks like an injected option is rejected.
Plain text, JSON lines, logfmt and kubectl prefixes are all parsed. Health-check lines are dropped unless they report an error.
# a workload, a pod, or a label selector firstsignal k8s --pod deploy/api -n prod --since 30m # the container that just crashed firstsignal k8s -l app=api -n prod --previous
# stdout and stderr, with timestamps
firstsignal docker --container my-api --since 1hfirstsignal journal --unit nginx --since "30 min ago" --packs core,nginx
firstsignal file --path /var/log/app.log
firstsignal file --path archive.log.gz
# or pipe anything in
kubectl logs deploy/api | firstsignal file --path -# proxy, app and pod as one timeline
firstsignal bundle --unit nginx --container my-api \
--pod deploy/api -n prodIt remembers what fixed it last time
Every run with findings is kept as a fingerprint: which patterns fired, in what order, on which target. When something similar happens again, firstsignal says so, with the fix you noted.
- Local and private. One file in your home directory, readable only by you.
- No log text stored. Pattern names, counts, target, time and your note.
- Deterministic. The same two incidents always score the same. No model involved.
$ firstsignal k8s --pod deploy/api -n prod … Seen before 3f9a1c2e 12 days ago on prod/deploy/api (100% similar, critical) Fix noted: raised DB pool size from 10 to 30, added index on orders.customer_id Remembered as 8b21d0aa. When it is fixed: $ firstsignal history note 8b21d0aa "what fixed it"
$ firstsignal history list # what is remembered $ firstsignal history forget 8b21d0aa
Watch it live
watch re-reads a sliding window of logs and prints only what changed: a new finding, a severity change, a finding that cleared, or a match with a past incident.
When you stop it, it writes the usual reports for the worst moment it saw and keeps one history record for the whole session. Run it as a systemd service or a sidecar to keep it going.
$ firstsignal watch k8s --pod deploy/api -n prod Watching prod/deploy/api: last 5 min, checked every 15s. Ctrl+C to stop. 09:41:12 NEW high Connection limit reached x2 09:41:12 SEVERITY none -> high 09:41:31 NEW critical Out of memory x1 09:41:31 SEVERITY high -> critical 09:41:31 SEEN BEFORE 3f9a1c2e, 12 days ago (80% similar) Fix noted: raised DB pool size 09:52:40 CLEARED Connection limit reached
$ firstsignal watch file --path /var/log/app.log --window 10 $ firstsignal watch docker --container my-api --json | jq .
What the report gives you
The terminal shows the essentials. Every run also writes report.md to paste into the incident channel and report.json for pipelines. Add --html for a self-contained dashboard; see an example.
- Four Golden Signals
- Every finding is mapped to latency, traffic, errors or saturation, so you can see which kind of trouble you are in.
- Order of first appearance
- Which pattern showed up first. Earlier ones are likelier causes; later ones are often knock-on effects.
- Severity you can gate on
--fail-on highexits 3, so a post-deploy check or a timer can act on the result.- Checks filled in for you
- Read-only commands with your unit, container or pod already in place. Printed, never run.
- Secrets masked by default
- Passwords, tokens, keys, URL credentials and emails are redacted before anything is written.
- Ten pattern packs
- nginx, PostgreSQL, MySQL, Redis, Kafka, HAProxy, Node.js, Kubernetes and the JVM, plus your own rules in
firstsignal.toml. - Works offline
- No account, no agent, and no network calls unless you pass
--ai. One runtime dependency, Python 3.10 to 3.13. - Fits in CI
- JSON output and exit codes make it a post-deploy smoke check: fail the job when a deploy starts throwing errors.
AI is optional, and it only explains
Everything above works offline. Pass --ai with your own Anthropic or OpenAI-compatible key, or point it at a local Ollama model, and the report gains up to three ranked hypotheses.
The answer is labeled unverified. Nothing a model returns is ever executed.
- Finding counts and severities
- Order of first appearance
- Up to two redacted example lines per finding
- Top repeating lines, redacted
- The raw log
- Lines that matched nothing
- Anything at all with
--no-redact - Anything at all without
--ai
export ANTHROPIC_API_KEY=...
firstsignal k8s --pod deploy/api -n prod --ai
# fully local, no key
firstsignal file --path app.log --ai \
--ai-provider ollama --ai-model llama3.1What it does not do
Correlate and explain, never auto-act. That is a design rule, and a test enforces it.
- It never restarts, deletes, scales or edits anything.
- Detection is rule-based. It recognizes known failure signatures; it does not understand your application.
- Order of appearance is a lead to check, not proof of cause.
- It reads logs only: no metrics, traces or deploy history.
- Redaction is pattern-based and cannot promise to catch every secret.