Skip to main content

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):

  1. Arguments to install() — inline overrides in code
  2. Environment variables — the usual way to supply secrets/endpoints in prod
  3. A config.yaml — if you pass config_path= or set ERROR_AGENT_CONFIG
  4. 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 Analysis model 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

error_logging_agent-1.0.0.tar.gz (32.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

error_logging_agent-1.0.0-py3-none-any.whl (34.8 kB view details)

Uploaded Python 3

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

Hashes for error_logging_agent-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ac451aa21b8500119dcfd218e8d514b73862092b5d7f0508b6f25af9efa4629a
MD5 0ae5136775f7b558a018f0f395835526
BLAKE2b-256 84e2bf82e3d86377aa16ccac1e6950137c726452e54959910d7bc29e077a6522

See more details on using hashes here.

File details

Details for the file error_logging_agent-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for error_logging_agent-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e45212dcd9ddafce40797c516d6f07e3bc7df515d4ad0cc5f8fb80bcda65a726
MD5 a5796cc2d68823973e901416df31dd7e
BLAKE2b-256 a2df5e3b2055ccf1f2ce30f94e27a20fcca173967e6b544d2f90c2a396016535

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page