Python
The Python SDK targets Python 3.8+ and uses only the standard library — no requests, no httpx, no transitive deps. It installs a sys.excepthook and a threading.excepthook at init time so unhandled exceptions on the main thread and worker threads are captured automatically.
init() — see Frameworks below to enable automatic 500-error capture for FastAPI, Flask, and Django in one line.
Install
$ pip install tinymonpy
Or pin it in requirements.txt / pyproject.toml:
tinymonpy==0.4.1
init()
Call init() once, at the very top of your app's entry point:
import os import tinymonpy tinymonpy.init( dsn=os.environ['TINYMON_DSN'], environment='production', release=os.environ.get('RELEASE'), # e.g. git short SHA, set at deploy sample_rate=1.0, )
Arguments
| Argument | Type | Description |
|---|---|---|
| dsn | str | Required. The project DSN, e.g. tm_pub_…. |
| endpoint | str | None | Override the ingest URL. Defaults to https://console.tinymon.dev/api/ingest. |
| environment | str | None | Free-form tag — production, staging, etc. |
| release | str | None | Version string for your app. Powers release tracking (first-seen-in-release, regression detection) and scopes source maps. Use the same value at deploy. |
| sample_rate | float | 0 to 1. Default 1.0. |
| before_send | Callable[[dict], dict | None] | Mutate or drop events. Return None to drop. |
Capturing exceptions
import tinymonpy try: risky_thing() except Exception as e: tinymonpy.capture_exception(e) # Or a plain message: tinymonpy.capture_message('cron job took 28 seconds', level='warning')
Levels: 'error', 'warning', 'info'.
Delivery & flush()
Events are sent immediately on a background thread — no batching delay. Failed sends are queued and retried with backoff; successful ones never queue. An atexit hook makes a best-effort flush on shutdown.
In a long-running server you never need to do anything. In a short-lived process — an AWS Lambda handler, a CLI script, a per-job worker — call flush() before it exits so an in-flight send isn't dropped:
import tinymonpy try: run_job() except Exception as e: tinymonpy.capture_exception(e) tinymonpy.flush(timeout=2.0) # seconds; never blocks forever raise
flush(). Serverless / script → call it once before exit. Recipes & mechanics: Delivery & flush() and Transport internals.
User & tag context
tinymonpy.set_user({'id': user.id}) tinymonpy.set_tag('plan', user.plan) tinymonpy.set_tag('tenant_id', str(tenant.id))
Breadcrumbs
Add short notes about what happened before an error. The last 30 are attached to the next event.
import time tinymonpy.add_breadcrumb({ 'timestamp': time.time(), 'category': 'http', 'message': 'POST /api/orders → 500', 'level': 'error', })
Frameworks
The SDK ships built-in middleware so you get automatic 500 capture in one line — no boilerplate class to copy. Pick the one for your stack (TinymonWSGI for WSGI apps, TinymonASGI for async apps).
FastAPI / Starlette
import tinymonpy from fastapi import FastAPI tinymonpy.init(dsn=os.environ['TINYMON_DSN']) app = FastAPI() app.add_middleware(tinymonpy.TinymonFastAPIMiddleware) # that's it
Flask
import tinymonpy from flask import Flask tinymonpy.init(dsn=os.environ['TINYMON_DSN']) app = Flask(__name__) app.wsgi_app = tinymonpy.TinymonWSGI(app.wsgi_app) # wrap the WSGI app
Django
Wrap the WSGI application in wsgi.py:
import tinymonpy from django.core.wsgi import get_wsgi_application tinymonpy.init(dsn=os.environ['TINYMON_DSN']) application = tinymonpy.TinymonWSGI(get_wsgi_application())
Celery / background workers
Capture in the task's on_failure hook or wrap the task body in try/except. The SDK installs a threading.excepthook so untouched worker threads are also covered.