---
title: "Integrations"
url: https://docs.sentry.io/platforms/python/legacy-sdk/integrations/
---

# Integrations | Sentry for Python

##### Deprecation Warning

A new Python SDK has superseded this deprecated version. Sentry preserves this documentation for customers using the old client. We recommend using the [updated Python SDK](https://docs.sentry.io/platforms/python.md) for new projects.

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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#bottle)

[Bottle](https://bottlepy.org/) is a microframework for Python. Raven supports this framework through the WSGI integration.

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation)

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

```bash
pip install raven --upgrade
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup)

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

```python
import bottle

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

##### Note

Bottle will not propagate exceptions to the underlying WSGI middleware by default. Setting catchall to False disables that.

Sentry will then act as Middleware:

```python
from raven import Client
from raven.contrib.bottle import Sentry
client = Client('___DSN___')
app = Sentry(app, client)
```

### [Usage](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#usage)

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

```python
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`:

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

Log a generic message with `captureMessage`:

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

## [Celery](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#celery)

[Celery](https://docs.celeryq.dev/) 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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-1)

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

```bash
pip install raven --upgrade
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-1)

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

```python
from raven import Client
from raven.contrib.celery import register_signal, register_logger_signal

client = Client('___DSN___')

# 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:

```python
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('___DSN___')

        # 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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#django)

[Django](https://djangoproject.com/) 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](https://docs.sentry.io/platforms/python.md).

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-2)

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

```bash
pip install raven --upgrade
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-2)

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

```python
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:

```python
import os
import raven

RAVEN_CONFIG = {
    'dsn': '___DSN___',
    # 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:

```bash
python manage.py raven test
```

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

```python
from raven.contrib.django.raven_compat.models import client

client.captureException()
```

### [Using with Raven.js](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#using-with-ravenjs)

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

```django
{% load raven %}
```

Inside your template, you can now use:

```html
<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:

```html
{% sentry_public_dsn 'https' %}
```

See the [*Raven.js documentation*](https://docs.sentry.io/platforms/javascript/legacy-sdk.md) for more information.

### [Integration with `logging`](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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:

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#usage-1)

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

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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:

```python
# 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.

```python
import re

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

### [Message References](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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:

```python
# 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:

```python
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:

```html
<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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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:

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#user-feedback)

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

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

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

```html
<!-- 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: "___PUBLIC_DSN___",
  });
</script>
{% endif %}
```

That’s it!

For more details on this feature, see the [*User Feedback guide*](https://docs.sentry.io/platforms/python/user-feedback.md).

### [Additional Settings](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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:

```python
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:

```python
SENTRY_CELERY_LOGLEVEL = logging.INFO
```

Alternatively you can use a similarly named key in `RAVEN_CONFIG`:

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#caveats)

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

#### [Error Handling Middleware](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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:

```python
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:

```python
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')
```

##### Note

This technique may break unit tests using the Django test client (`django.test.client.Client`) if a view under test generates a `Http404` or `PermissionDenied` exception, because the exceptions won’t be translated into the expected 404 or 403 response codes.

Or, alternatively, you can just enable Sentry responses:

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#circus)

If you are running Django with [circus](https://circus.rtfd.org/) and [chaussette](https://chaussette.readthedocs.io/) you will also need to add a hook to circus to activate Raven:

```python
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:

```ini
[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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#flask)

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-3)

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

```bash
pip install raven[flask]
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-3)

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

```python
from raven.contrib.flask import Sentry
sentry = Sentry(app, dsn='___DSN___')
```

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

### [Extended Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#extended-setup)

You can optionally configure logging too:

```python
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:

```python
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:

```python
sentry = Sentry()

def create_app():
    app = Flask(__name__)
    sentry.init_app(app, dsn='___DSN___', logging=True,
                    level=logging.ERROR,
                    logging_exclusions=("logger1", "logger2", ...))
    return app
```

### [Settings](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#settings)

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

```python
class MyConfig(object):
    SENTRY_CONFIG = {
        'dsn': '___DSN___',
        'include_paths': ['myproject'],
        'release': raven.fetch_git_sha(os.path.dirname(__file__)),
    }
```

If [Flask-Login](https://pypi.python.org/pypi/Flask-Login/) is used by your application (including [Flask-Security](https://pypi.python.org/pypi/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`:

```python
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:

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

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

### [Usage](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#usage-2)

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`:

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

Log a generic message with `captureMessage`:

```python
sentry.captureMessage('hello, world!')
```

### [Getting The Last Event ID](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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.

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

### [User Feedback](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#user-feedback-1)

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:

```python
from flask import Flask, g, render_template
from raven.contrib.flask import Sentry

app = Flask(__name__)
sentry = Sentry(app, dsn='___DSN___')

@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:

```html
<!-- 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*](https://docs.sentry.io/platforms/python/user-feedback.md).

### [Dealing With Proxies](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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.

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

This may also require [changes](https://flask.palletsprojects.com/en/1.1.x/deploying/wsgi-standalone/#proxy-setups) to the proxy configuration to pass the right headers if it isn’t doing so already.

### [Signals](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#signals)

Raven uses [blinker](https://github.com/jek/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`.

```python
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='___DSN___', 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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#amazon-web-services-lambda)

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-4)

To use [Sentry](https://getsentry.com/) with [AWS Lambda](https://aws.amazon.com/lambda), you have to install *raven* as an external dependency. This involves creating a [Deployment package](https://docs.aws.amazon.com/lambda/latest/dg/lambda-python-how-to-create-deployment-package.html) and uploading it to AWS.

To install raven into your current project directory:

```shell
pip install raven -t /path/to/project-dir
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-4)

Create a *LambdaClient* instance and wrap your lambda handler with the *capture\_exceptions* decorator:

```python
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*](https://docs.sentry.io/platforms/python/legacy-sdk/advanced.md#python-client-config).

The integration was inspired by [raven python lambda](https://github.com/Netflix-Skunkworks/raven-python-lambda), another implementation that also integrates with Serverless Framework and has SQS transport support.

## [Logbook](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#logbook)

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-5)

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

```bash
pip install raven --upgrade
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-5)

Raven provides a [logbook](https://logbook.readthedocs.io) handler which will pipe messages to Sentry.

First you’ll need to configure a handler:

```python
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:

```python
# Configure the default client
handler = SentryHandler('___DSN___')
```

Finally, bind your handler to your context:

```python
from raven.handlers.logbook import SentryHandler

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

## [Logging](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#logging)

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-6)

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

```bash
pip install raven --upgrade
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-6)

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:

```python
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:

```python
# Configure the default client
handler = SentryHandler('___DSN___')
```

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

```python
handler.setLevel(logging.ERROR)
```

Finally, call the `setup_logging()` helper function:

```python
from raven.conf import setup_logging

setup_logging(handler)
```

Another option is to use `logging.config.dictConfig`:

```python
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': '___DSN___',
            },
        },

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

#### [Usage](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#usage-3)

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:

```python
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:

```python
# 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,
})
```

##### Note on Python version

Depending on the version of Python you’re using, `extra` might not be an acceptable keyword argument for a logger’s `.exception()` method (`.debug()`, `.info()`, `.warning()`, `.error()` and `.critical()` should work fine regardless of Python version). This should be fixed as of Python 2.7.4 and 3.2. Official issue here: [bugs.python.org/issue15541](https://bugs.python.org/issue15541).

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

```python
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:

```python
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:

```python
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:

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#exclusions)

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

```python
from raven.conf import setup_logging

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

## [Pylons](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#pylons)

Pylons is a framework for Python.

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-7)

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

```bash
pip install raven --upgrade
```

### [WSGI Middleware](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#wsgi-middleware-1)

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

```python
from raven.contrib.pylons import Sentry

application = Sentry(application, config)
```

Configuration is handled via the sentry namespace:

```ini
[sentry]
dsn=___DSN___
include_paths=my.package,my.other.package,
exclude_paths=my.package.crud
```

### [Logger setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#logger-setup)

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

```ini
[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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#pyramid)

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-8)

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

```bash
pip install raven --upgrade
```

### [PasteDeploy Filter](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#pastedeploy-filter)

A filter factory for [PasteDeploy](https://pastedeploy.readthedocs.io/en/latest/) exists to allow easily inserting Raven into a WSGI pipeline:

```ini
[pipeline:main]
pipeline =
 raven
 tm
 MyApp

[filter:raven]
use = egg:raven#raven
dsn = ___DSN___
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](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/paste.html) for more information.

### [Logger setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#logger-setup-1)

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

```ini
[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 = ('___DSN___',)
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](https://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html) 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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#rq)

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

### [Usage](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#usage-4)

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

```bash
rqworker --sentry-dsn="___DSN___"
```

### [Extended Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#extended-setup-1)

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

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

client = Client('___DSN___', transport=HTTPTransport)
register_sentry(client, worker)
```

Please see `rq`‘s documentation for more information: [python-rq.org/patterns/sentry/](https://python-rq.org/patterns/sentry/)

## [Tornado](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#tornado)

Tornado is an async web framework for Python.

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-9)

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

```bash
pip install raven --upgrade
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-7)

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

```python
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(
    '___DSN___'
)
```

### [Usage](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#usage-5)

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

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#asynchronous)

```python
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()
```

##### Tip

The value returned by the yield is a `HTTPResponse` object.

To dynamically use Python if configuration DSN available, change your base handler on fly and make sure all concrete handlers are imported after this.

> ```python
> from raven.contrib.tornado import SentryMixin
> app.sentry_client = AsyncSentryClient(dsn)
> BaseHandler.__bases__ = (SentryMixin, ) + BaseHandler.__bases__
> ```

#### [Synchronous](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#synchronous)

```python
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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#wsgi-middleware-2)

Raven includes a simple to use WSGI middleware.

```python
from raven import Client
from raven.middleware import Sentry

application = Sentry(
    application,
    Client('___DSN___')
)
```

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

## [ZConfig logging configuration](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#zconfig-logging-configuration)

[ZConfig](https://zconfig.readthedocs.io/en/latest/using-logging.html) provides a configuration mechanism for the Python logging module.

To learn more, see:

> [zconfig.readthedocs.io/en/latest/using-logging.html](https://zconfig.readthedocs.io/en/latest/using-logging.html)

To use with Sentry, use the Sentry handler tag:

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

  %import raven.contrib.zconfig
  <sentry>
    dsn ___DSN___
    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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#zerorpc)

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

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-10)

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

```bash
pip install raven --upgrade
```

### [Setup](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#setup-8)

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:

```python
import zerorpc

from raven.contrib.zerorpc import SentryMiddleware

sentry = SentryMiddleware(dsn='___DSN___')
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:

```python
sentry = SentryMiddleware(hide_zerorpc_frames=False, dsn='___DSN___')
```

### [Compatibility](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#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](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#zopeplone)

### [Installation](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#installation-11)

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

```bash
pip install raven --upgrade
```

### [zope.conf](https://docs.sentry.io/platforms/python/legacy-sdk/integrations.md#zopeconf)

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

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

  %import raven.contrib.zope
  <sentry>
    dsn ___DSN___
    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:

```bash
[instance]
recipe = plone.recipe.zope2instance
...
event-log-custom =
 %import raven.contrib.zope
 <logfile>
 path ${buildout:directory}/var/instance.log
 level INFO
 </logfile>
 <sentry>
 dsn ___DSN___
 level ERROR
 </sentry>
```

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

```bash
[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 ___DSN___
 level ERROR
 </sentry>
```
