New Python SDK - Feedback wanted

You might have noticed that we have been working on a few “next-generation” SDKs as of recently. A major goal of this cross-language effort is not only to get rid of legacy code, but to actually establish some API design norms across languages, such that e.g. using the JS SDK in your frontend feels rather similar to using the Python one in your backend. See this post for an overview of the new guidelines.

Today we’re announcing the “public alpha” for the new Python SDK, “Sentry-Python”, which ideallly eventually displaces our stable SDK raven-python. Here’s what it can do for now:

  • Exception handling hooks for Flask, Django, Celery
  • Attaches request data from Flask and Django to events
  • Captures all logging messages as breadcrumbs by default

Key differences to raven-python:

Global client object

This code using raven-python…

from raven import Client

client = Client('___DSN___')

try:
    1 / 0
except ZeroDivisionError:
    client.captureException()

…looks like this in Sentry-Python:

from sentry_sdk import init, capture_exception

init("___DSN___")

try:
    1 / 0
except ZeroDivisionError:
    capture_exception()

Inversion of how integrations work

They now truly complement the core client instead of wrapping it in their own API.
For example, if you’re writing a Flask app and want to use raven-python, creating a client like the following is not very useful on its own:

from raven import Client
c = Client(dsn)

So what you do is call raven.contrib.flask.Sentry which sets up the client for you in a way that is actually useful:

from raven.contrib.flask import Sentry
sentry = Sentry(app, dsn='your dsn')

With the new SDK (“Sentry-Python”) we no longer let integrations call the main client. Instead, you initialize the SDK in your Flask app like this:

from sentry_sdk.integrations.flask import FlaskIntegration
from sentry_sdk import init

init("your dsn", integrations=[FlaskIntegration()])

A lot of things are going on here:

  • We exclusively use Flask’s signals to capture exceptions. We don’t need your app object. Sentry-Python is now configured for all apps.
  • There is no loading from app.config at all. Only keyword arguments to init.
  • The client object is global.
  • Calling init without the FlaskIntegration object (therefore creating only a simple client like in raven) does more things out of the box for you: You get breadcrumbs from logging automatically. In contrast to raven, where the Flask and Django integrations have to set up logging for you.

Also capture_exception now truly works everywhere the same way, regardless of integrations. In raven, depending on whether you used Flask or not, you used raven.Client.captureException or raven.contrib.flask.Sentry.captureException. This doesn’t seem too bad, but forwarding such core function calls to the client should not really be the responsibility of the integration. Especially as each integration in raven exposes captureException in a different way, this is slightly annoying.

In Sentry-Python it’s just a global function, because the client is 1. That makes it work the same in any other framework/ecosystem as well.

Scopes

raven-python had a thread-local context where you could attach data and push transactions. Sentry-Python improves on this by introducing scopes: Instead of populating your context and clearing it, you get a context manager:

from sentry_sdk import init, configure_scope, get_current_hub, capture_message

init("___DSN___")
capture_message("I am a normal event without any additional data.")

with get_current_hub().push_scope():
    with configure_scope() as scope:
        scope.user = {"id": 1234}
        
    capture_message("I carry user data.")

capture_message("I, again, don't carry user data.")

Why this additional configure_scope call? Because we want to restrict the duration you have direct access to the scope to as little lines of code as necessary.
In contrast to raven’s contexts scopes can be nested, i.e. you can call push_scope() inside of the with-block again. Inner scopes inherit data from the outer ones.

Feedback requested!

Sentry-Python is still a work in progress. As it does not have a lot of features right now, we need to prioritize on features to port over from Raven. It’s getting there… only with your help though. Tell us (here in the forum or on the GitHub issue tracker) what you need to be able to switch over from Raven. Report issues that you ran into. Help us replace a chunk of legacy code!


1. actually a thread/context-local, like flask.g, flask.request, flask.current_app

1 Like