Skip to main content

Sentry-style Slack (+ optional SendGrid email) error reporting for Python — Lambda + servers + scripts.

Project description

self-sentry

Sentry-style Slack error reporting for Python — works in AWS Lambda, FastAPI/Django servers, plain scripts, anywhere.

One init() call per project, then:

  • @report_errors() decorator catches uncaught exceptions and posts to Slack.
  • Global hooks (sys.excepthook, threading.excepthook, asyncio loop handler) catch anything you forgot to wrap.
  • Lambda timeout watchdog posts a warning ~1s before your function times out (the silent-kill case Lambda gives you nothing for).
  • Manual notify(...) for ad-hoc info/success/error messages.

Install

pip install git+ssh://git@github.com/Ad-Leverage/self-sentry.git@v0.1.0

Pin to a tag, not a branch — that's what makes reproducible Lambda builds work.

Quickstart

import os
import self_sentry

self_sentry.init(
    token=os.environ["SLACK_BOT_TOKEN"],
    channel="#my-project-alerts",
    service_name="my-service",
)

@self_sentry.report_errors()
def lambda_handler(event, context):
    ...

self_sentry.notify("Booking succeeded", fields={"booking_id": 42}, status=0)

Env-driven init (good for Lambdas that already hydrate secrets)

Set SLACK_BOT_TOKEN, SLACK_CHANNEL, and SERVICE_NAME (and optionally the email vars below), then:

self_sentry.init_from_env()

No-op (with a warning) if any of the three required vars is missing — safe to call unconditionally at app startup.

Email alerts (optional, via SendGrid)

Slack is always the primary destination. To also email an alert, configure SendGrid at init() and opt in per call with send_email=True:

self_sentry.init(
    token=os.environ["SLACK_BOT_TOKEN"],
    channel="#my-project-alerts",
    service_name="my-service",
    sendgrid_api_key=os.environ["SENDGRID_API_KEY"],
    email_from="alerts@my-co.com",
    email_to="oncall@my-co.com,backend@my-co.com",   # comma-separated string or a list
)

# Slack only (default):
self_sentry.notify("Heads up", status=3)

# Slack + email:
self_sentry.notify("Cookie expired", status=1, fields={"builder_id": 106609}, send_email=True)
self_sentry.report_exception(exc, send_email=True)

@self_sentry.report_errors(send_email=True)   # email uncaught exceptions too
def lambda_handler(event, context): ...

init_from_env() reads the same from SENDGRID_API_KEY, ALERT_EMAIL_FROM, and ALERT_EMAIL_TO. Email is sent through SendGrid's v3/mail/send REST API over stdlib urllibno extra dependency. The email body mirrors the Slack alert's message + fields (and, for report_exception, the full traceback).

If send_email=True is requested but email creds are absent (or recipients parse to empty), nothing is emailed — the Slack post still goes out and a warning is logged. Email failures are swallowed like Slack failures and never break business code.

What gets reported

Source Fires when
@report_errors() The wrapped function raises (re-raised after reporting).
sys.excepthook Uncaught exception kills the main thread.
threading.excepthook Uncaught exception in a threading.Thread.
asyncio loop handler Uncaught exception in a Task / call_soon callback. (Installed lazily on the first running loop.)
Lambda timeout watchdog context.get_remaining_time_in_millis() drops below timeout_warning_buffer_ms (default 1000).

Configuration

self_sentry.init(
    token="xoxb-...",                # required
    channel="#alerts",               # required
    service_name="my-service",       # shows up as Slack author_name
    install_excepthook=True,
    install_threading_hook=True,
    install_asyncio_hook=True,
    lambda_timeout_warning=True,
    timeout_warning_buffer_ms=1000,
)

One bot, one channel. If you need to post to multiple destinations, call notify(..., channel="#other") explicitly at the call site.

If init() is never called, every reporting function is a silent no-op — safe to leave decorators and notify() calls in code that runs locally without Slack creds.

Status codes (Slack color)

status Color Use
0 green success
1 orange error (default for report_exception)
2 grey debug
3 purple info (default for notify)

Local dev

pip install -e ".[dev]"
pytest -q
ruff check src tests
mypy src/self_sentry

Manual smoke test against a real Slack workspace:

LIVE_SLACK_TOKEN=xoxb-... LIVE_SLACK_CHANNEL='#test' python -m tests.smoke.send_real

Release

Tag-based; no PyPI.

git tag v0.1.0 && git push --tags

Bump the @vX.Y.Z pin in consumer projects to upgrade.

Caveats

  • The asyncio handler is installed lazily on the first running loop observed (via @report_errors or report_exception). Exceptions on a loop that runs before that first call are not captured. Fine for typical FastAPI/Mangum/Lambda layouts.
  • The Lambda timeout watchdog uses a threading.Timer. It is always cancelled in the decorator's finally so it cannot leak across invocations — but if you reach inside and start a watchdog yourself, don't outlive the handler scope.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

self_sentry-0.5.0.tar.gz (12.5 kB view details)

Uploaded Source

Built Distribution

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

self_sentry-0.5.0-py3-none-any.whl (14.4 kB view details)

Uploaded Python 3

File details

Details for the file self_sentry-0.5.0.tar.gz.

File metadata

  • Download URL: self_sentry-0.5.0.tar.gz
  • Upload date:
  • Size: 12.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for self_sentry-0.5.0.tar.gz
Algorithm Hash digest
SHA256 03e6ece44aefc14ed0fd6667c371886a42f3796b508741ee8b412e8f3b4f6e7a
MD5 47897b59c0baa062c7cd3f25d2d17d34
BLAKE2b-256 5d0bf72a3891af8f325183cd49ff8b112b972ddba5907ffa55f7bfca39264ecc

See more details on using hashes here.

File details

Details for the file self_sentry-0.5.0-py3-none-any.whl.

File metadata

  • Download URL: self_sentry-0.5.0-py3-none-any.whl
  • Upload date:
  • Size: 14.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.9

File hashes

Hashes for self_sentry-0.5.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fafac9df3a0e954ac908c71d9e21f248aee278d50e71754f46fcb95cfa5adc74
MD5 270bb6b5e4fbc6f9013a154580373e08
BLAKE2b-256 84ae98a50d50a73735924568b41d16c6ef58261257c9c1000f5896e63b89d665

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 Pingdom Monitoring Sentry Error logging StatusPage Status page