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 urllib — no 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_errorsorreport_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'sfinallyso 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
Release history Release notifications | RSS feed
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03e6ece44aefc14ed0fd6667c371886a42f3796b508741ee8b412e8f3b4f6e7a
|
|
| MD5 |
47897b59c0baa062c7cd3f25d2d17d34
|
|
| BLAKE2b-256 |
5d0bf72a3891af8f325183cd49ff8b112b972ddba5907ffa55f7bfca39264ecc
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fafac9df3a0e954ac908c71d9e21f248aee278d50e71754f46fcb95cfa5adc74
|
|
| MD5 |
270bb6b5e4fbc6f9013a154580373e08
|
|
| BLAKE2b-256 |
84ae98a50d50a73735924568b41d16c6ef58261257c9c1000f5896e63b89d665
|