Integrations

The Raven Python module also comes with integration for some commonly used libraries to automatically capture errors from common environments. This means that once you have such an integration configured you typically do not need to report errors manually.

Some integrations allow specifying these in a standard configuration, otherwise they are generally passed upon instantiation of the Sentry client.

Bottle

Bottle is a microframework for Python. Raven supports this framework through the WSGI integration.

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

Setup

The first thing you’ll need to do is to disable catchall in your Bottle app:

Copied
import bottle

app = bottle.app()
app.catchall = False

Sentry will then act as Middleware:

Copied
from raven import Client
from raven.contrib.bottle import Sentry
client = Client('https://examplePublicKey@o0.ingest.sentry.io/0')
app = Sentry(app, client)

Usage

Once you’ve configured the Sentry application you need only call run with it:

Copied
run(app=app)

If you want to send additional events, a couple of shortcuts are provided on the Bottle request app object.

Capture an arbitrary exception by calling captureException:

Copied
try:
    1 / 0
except ZeroDivisionError:
    request.app.sentry.captureException()

Log a generic message with captureMessage:

Copied
request.app.sentry.captureMessage('Hello, world!')

Celery

Celery is a distributed task queue system for Python built on AMQP principles. For Celery built-in support by Raven is provided but it requires some manual configuration.

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

Setup

To capture errors, you need to register a couple of signals to hijack Celery error handling:

Copied
from raven import Client
from raven.contrib.celery import register_signal, register_logger_signal

client = Client('https://examplePublicKey@o0.ingest.sentry.io/0')

# register a custom filter to filter out duplicate logs
register_logger_signal(client)

# The register_logger_signal function can also take an optional argument
# `loglevel` which is the level used for the handler created.
# Defaults to `logging.ERROR`
register_logger_signal(client, loglevel=logging.INFO)

# hook into the Celery error handler
register_signal(client)

# The register_signal function can also take an optional argument
# `ignore_expected` which causes exception classes specified in Task.throws
# to be ignored
register_signal(client, ignore_expected=True)

A more complex version to encapsulate behavior:

Copied
import celery
import raven
from raven.contrib.celery import register_signal, register_logger_signal

class Celery(celery.Celery):

    def on_configure(self):
        client = raven.Client('https://examplePublicKey@o0.ingest.sentry.io/0')

        # register a custom filter to filter out duplicate logs
        register_logger_signal(client)

        # hook into the Celery error handler
        register_signal(client)

app = Celery(__name__)
app.config_from_object('django.conf:settings')

Django

Django versions 1.4 to 2.0 are supported. Since this SDK is being phased out, newer versions of Django are only supported by the new Python SDK.

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

Setup

Using the Django integration is as simple as adding raven.contrib.django.raven_compat to your installed apps:

Copied
INSTALLED_APPS = (
    'raven.contrib.django.raven_compat',
)

This causes Raven to install a hook in Django that will automatically report uncaught exceptions.

Additional settings for the client are configured using the RAVEN_CONFIG dictionary:

Copied
import os
import raven

RAVEN_CONFIG = {
    'dsn': 'https://examplePublicKey@o0.ingest.sentry.io/0',
    # If you are using git, you can also automatically configure the
    # release based on the git info.
    'release': raven.fetch_git_sha(os.path.abspath(os.pardir)),
}

Once you’ve configured the client, you can test it using the standard Django management interface:

Copied
python manage.py raven test

You’ll be referencing the client slightly differently in Django as well:

Copied
from raven.contrib.django.raven_compat.models import client

client.captureException()

Using with Raven.js

A Django template tag is provided to render a proper public DSN inside your templates, you must first load raven:

Copied
{% load raven %}

Inside your template, you can now use:

Copied
<script>
  Raven.config("{% sentry_public_dsn %}").install();
</script>

By default, the DSN is generated in a protocol relative fashion, e.g. //public@example.com/1. If you need a specific protocol, you can override:

Copied
{% sentry_public_dsn 'https' %}

See the Raven.js documentation for more information.

Integration with logging

To integrate with the standard library’s logging module, and send all ERROR and above messages to sentry, the following config can be used:

Copied
LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'root': {
        'level': 'WARNING',
        'handlers': ['sentry'],
    },
    'formatters': {
        'verbose': {
            'format': '%(levelname)s  %(asctime)s  %(module)s '
                      '%(process)d  %(thread)d  %(message)s'
        },
    },
    'handlers': {
        'sentry': {
            'level': 'ERROR', # To capture more than ERROR, change to WARNING, INFO, etc.
            'class': 'raven.contrib.django.raven_compat.handlers.SentryHandler',
            'tags': {'custom-tag': 'x'},
        },
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose'
        }
    },
    'loggers': {
        'django.db.backends': {
            'level': 'ERROR',
            'handlers': ['console'],
            'propagate': False,
        },
        'raven': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
        'sentry.errors': {
            'level': 'DEBUG',
            'handlers': ['console'],
            'propagate': False,
        },
    },
}

Usage

Logging usage works the same way as it does outside of Django, with the addition of an optional request key in the extra data:

Copied
logger.error('There was some crazy error', exc_info=True, extra={
    # Optionally pass a request and we'll grab any information we can
    'request': request,
})

404 Logging

In certain conditions you may wish to log 404 events to the Sentry server. To do this, you simply need to enable a Django middleware:

Copied
# Use ``MIDDLEWARE_CLASSES`` prior to Django 1.10
MIDDLEWARE = (
    'raven.contrib.django.raven_compat.middleware.Sentry404CatchMiddleware',
    ...,
) + MIDDLEWARE

It is recommended to put the middleware at the top, so that only 404s that bubbled all the way up get logged. Certain middlewares (e.g. flatpages) capture 404s and replace the response.

It is also possible to configure this middleware to ignore 404s on particular pages by defining the IGNORABLE_404_URLS setting as an iterable of regular expression patterns. If any pattern produces a match against the full requested URL (as defined by the regular expression’s search method), then the 404 will not be reported to Sentry.

Copied
import re

IGNORABLE_404_URLS = (
    re.compile('/foo'),
)

Message References

Sentry supports sending a message ID to your clients so that they can be tracked easily by your development team. There are two ways to access this information, the first is via the X-Sentry-ID HTTP response header. Adding this is as simple as appending a middleware to your stack:

Copied
# Use ``MIDDLEWARE_CLASSES`` prior to Django 1.10
MIDDLEWARE = MIDDLEWARE + (
  # We recommend putting this as high in the chain as possible
  'raven.contrib.django.raven_compat.middleware.SentryResponseErrorIdMiddleware',
  ...,
)

Another alternative method is rendering it within a template. By default, Sentry will attach request.sentry when it catches a Django exception. In our example, we will use this information to modify the default 500.html which is rendered, and show the user a case reference ID. The first step in doing this is creating a custom handler500() in your urls.py file:

Copied
from django.conf.urls.defaults import *

from django.views.defaults import page_not_found, server_error
from django.template.response import TemplateResponse

def handler500(request):
    """500 error handler which includes ``request`` in the context.

 Templates: `500.html`
 Context: None
 """

    context = {'request': request}
    template_name = '500.html'  # You need to create a 500.html template.
    return TemplateResponse(request, template_name, context, status=500)

Once we’ve successfully added the request context variable, adding the Sentry reference ID to our 500.html is simple:

Copied
<p>You've encountered an error, oh noes!</p>
{% if request.sentry.id %}
<p>
  If you need assistance, you may reference this error as
  <strong>{{ request.sentry.id }}</strong>.
</p>
{% endif %}

WSGI Middleware

If you are using a WSGI interface to serve your app, you can also apply a middleware which will ensure that you catch errors even at the fundamental level of your Django application:

Copied
from raven.contrib.django.raven_compat.middleware.wsgi import Sentry
from django.core.wsgi import get_wsgi_application

application = Sentry(get_wsgi_application())

User Feedback

To enable user feedback for crash reports, start with ensuring the request value is available in your context processors:

Copied
TEMPLATE_CONTEXT_PROCESSORS = (
    # ...
    'django.core.context_processors.request',
)

By default Django will render 500.html, so simply drop the following snippet into your template:

Copied
<!-- Sentry JS SDK 2.1.+ required -->
<script src="https://cdn.ravenjs.com/2.3.0/raven.min.js"></script>

{% if request.sentry.id %}
<script>
  Raven.showReportDialog({
    eventId: "{{ request.sentry.id }}",

    // use the public DSN (don't include your secret!)
    dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
  });
</script>
{% endif %}

That’s it!

For more details on this feature, see the User Feedback guide.

Additional Settings

SENTRY_CLIENT
In some situations you may wish for a slightly different behavior to how Sentry communicates with your server. For this, Raven allows you to specify a custom client:

Copied
SENTRY_CLIENT = 'raven.contrib.django.raven_compat.DjangoClient'

SENTRY_CELERY_LOGLEVEL
If you are also using Celery, there is a handler being automatically registered for you that captures the errors from workers. The default logging level for that handler is logging.ERROR and can be customized using this setting:

Copied
SENTRY_CELERY_LOGLEVEL = logging.INFO

Alternatively you can use a similarly named key in RAVEN_CONFIG:

Copied
RAVEN_CONFIG = {
    'CELERY_LOGLEVEL': logging.INFO
}

SENTRY_CELERY_IGNORE_EXPECTED
If you are also using Celery, then you can ignore expected exceptions by setting this to True. This will cause exception classes in Task.throws to be ignored.

Caveats

The following things you should keep in mind when using Raven with Django.

Error Handling Middleware

If you already have middleware in place that handles process_exception() you will need to take extra care when using Sentry.

For example, the following middleware would suppress Sentry logging due to it returning a response:

Copied
class MyMiddleware(object):
    def process_exception(self, request, exception):
        return HttpResponse('foo')

To work around this, you can either disable your error handling middleware, or add something like the following:

Copied
from django.core.signals import got_request_exception

class MyMiddleware(object):
    def process_exception(self, request, exception):
        # Make sure the exception signal is fired for Sentry
        got_request_exception.send(sender=self, request=request)
        return HttpResponse('foo')

Or, alternatively, you can just enable Sentry responses:

Copied
from raven.contrib.django.raven_compat.models import sentry_exception_handler

class MyMiddleware(object):
    def process_exception(self, request, exception):
        # Make sure the exception signal is fired for Sentry
        sentry_exception_handler(request=request)
        return HttpResponse('foo')

Circus

If you are running Django with circus and chaussette you will also need to add a hook to circus to activate Raven:

Copied
from django.conf import settings
from django.core.management import call_command

def run_raven(*args, **kwargs):
    """Set up raven for django by running a django command.
 It is necessary because chaussette doesn't run a django command.
 """
    if not settings.configured:
        settings.configure()

    call_command('validate')
    return True

And in your circus configuration:

Copied
[socket:dwebapp]
host = 127.0.0.1
port = 8080

[watcher:dwebworker]
cmd = chaussette --fd $(circus.sockets.dwebapp) dproject.wsgi.application
use_sockets = True
numprocesses = 2
hooks.after_start = dproject.hooks.run_raven

Flask

Installation

If you haven’t already, install raven with its explicit Flask dependencies:

Copied
pip install raven[flask]

Setup

The first thing you’ll need to do is to initialize Raven under your application:

Copied
from raven.contrib.flask import Sentry
sentry = Sentry(app, dsn='https://examplePublicKey@o0.ingest.sentry.io/0')

If you don’t specify the dsn value, we will attempt to read it from your environment under the SENTRY_DSN key.

Extended Setup

You can optionally configure logging too:

Copied
import logging
from raven.contrib.flask import Sentry
sentry = Sentry(app, logging=True, level=logging.ERROR, \
                logging_exclusions=("logger1", "logger2", ...))

Building applications on the fly? You can use Raven’s init_app hook:

Copied
sentry = Sentry(dsn='http://public_key:secret_key@example.com/1')

def create_app():
    app = Flask(__name__)
    sentry.init_app(app)
    return app

You can pass parameters in the init_app hook:

Copied
sentry = Sentry()

def create_app():
    app = Flask(__name__)
    sentry.init_app(app, dsn='https://examplePublicKey@o0.ingest.sentry.io/0', logging=True,
                    level=logging.ERROR,
                    logging_exclusions=("logger1", "logger2", ...))
    return app

Settings

Additional settings for the client can be configured using SENTRY_CONFIG in your application’s configuration:

Copied
class MyConfig(object):
    SENTRY_CONFIG = {
        'dsn': 'https://examplePublicKey@o0.ingest.sentry.io/0',
        'include_paths': ['myproject'],
        'release': raven.fetch_git_sha(os.path.dirname(__file__)),
    }

If Flask-Login is used by your application (including Flask-Security), user information will be captured when an exception or message is captured. By default, only the id (current_user.get_id()), is_authenticated, and is_anonymous is captured for the user. If you would like additional attributes on the current_user to be captured, you can configure them using SENTRY_USER_ATTRS:

Copied
class MyConfig(object):
    SENTRY_USER_ATTRS = ['username', 'first_name', 'last_name', 'email']

email will be captured as sentry.interfaces.User.email, and any additional attributes will be available under sentry.interfaces.User.data

You can specify the types of exceptions that should not be reported by Sentry client in your application by setting the ignore_exceptions configuration value:

Copied
class MyExceptionType(Exception):
    def __init__(self, message):
        super(MyExceptionType, self).__init__(message)

app = Flask(__name__)
app.config['SENTRY_CONFIG'] = {
    'ignore_exceptions': [MyExceptionType],
}

Usage

Once you’ve configured the Sentry application it will automatically capture uncaught exceptions within Flask. If you want to send additional events, a couple of shortcuts are provided on the Sentry Flask middleware object.

Capture an arbitrary exception by calling captureException:

Copied
try:
    1 / 0
except ZeroDivisionError:
    sentry.captureException()

Log a generic message with captureMessage:

Copied
sentry.captureMessage('hello, world!')

Getting The Last Event ID

If possible, the last Sentry event ID is stored in the request context g.sentry_event_id variable. This allow to present the user an error ID if have done a custom error 500 page.

Copied
<h2>Error 500</h2>
{% if g.sentry_event_id %}
<p>The error identifier is {{ g.sentry_event_id }}</p>
{% endif %}

User Feedback

To enable user feedback for crash reports just make sure you have a custom 500 error handler and render out a HTML snippet for bringing up the crash dialog:

Copied
from flask import Flask, g, render_template
from raven.contrib.flask import Sentry

app = Flask(__name__)
sentry = Sentry(app, dsn='https://examplePublicKey@o0.ingest.sentry.io/0')

@app.errorhandler(500)
def internal_server_error(error):
    return render_template('500.html',
        event_id=g.sentry_event_id,
        public_dsn=sentry.client.get_public_dsn('https')
    )

And in the error template (500.html) you can then do this:

Copied
<!-- Sentry JS SDK 2.1.+ required -->
<script src="https://cdn.ravenjs.com/2.3.0/raven.min.js"></script>

{% if event_id %}
<script>
  Raven.showReportDialog({
    eventId: "{{ event_id }}",
    dsn: "{{ public_dsn }}",
  });
</script>
{% endif %}

That’s it!

For more details on this feature, see the User Feedback guide.

Dealing With Proxies

When your Flask application is behind a proxy such as nginx, Sentry will use the remote address from the proxy, rather than from the actual requesting computer. By using ProxyFix from werkzeug.contrib.fixers the Flask .wsgi_app can be modified to send the actual REMOTE_ADDR along to Sentry.

Copied
from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app)

This may also require changes to the proxy configuration to pass the right headers if it isn’t doing so already.

Signals

Raven uses blinker to emit a signal (called logging_configured) after logging has been configured for the client. You may bind to that signal in your application to do any additional configuration to the logging handler SentryHandler.

Copied
from raven.contrib.flask import Sentry, logging_configured
from flask import Flask, g, render_template
from raven.contrib.flask import Sentry

app = Flask(__name__)
sentry = Sentry(app, dsn='https://examplePublicKey@o0.ingest.sentry.io/0', logging=True)

@logging_configured.connect
def internal_server_error(sender, sentry_handler=None, **kwargs):
    # configure sentry_handler here
    sentry_handler.addFilter(some_filter)

Amazon Web Services Lambda

Installation

To use Sentry with AWS Lambda, you have to install raven as an external dependency. This involves creating a Deployment package and uploading it to AWS.

To install raven into your current project directory:

Copied
pip install raven -t /path/to/project-dir

Setup

Create a LambdaClient instance and wrap your lambda handler with the capture_exceptions decorator:

Copied
from raven.contrib.awslambda import LambdaClient

client = LambdaClient()

@client.capture_exceptions
def handler(event, context):
    ...
    raise Exception('I will be sent to sentry!')

By default this will report unhandled exceptions and errors to Sentry.

The LambdaClient accepts the same arguments as the regular Client, see Configuring the Client.

The integration was inspired by raven python lambda, another implementation that also integrates with Serverless Framework and has SQS transport support.

Logbook

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

Setup

Raven provides a logbook handler which will pipe messages to Sentry.

First you’ll need to configure a handler:

Copied
from raven.handlers.logbook import SentryHandler

# Manually specify a client
client = Client(...)
handler = SentryHandler(client)

You can also automatically configure the default client with a DSN:

Copied
# Configure the default client
handler = SentryHandler('https://examplePublicKey@o0.ingest.sentry.io/0')

Finally, bind your handler to your context:

Copied
from raven.handlers.logbook import SentryHandler

client = Client(...)
sentry_handler = SentryHandler(client)
with sentry_handler.applicationbound():
    # everything logged here will go to sentry.
    ...

Logging

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

Setup

Sentry supports the ability to directly tie into the logging module. To use it simply add SentryHandler to your logger.

First you’ll need to configure a handler:

Copied
from raven.handlers.logging import SentryHandler

# Manually specify a client
client = Client(...)
handler = SentryHandler(client)

You can also automatically configure the default client with a DSN:

Copied
# Configure the default client
handler = SentryHandler('https://examplePublicKey@o0.ingest.sentry.io/0')

You may want to specify the logging level at this point so you don’t send INFO or DEBUG messages to Sentry:

Copied
handler.setLevel(logging.ERROR)

Finally, call the setup_logging() helper function:

Copied
from raven.conf import setup_logging

setup_logging(handler)

Another option is to use logging.config.dictConfig:

Copied
LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,

    'formatters': {
        'console': {
            'format': '[%(asctime)s][%(levelname)s] %(name)s '
                      '%(filename)s:%(funcName)s:%(lineno)d | %(message)s',
            'datefmt': '%H:%M:%S',
            },
        },

    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'console'
            },
        'sentry': {
            'level': 'ERROR',
            'class': 'raven.handlers.logging.SentryHandler',
            'dsn': 'https://examplePublicKey@o0.ingest.sentry.io/0',
            },
        },

    'loggers': {
        '': {
            'handlers': ['console', 'sentry'],
            'level': 'DEBUG',
            'propagate': False,
            },
        'your_app': {
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

Usage

A recommended pattern in logging is to simply reference the modules name for each logger, so for example, you might at the top of your module define the following:

Copied
import logging
logger = logging.getLogger(__name__)

You can also use the exc_info and extra={'stack': True} arguments on your log methods. This will store the appropriate information and allow Sentry to render it based on that information:

Copied
# If you're actually catching an exception, use `exc_info=True`
logger.error('There was an error, with a stack trace!', exc_info=True)

# If you don't have an exception, but still want to capture a
# stack trace, use the `stack` arg
logger.error('There was an error, with a stack trace!', extra={
    'stack': True,
})

While we don’t recommend this, you can also enable implicit stack capturing for all messages:

Copied
client = Client(..., auto_log_stacks=True)
handler = SentryHandler(client)

logger.error('There was an error, with a stack trace!')

Passing tags and user context is also available through extra:

Copied
logger.error('There was an error, with user context and tags'), extra={
    'user': {'email': 'test@test.com'},
    'tags': {'database': '1.0'},
})

You may also pass additional information to be stored as meta information with the event. As long as the key name is not reserved and not private (_foo) it will be displayed on the Sentry dashboard. To do this, pass it as data within your extra clause:

Copied
logger.error('There was some crazy error', exc_info=True, extra={
    # Optionally you can pass additional arguments to specify request info
    'culprit': 'my.view.name',
    'fingerprint': [...],

    'data': {
        # You may specify any values here and Sentry will log and output them
        'username': request.user.username,
    }
})

The url and view keys are used internally by Sentry within the extra data.

Any key (in data) prefixed with _ will not automatically output on the Sentry details view.

Sentry will intelligently group messages if you use proper string formatting. For example, the following messages would be seen as the same message within Sentry:

Copied
logger.error('There was some %s error', 'crazy')
logger.error('There was some %s error', 'fun')
logger.error('There was some %s error', 1)

Exclusions

You can also configure some logging exclusions during setup. These loggers will not propagate their logs to the Sentry handler:

Copied
from raven.conf import setup_logging

setup_logging(handler, exclude=("logger1", "logger2", ...))

Pylons

Pylons is a framework for Python.

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

WSGI Middleware

A Pylons-specific middleware exists to enable easy configuration from settings:

Copied
from raven.contrib.pylons import Sentry

application = Sentry(application, config)

Configuration is handled via the sentry namespace:

Copied
[sentry]
dsn=https://examplePublicKey@o0.ingest.sentry.io/0
include_paths=my.package,my.other.package,
exclude_paths=my.package.crud

Logger setup

Add the following lines to your project’s .ini file to setup SentryHandler:

Copied
[loggers]
keys = root, sentry

[handlers]
keys = console, sentry

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console, sentry

[logger_sentry]
level = WARN
handlers = console
qualname = sentry.errors
propagate = 0

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[handler_sentry]
class = raven.handlers.logging.SentryHandler
args = ('SENTRY_DSN',)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

You may want to set up other loggers as well.

Pyramid

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

PasteDeploy Filter

A filter factory for PasteDeploy exists to allow easily inserting Raven into a WSGI pipeline:

Copied
[pipeline:main]
pipeline =
 raven
 tm
 MyApp

[filter:raven]
use = egg:raven#raven
dsn = https://examplePublicKey@o0.ingest.sentry.io/0
include_paths = my.package, my.other.package
exclude_paths = my.package.crud

In the [filter:raven] section, you must specify the entry-point for raven with the use = key. All other raven client parameters can be included in this section as well.

See the Pyramid PasteDeploy Configuration Documentation for more information.

Logger setup

Add the following lines to your project’s .ini file to setup SentryHandler:

Copied
[loggers]
keys = root, sentry

[handlers]
keys = console, sentry

[formatters]
keys = generic

[logger_root]
level = INFO
handlers = console, sentry

[logger_sentry]
level = WARN
handlers = console
qualname = sentry.errors
propagate = 0

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[handler_sentry]
class = raven.handlers.logging.SentryHandler
args = ('https://examplePublicKey@o0.ingest.sentry.io/0',)
level = WARNING
formatter = generic

[formatter_generic]
format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

You may want to setup other loggers as well. See the Pyramid Logging Documentation for more information.

Instead of defining the DSN in the .ini file you can also use the environment variable SENTRY_DSN which overwrites the setting in this file. Because of a syntax check you cannot remove the args setting completely, as workaround you can define an empty list of arguments args = ().

RQ

Starting with RQ version 0.3.1, support for Sentry has been built in.

Usage

RQ natively supports binding with Sentry by passing your SENTRY_DSN through rqworker:

Copied
rqworker --sentry-dsn="https://examplePublicKey@o0.ingest.sentry.io/0"

Extended Setup

If you want to pass additional information, such as release, you’ll need to bind your own instance of the Sentry Client:

Copied
from raven import Client
from raven.transport.http import HTTPTransport
from rq.contrib.sentry import register_sentry

client = Client('https://examplePublicKey@o0.ingest.sentry.io/0', transport=HTTPTransport)
register_sentry(client, worker)

Please see rq‘s documentation for more information: python-rq.org/patterns/sentry/

Tornado

Tornado is an async web framework for Python.

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

Setup

The first thing you’ll need to do is to initialize sentry client under your application

Copied
import tornado.web
from raven.contrib.tornado import AsyncSentryClient

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")

application = tornado.web.Application([
    (r"/", MainHandler),
])
application.sentry_client = AsyncSentryClient(
    'https://examplePublicKey@o0.ingest.sentry.io/0'
)

Usage

Once the sentry client is attached to the application, request handlers can automatically capture uncaught exceptions by inheriting the SentryMixin class.

Copied
import tornado.web
from raven.contrib.tornado import SentryMixin

class UncaughtExceptionExampleHandler(
        SentryMixin, tornado.web.RequestHandler):
    def get(self):
        1/0

You can also send events manually using the shortcuts defined in SentryMixin. The shortcuts can be used for both asynchronous and synchronous usage.

Asynchronous

Copied
import tornado.web
import tornado.gen
from raven.contrib.tornado import SentryMixin

class AsyncMessageHandler(SentryMixin, tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.engine
    def get(self):
        self.write("You requested the main page")
        yield tornado.gen.Task(
            self.captureMessage, "Request for main page served"
        )
        self.finish()

class AsyncExceptionHandler(SentryMixin, tornado.web.RequestHandler):
    @tornado.web.asynchronous
    @tornado.gen.engine
    def get(self):
        try:
            raise ValueError()
        except Exception as e:
            response = yield tornado.gen.Task(
                self.captureException, exc_info=True
            )
        self.finish()

Synchronous

Copied
import tornado.web
from raven.contrib.tornado import SentryMixin

class AsyncExampleHandler(SentryMixin, tornado.web.RequestHandler):
    def get(self):
        self.write("You requested the main page")
        self.captureMessage("Request for main page served")

WSGI Middleware

Raven includes a simple to use WSGI middleware.

Copied
from raven import Client
from raven.middleware import Sentry

application = Sentry(
    application,
    Client('https://examplePublicKey@o0.ingest.sentry.io/0')
)

Many frameworks will not propagate exceptions to the underlying WSGI middleware by default.

ZConfig logging configuration

ZConfig provides a configuration mechanism for the Python logging module.

To learn more, see:

zconfig.readthedocs.io/en/latest/using-logging.html

To use with sentry, use the sentry handler tag:

Copied
<logger>
  level INFO
  <logfile>
   path ${buildout:directory}/var/{:_buildout_section_name_}.log
   level INFO
  </logfile>

  %import raven.contrib.zconfig
  <sentry>
    dsn https://examplePublicKey@o0.ingest.sentry.io/0
    level ERROR
  </sentry>
</logger>

This configuration retains normal logging to a logfile, but adds Sentry logging for ERRORs.

All options of raven.base.Client are supported.

ZeroRPC

ZeroRPC is a light-weight, reliable and language-agnostic library for distributed communication between server-side processes.

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

Setup

The ZeroRPC integration comes as middleware for ZeroRPC. The middleware can be configured like the original Raven client (using keyword arguments) and registered into ZeroRPC’s context manager:

Copied
import zerorpc

from raven.contrib.zerorpc import SentryMiddleware

sentry = SentryMiddleware(dsn='https://examplePublicKey@o0.ingest.sentry.io/0')
zerorpc.Context.get_instance().register_middleware(sentry)

By default, the middleware will hide internal frames from ZeroRPC when it submits exceptions to Sentry. This behavior can be disabled by passing the hide_zerorpc_frames parameter to the middleware:

Copied
sentry = SentryMiddleware(hide_zerorpc_frames=False, dsn='https://examplePublicKey@o0.ingest.sentry.io/0')

Compatibility

  • ZeroRPC-Python < 0.4.0 is compatible with Raven <= 3.1.0;
  • ZeroRPC-Python >= 0.4.0 requires Raven > 3.1.0.

Zope/Plone

Installation

If you haven’t already, start by downloading Raven. The easiest way is with pip:

Copied
pip install raven --upgrade

zope.conf

Zope has extensible logging configuration options. A basic instance (not ZEO client) setup for logging looks like this:

Copied
<eventlog>
  level INFO
  <logfile>
   path ${buildout:directory}/var/{:_buildout_section_name_}.log
   level INFO
  </logfile>

  %import raven.contrib.zope
  <sentry>
    dsn https://examplePublicKey@o0.ingest.sentry.io/0
    level ERROR
  </sentry>
</eventlog>

This configuration retains normal logging to a logfile, but adds Sentry logging for ERRORs.

All options of raven.base.Client are supported.

Use a buildout recipe instead of editing zope.conf directly. To add the equivalent instance configuration, you would do this:

Copied
[instance]
recipe = plone.recipe.zope2instance
...
event-log-custom =
 %import raven.contrib.zope
 <logfile>
 path ${buildout:directory}/var/instance.log
 level INFO
 </logfile>
 <sentry>
 dsn https://examplePublicKey@o0.ingest.sentry.io/0
 level ERROR
 </sentry>

To add the equivalent ZEO client configuration, you would do this:

Copied
[instance]
recipe = plone.recipe.zope2instance
...
event-log-custom =
 %import raven.contrib.zope
 <logfile>
 path ${buildout:var-dir}/${:_buildout_section_name_}/event.log
 level INFO
 </logfile>
 <sentry>
 dsn https://examplePublicKey@o0.ingest.sentry.io/0
 level ERROR
 </sentry>