Skip to main content

Muffin-Sentry

Muffin-Sentry — Sentry integration for the Muffin ASGI framework.

Tests Status PyPI Version Python Versions License


Requirements

  • Python 3.11 - 3.15
  • Muffin
  • sentry-sdk >= 2, < 3

Installation

Install using pip:

pip install muffin-sentry

Usage

from muffin import Application
import muffin_sentry

app = Application("example", SENTRY_DSN="https://<public>@sentry.io/<project_id>")
sentry = muffin_sentry.Plugin(app)

# Add a custom processor (must be sync)
@sentry.processor
def enrich_event(event, hint, request):
    if user := getattr(request, "user", None):
        event["user"] = {"id": str(user.id)}
    return event

# Raise unhandled exception
@app.route("/fail")
async def fail(request):
    raise RuntimeError("Boom")

# Manually capture a message
@app.route("/capture")
async def capture(request):
    sentry.capture_message("Manual log")
    return "OK"

# Update scope manually
@app.route("/scope")
async def tag_scope(request):
    sentry.scope.set_tag("section", "test")
    sentry.capture_exception(Exception("With scope tag"))
    return "OK"

Plugin(app) calls setup() for you. Calling muffin_sentry.Plugin() and then sentry.setup(app) is equivalent.

Configuration

Options are read from the application config with the SENTRY_ prefix (SENTRY_DSN, SENTRY_SDK_OPTIONS, ...), or from environment variables with the {CFG.NAME}_SENTRY_ prefix, MUFFIN_SENTRY_ by default. JSON is parsed for complex values:

export MUFFIN_SENTRY_DSN=https://<public>@sentry.io/<project_id>
export MUFFIN_SENTRY_SDK_OPTIONS='{"environment": "production", "traces_sample_rate": 0.05}'

Environment variables are applied by Muffin before the plugin is set up, so they win over the values passed to Application(...).

  1. Via Muffin application config (recommended):
app = Application(
    "app",
    SENTRY_DSN="https://...",
    SENTRY_SDK_OPTIONS={"traces_sample_rate": 0.5},
)
  1. Or by calling .setup() manually:
sentry.setup(app, dsn="https://...", sdk_options={"traces_sample_rate": 0.5})

Available options:

Name Default value Description
dsn "" Sentry DSN; when empty sentry_sdk.init() is never called
sdk_options {"traces_sample_rate": 0.1, "profiles_sample_rate": 0.0} Keyword arguments for sentry_sdk.init()
ignore_errors () Exception classes the middleware reports no event for

sdk_options is replaced as a whole (no deep merge), so a custom dict has to repeat the defaults you want to keep:

app = Application(
    "app",
    SENTRY_DSN="https://...",
    SENTRY_SDK_OPTIONS={
        "environment": "production",
        "release": "myapp@1.4.2",
        "traces_sample_rate": 0.05,  # 10% default, 0 disables tracing
        "send_default_pii": True,  # send user IPs and headers to Sentry
    },
)

ResponseError (Muffin's 404) and ResponseRedirect (muffin.redirect) are handled by the middleware itself: they are control flow, not failures, so no event is sent and the transaction gets the real status code. ignore_errors is for your own exception classes and compares by exact type.

API

plugin.scope

Property returning the current Sentry Scope (sentry_sdk.get_current_scope()). Inside a request it is the isolation scope created by the middleware, so tags, users and breadcrumbs set there are attached to events captured during that request. Before setup() it returns the global scope; it never raises.

plugin.processor(fn)

Decorator registering an event processor. fn(event, hint, request) is called synchronously from process_data() after the request context (url, query_string, method, headers) has been added to the event. REMOTE_ADDR is added only when send_default_pii is enabled. Return the modified event, or None to keep the event unchanged. Processors are never awaited: an async def processor returns a coroutine that is stored as the event, so keep them synchronous.

plugin.capture_exception(exc) / plugin.capture_message(msg)

Proxies to sentry_sdk.capture_exception() / capture_message(), which do nothing when no Sentry client is active (no dsn configured). The difference from calling the SDK directly is what is attached: the request isolation scope, the plugin's tags (framework, asgi.type), the scope modified by your processors and the active transaction all come along automatically.

plugin.middleware

Runs around every request:

  • opens an isolation scope, clears breadcrumbs, tags framework=muffin and asgi.type (http/websocket/...), and registers the event processor that fills event["request"];
  • starts a Sentry session for the request and ends it when the request is done, which is what release health reports;
  • continues the incoming trace (sentry-trace/baggage headers) and starts a transaction named after the request path with op="{asgi.type}.server", so distributed traces connect the frontend request with backend errors. The event is then renamed after the matched view (module.function), so routes with ids (/users/42) do not create one transaction name per id;
  • sets the HTTP status on the transaction and captures unhandled exceptions, except the classes listed in ignore_errors.

Consequently a request that ends up with ResponseError (Muffin's 404, for example) produces a transaction with status not_found but no error event. Disable tracing by setting traces_sample_rate to 0 in sdk_options.

Notes

  • Event processors must be synchronous functions.
  • Sentry sessions and transactions are handled automatically inside the plugin middleware.
  • sentry_sdk.init() is called only when dsn is set; without it the plugin is a thin no-op.

Bug Tracker

Found a bug or have a feature request? Please open an issue at: https://github.com/klen/muffin-sentry/issues

Contributing

Development happens at: https://github.com/klen/muffin-sentry

Pull requests and suggestions are welcome!

License

Licensed under the MIT license.

Credits

  • Created by klen (Kirill Klenov)

Metadata

Release files for muffin-sentry 2.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for muffin-sentry 2.1.0
File Size Uploaded Provenance Actions
muffin_sentry-2.1.0.tar.gz 6.5 kB Without provenance Details for muffin_sentry-2.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for muffin-sentry 2.1.0
File Interpreter ABI Platform Actions
muffin_sentry-2.1.0-py3-none-any.whl Python 3 none any Details for muffin_sentry-2.1.0-py3-none-any.whl

Total release size: 13.0 kB

Release files / muffin_sentry-2.1.0.tar.gz

Download URL muffin_sentry-2.1.0.tar.gz
Size 6.5 kB
Tags Source
SHA-256 checksum
How to use checksums
340c2d086d30eb6ad8aae955100e69021159641524af3b73ca87ffe09ce64729
BLAKE2b-256 checksum
How to use checksums
d88e6b695fa53efc1bf350a1d0d58dbd488c96db3643e42e743c625dc29cabe9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / muffin_sentry-2.1.0-py3-none-any.whl

Download URL muffin_sentry-2.1.0-py3-none-any.whl
Size 6.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b54b67e4adeac96c0ca47771de383884e4070189f16f3b62f65a41a77ccb6c84
BLAKE2b-256 checksum
How to use checksums
81aa3eb9cfafac6bbc22f998b6d518d84ecacc5167cb833bd145263d7d4bed1a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"26.04","id":"resolute","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for muffin-sentry 2.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

2.1.0 This release

2 release files No provenance

0.0.0

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page