error-logging-agent
A plug-n-play AI error-triage agent for Python. It captures every error traceback, asks an LLM to explain it (what caused it, which files are involved, and how a human might fix it), and reports the result to Slack and JIRA.
It never fixes your code. By design, the agent only diagnoses and advises — a human applies the fix. There is no code path that edits files or runs commands.
This is Version A: a deterministic pipeline (capture → LLM → dedup → notify). It's built so the "analyze" step can later be upgraded to an agentic investigator (reading repo files, git blame, etc.) without touching the rest.
Install
pip install error_logging_agent-1.0.0-py3-none-any.whl # from the built wheel
# or, from source: pip install . (add -e for editable/dev)
Requires Python 3.9+. Dependencies are light: requests, pydantic, PyYAML.
Ollama, Groq, Slack, and JIRA are all reached over plain HTTP — no heavy SDKs.
How configuration & Ollama work (read this first)
This package is a client, not a host. It does not run Ollama and it does not own your environment — the application that installs it does. You point the library at services that already exist. Configuration resolves in this order (highest priority first):
- Arguments to
install()— inline overrides in code - Environment variables — the usual way to supply secrets/endpoints in prod
- A
config.yaml— if you passconfig_path=or setERROR_AGENT_CONFIG - Built-in defaults
A .env file in the working directory is auto-loaded (no extra dependency), so
local dev "just works" without exporting anything.
Ollama
Ollama runs as a separate service you already operate — the library only makes HTTP calls to it. Nothing about installing this package installs or starts Ollama. You tell the library where it is and which model to use:
export LLM_PROVIDER=ollama
export OLLAMA_BASE_URL=http://localhost:11434 # or a remote host
export OLLAMA_MODEL=qwen2.5-coder:7b # any model you've `ollama pull`ed
If Ollama lives on another machine, just point OLLAMA_BASE_URL at it. If you'd
rather use the hosted Groq fallback instead of (or in addition to) Ollama, set
GROQ_API_KEY and select it — see below.
All recognized environment variables
| Variable | Purpose |
|---|---|
LLM_PROVIDER |
ollama (default) or groq |
OLLAMA_BASE_URL |
Ollama server URL (default http://localhost:11434) |
OLLAMA_MODEL |
Ollama model name (default qwen2.5-coder:7b) |
GROQ_API_KEY |
Groq key (enables the cloud provider) |
GROQ_MODEL |
Groq model (e.g. openai/gpt-oss-120b) |
SLACK_WEBHOOK_URL |
Slack incoming webhook (simplest) |
SLACK_BOT_TOKEN + SLACK_CHANNEL |
Slack bot posting (alternative) |
JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN, JIRA_PROJECT_KEY |
JIRA Cloud |
ERROR_AGENT_ENV, ERROR_AGENT_SERVICE |
environment / service labels |
ERROR_AGENT_CONFIG |
path to a config.yaml |
Configure entirely in code (no YAML needed)
Everything can be passed to install() — handy when your app already has its own
settings system:
import error_logging_agent
error_logging_agent.install(
service="smarthub",
environment="production",
llm={
"primary": {"kind": "ollama", "model": "qwen2.5-coder:7b",
"base_url": "http://localhost:11434"},
"fallback": {"kind": "groq", "model": "openai/gpt-oss-120b"}, # api_key via GROQ_API_KEY
},
slack={"enabled": True}, # webhook via SLACK_WEBHOOK_URL
jira={"enabled": True, "base_url": "https://yourorg.atlassian.net",
"project_key": "SHA"}, # email/token via env
)
Secrets (webhook, JIRA token, Groq key) are best left in environment variables even when configuring in code — the library reads them automatically.
Turn it on (one line)
import error_logging_agent
error_logging_agent.install() # reads config.yaml / env vars
From that point on:
- any uncaught exception (main thread, other threads, process crash) is captured
- anything sent via
logger.exception(...)/logger.error(..., exc_info=True)is captured - you can also report manually:
error_logging_agent.report_exception(customer_id="acct_123")
Everything runs on a background worker, so your app is never blocked waiting on the LLM, and a failure inside the agent can never crash your app.
Configure
Copy src/error_logging_agent/config.example.yaml to config.yaml, then either set
ERROR_SENTINEL_CONFIG=/path/to/config.yaml or call
install(config_path="config.yaml"). Secrets are best passed via env vars:
| Env var | Purpose |
|---|---|
GROQ_API_KEY |
Groq API key (for the cloud fallback provider) |
SLACK_BOT_TOKEN + SLACK_CHANNEL |
Slack bot posting (preferred) |
SLACK_WEBHOOK_URL |
Slack incoming webhook (simplest alternative) |
JIRA_BASE_URL, JIRA_EMAIL, JIRA_API_TOKEN, JIRA_PROJECT_KEY |
JIRA Cloud |
LLM providers (plug-n-play)
The LLM layer is provider-agnostic. Pick a primary and an optional fallback:
llm:
primary: # local & private — recommended default
kind: ollama
model: qwen2.5-coder:7b
base_url: http://localhost:11434
fallback: # used automatically if primary errors/times out
kind: groq
model: openai/gpt-oss-120b # api_key via GROQ_API_KEY
Switching Ollama ↔ Groq is a config change, never a code change. Adding a new
provider (OpenAI, Anthropic, …) is one small subclass of LLMProvider.
Testing — from zero-setup to full integration
Level 0 — unit tests (no services, ~1s). Proves the capture → fingerprint → dedup → analyze → notify logic and the FastAPI middleware:
pip install -e ".[dev]"
pytest -q
Level 1 — dry-run selftest (no Slack/JIRA needed). Fires a synthetic error and prints the analysis to your terminal. With Ollama down you'll see an "analysis unavailable" block (proves the plumbing); with Ollama up you'll see a real diagnosis:
# start Ollama and pull a model first, e.g.:
ollama serve & # if not already running
ollama pull qwen2.5-coder:7b
error-logging-agent --config config.yaml selftest --dry-run
dry_run: true (or a bare install with no notifier configured) routes results to
the console notifier, so you can iterate on models/prompts before touching Slack.
Level 2 — real Slack (still no JIRA). In config.yaml set slack.enabled: true
and export SLACK_WEBHOOK_URL (or SLACK_BOT_TOKEN + SLACK_CHANNEL), then:
error-logging-agent --config config.yaml selftest
A formatted message should land in your channel.
Level 3 — FastAPI end to end. Run the example app and trigger a route error:
uvicorn examples.fastapi_app:app --port 8000
curl http://localhost:8000/boom # 500 to the client; triage in your logs/Slack
Test dedup: hit /boom (or run selftest) several times quickly — you should
get exactly one notification, with the occurrence count rising on repeats.
How it works
exception ──► capture (fast, non-blocking) ──► queue ──► worker
│
scrub secrets ─► fingerprint ─► dedup/rate-limit ─► LLM analyze ─► notify
├─ JIRA (create/update)
└─ Slack (Block Kit)
Key design points:
- Dedup + rate-limiting first. The same bug is fingerprinted (exception type + normalized stack) so repeats collapse into one ticket/alert. A per-minute cap stops error storms from flooding Slack/JIRA. Dedup runs before the LLM, so you also don't re-pay to analyze the same error.
- Secret scrubbing. Emails, API keys, tokens, and card numbers are redacted before anything reaches a cloud LLM or JIRA. Local Ollama is the default so tracebacks can stay entirely on your infrastructure.
- Graceful degradation. If the LLM is unreachable, you still get the raw traceback reported with an "analysis unavailable" note. If a notifier fails, the worker keeps running.
- No auto-fix. The
Analysismodel has no field for a patch or command. The agent describes a fix; a human applies it.
Module map
| File | Responsibility |
|---|---|
__init__.py |
public API: install, report_exception, shutdown |
capture.py |
logging handler + excepthooks → ErrorEvent |
worker.py |
background thread + queue (swap for Redis/RQ later) |
pipeline.py |
scrub → fingerprint → dedup → analyze → notify |
analyzer.py |
prompt + provider call + JSON validation + fallback |
providers/ |
OllamaProvider, GroqProvider behind one interface |
notifiers/ |
SlackNotifier, JiraNotifier |
dedup.py |
SQLite fingerprint store + rate limiter |
fingerprint.py |
stable hashing of errors |
scrub.py |
PII/secret redaction |
config.py |
YAML + env config schema |
FastAPI integration (SmartHub)
The logging handler already covers any app using standard logging, but the
FastAPI integration adds request context (method, path, client, safe headers)
to every captured error. Two lines at startup:
from fastapi import FastAPI
import error_logging_agent
from error_logging_agent.integrations.fastapi import instrument
app = FastAPI()
error_logging_agent.install() # start the sentinel (reads config/env)
instrument(app) # capture request errors + context, then re-raise
The middleware is pure ASGI: it never touches successful responses, and on an
unhandled error it reports to the sentinel and then re-raises, so FastAPI's
normal 500 handling is completely unchanged. Only an allow-list of headers is
captured (user-agent, x-request-id, …) — Authorization/Cookie are never
collected. See examples/fastapi_app.py.
Other frameworks follow the same pattern (Django middleware / got_request_exception,
Flask @app.errorhandler) — call error_logging_agent.report_exception(**context).
Running without JIRA (Slack-only)
JIRA is off by default — you don't need a project key to start. With
jira.enabled: false (or simply omitting the block), errors are analyzed and
posted to Slack only. When you're ready for tickets, create a JIRA project (its
key is the short prefix in issue ids, e.g. SMART-123 → key SMART), then
set jira.enabled: true with base_url / project_key and the token env vars.
Nothing else changes.
Roadmap to Version B (agentic)
The Analyzer is the single seam to upgrade. Replace its one-shot LLM call with a
tool-using loop (read the files named in the traceback, run git blame, search past
errors) and the rest of the pipeline — capture, dedup, Slack, JIRA — stays exactly
the same.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file error_logging_agent-1.0.0.tar.gz.
File metadata
- Download URL: error_logging_agent-1.0.0.tar.gz
- Upload date:
- Size: 32.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac451aa21b8500119dcfd218e8d514b73862092b5d7f0508b6f25af9efa4629a
|
|
| MD5 |
0ae5136775f7b558a018f0f395835526
|
|
| BLAKE2b-256 |
84e2bf82e3d86377aa16ccac1e6950137c726452e54959910d7bc29e077a6522
|
File details
Details for the file error_logging_agent-1.0.0-py3-none-any.whl.
File metadata
- Download URL: error_logging_agent-1.0.0-py3-none-any.whl
- Upload date:
- Size: 34.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e45212dcd9ddafce40797c516d6f07e3bc7df515d4ad0cc5f8fb80bcda65a726
|
|
| MD5 |
a5796cc2d68823973e901416df31dd7e
|
|
| BLAKE2b-256 |
a2df5e3b2055ccf1f2ce30f94e27a20fcca173967e6b544d2f90c2a396016535
|