octri (Python)
Error and performance monitoring for Python backends. Report errors out of
Flask, FastAPI, or Django with original-source context per stack frame, time
every request into a waterfall, and join each server error to the client SDK
error for the same request through the W3C traceparent header. In the
dashboard you see the full client and server stack under one trace.
Octri turns an OpenAPI spec into a documentation site, client SDKs for ten languages, an MCP server your AI assistant can call, and monitoring for the API behind them. This package is the Python monitoring runtime, and it works on its own: a generated Octri API SDK is not required. See octri.dev/monitoring.
Python 3.8 or newer. Pure standard library, with no required dependencies. The
Python sibling of @octri/node.
Install
pip install octri
Setup
from octri import init
init(
url="https://monitoring.example.com", # your monitoring base URL
token=os.environ["OCTRI_TOKEN"], # your project ingest token
environment="<your project id>", # the dashboard project id
release=os.environ.get("GIT_SHA"), # optional
)
Hosted users can copy the project-scoped URL, token, and environment from the
Monitoring connection settings (or its API). Pass token=None only when
pointing at an open self-hosted ingest endpoint. Every request carries an
idempotency key.
Standalone events
No generated API SDK is required to send your own events:
from octri import capture_event
capture_event(
"checkout.completed",
user={"id": customer.id},
tags={"region": "eu-west", "plan": "growth"},
context={"order_id": order.id, "total": order.total},
)
Delivery is best-effort and happens off the calling thread. Pass event_id to
make a retried delivery idempotent.
Flask
from octri.flask import octri_flask
app = Flask(__name__)
octri_flask(app) # observes unhandled request exceptions; nothing else to wire
FastAPI / Starlette
from octri.fastapi import OctriMiddleware
app = FastAPI()
app.add_middleware(OctriMiddleware) # reports unhandled 500s, then re-raises
Django
# settings.py, after calling init(...) somewhere at startup
MIDDLEWARE = [
# ...
"octri.django.OctriMiddleware",
]
How linking works
The Octri client SDK sends a traceparent header on every request. Each
integration reads it, captures the failing exception (with source context for
each in-app frame), and reports it tagged octri.origin=server under the same
traceId, so the client SDK error and this server error appear as one linked
trace in the dashboard.
For compiled/minified clients, the dashboard pairs this with source maps / source bundles; the Python server frames already carry their original source inline.
Spans & the request waterfall
The middleware times each request. To see where time goes inside it, let Octri instrument common I/O automatically, or open spans yourself.
Automatic
octri.auto_instrument() # traces requests + urllib (outbound HTTP)
octri.instrument(cursor, ["execute"], op="db") # your own DB client / util module, once
octri.instrument(cache, ["get", "set"], op="cache")
@octri.traced(op="fn")
def compute_totals(orders): ...
Every instrumented call (and every outbound HTTP request) becomes a sub-span under the current request, with no per-call code. Calls to your monitoring backend are never traced (no feedback loop).
Manual
with octri.span("orders.list", op="db"):
rows = db.query(sql)
s = octri.start_span("render", op="view")
# ...work...
s.finish()
op ("db", "cache", "http", and so on) color-codes the bar in the dashboard waterfall.
Manual capture
from octri import capture_error, trace_from_header
try:
...
except Exception as exc:
capture_error(exc, trace=trace_from_header(request.headers.get("traceparent")))
raise
What gets redacted
Payloads are scrubbed on the way out, so a credential that ended up in a log line or a context object never reaches the dashboard.
Any key whose name looks like a credential (password, secret, token,
apiKey, authorization, cookie, ssn and the rest of the usual list) has
its value replaced with [redacted], at any depth. Matching ignores case and
separators, so api_key, apiKey and X-API-KEY are all the same key.
Free text is swept too: the message, an error message and its stack, and
anything else you send as a string. Bearer tokens, JWTs, card numbers and email
addresses come out as [redacted]. A card number has to pass the Luhn check
first, so an order number or a timestamp survives.
user is the exception. It is the field you fill with an identity on purpose,
so user.email is reported exactly as you set it. Credential-shaped keys inside
it are still redacted.
Add your own key names:
octri.add_scrub_fields("account_number", "otp")
Or take the payload yourself, and return None to drop the event:
octri.set_before_send(lambda payload: None if payload.get("path") == "/health" else payload)
Redaction runs after your hook, so a hook cannot leak a credential by accident.
The rest of Octri
| Product | What it does |
|---|---|
| API Studio | Your OpenAPI spec becomes a hosted documentation site with a live request playground, editable page by page. |
| SDK Studio | The same spec becomes client libraries for ten languages, versioned and released together. |
| MCP | Your endpoints and docs become tools an AI assistant can call, generated from the same spec. |
| Monitoring | Errors, traces, uptime and releases for the API, joined to the SDK calls that reached it. |
Monitoring runtimes
More
MIT licensed.
Metadata
Release files for octri 1.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| octri-1.2.0.tar.gz | 21.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| octri-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 38.3 kB
Release files / octri-1.2.0.tar.gz
| Download URL | octri-1.2.0.tar.gz |
|---|---|
| Size | 21.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
baa070cfe242ed90a0219a2045f61e295a18f9dc0d0e623d190ad5ecc9bc1baf
|
|
BLAKE2b-256 checksum How to use checksums |
50c0d8fa04f3d9a23a4f6d4106099cd5cae5fd369538257c0a914fee1a846c7b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / octri-1.2.0-py3-none-any.whl
| Download URL | octri-1.2.0-py3-none-any.whl |
|---|---|
| Size | 17.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
85d61c63d6834b7db5b48e76d017bdf2c862df7b760419fe56dced2cdcb03744
|
|
BLAKE2b-256 checksum How to use checksums |
8ebcbf1683bb278906404a983455c6fce36c3f084985d5d53e30cbc4b16c8b39
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|