Integrations
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 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 is a microframework for Python. Raven supports this framework through the WSGI integration.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
The first thing you’ll need to do is to disable catchall in your Bottle app:
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:
from raven import Client
from raven.contrib.bottle import Sentry
client = Client('https://examplePublicKey@o0.ingest.sentry.io/0')
app = Sentry(app, client)
Once you’ve configured the Sentry application you need only call run with it:
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
:
try:
1 / 0
except ZeroDivisionError:
request.app.sentry.captureException()
Log a generic message with captureMessage
:
request.app.sentry.captureMessage('Hello, world!')
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.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
To capture errors, you need to register a couple of signals to hijack Celery error handling:
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:
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 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.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
Using the Django integration is as simple as adding raven.contrib.django.raven_compat
to your installed apps:
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:
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:
python manage.py raven test
You’ll be referencing the client slightly differently in Django as well:
from raven.contrib.django.raven_compat.models import client
client.captureException()
A Django template tag is provided to render a proper public DSN inside your templates, you must first load raven
:
{% load raven %}
Inside your template, you can now use:
<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:
{% sentry_public_dsn 'https' %}
See the Raven.js documentation for more information.
To integrate with the standard library’s logging
module, and send all ERROR and above messages to Sentry, the following config can be used:
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,
},
},
}
Logging usage works the same way as it does outside of Django, with the addition of an optional request
key in the extra data:
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,
})
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:
# 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.
import re
IGNORABLE_404_URLS = (
re.compile('/foo'),
)
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:
# 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:
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:
<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 %}
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:
from raven.contrib.django.raven_compat.middleware.wsgi import Sentry
from django.core.wsgi import get_wsgi_application
application = Sentry(get_wsgi_application())
To enable user feedback for crash reports, start with ensuring the request
value is available in your context processors:
TEMPLATE_CONTEXT_PROCESSORS = (
# ...
'django.core.context_processors.request',
)
By default Django will render 500.html
, so simply drop the following snippet into your template:
<!-- 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.
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:
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:
SENTRY_CELERY_LOGLEVEL = logging.INFO
Alternatively you can use a similarly named key in RAVEN_CONFIG
:
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.
The following things you should keep in mind when using Raven with Django.
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:
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:
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:
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')
If you are running Django with circus and chaussette you will also need to add a hook to circus to activate Raven:
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:
[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
If you haven’t already, install raven with its explicit Flask dependencies:
pip install raven[flask]
The first thing you’ll need to do is to initialize Raven under your application:
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.
You can optionally configure logging too:
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:
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:
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
Additional settings for the client can be configured using SENTRY_CONFIG
in your application’s configuration:
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
:
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:
class MyExceptionType(Exception):
def __init__(self, message):
super(MyExceptionType, self).__init__(message)
app = Flask(__name__)
app.config['SENTRY_CONFIG'] = {
'ignore_exceptions': [MyExceptionType],
}
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
:
try:
1 / 0
except ZeroDivisionError:
sentry.captureException()
Log a generic message with captureMessage
:
sentry.captureMessage('hello, world!')
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.
<h2>Error 500</h2>
{% if g.sentry_event_id %}
<p>The error identifier is {{ g.sentry_event_id }}</p>
{% endif %}
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:
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:
<!-- 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.
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.
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.
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
.
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)
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:
pip install raven -t /path/to/project-dir
Create a LambdaClient instance and wrap your lambda handler with the capture_exceptions decorator:
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.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
Raven provides a logbook handler which will pipe messages to Sentry.
First you’ll need to configure a handler:
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:
# Configure the default client
handler = SentryHandler('https://examplePublicKey@o0.ingest.sentry.io/0')
Finally, bind your handler to your context:
from raven.handlers.logbook import SentryHandler
client = Client(...)
sentry_handler = SentryHandler(client)
with sentry_handler.applicationbound():
# everything logged here will go to sentry.
...
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
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:
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:
# 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:
handler.setLevel(logging.ERROR)
Finally, call the setup_logging()
helper function:
from raven.conf import setup_logging
setup_logging(handler)
Another option is to use logging.config.dictConfig
:
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,
},
}
}
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:
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:
# 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.
While we don’t recommend this, you can also enable implicit stack capturing for all messages:
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:
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:
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:
logger.error('There was some %s error', 'crazy')
logger.error('There was some %s error', 'fun')
logger.error('There was some %s error', 1)
You can also configure some logging exclusions during setup. These loggers will not propagate their logs to the Sentry handler:
from raven.conf import setup_logging
setup_logging(handler, exclude=("logger1", "logger2", ...))
Pylons is a framework for Python.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
A Pylons-specific middleware exists to enable easy configuration from settings:
from raven.contrib.pylons import Sentry
application = Sentry(application, config)
Configuration is handled via the sentry namespace:
[sentry]
dsn=https://examplePublicKey@o0.ingest.sentry.io/0
include_paths=my.package,my.other.package,
exclude_paths=my.package.crud
Add the following lines to your project’s .ini file to setup SentryHandler:
[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.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
A filter factory for PasteDeploy exists to allow easily inserting Raven into a WSGI pipeline:
[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.
Add the following lines to your project’s .ini file to setup SentryHandler:
[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 = ()
.
Starting with RQ version 0.3.1, support for Sentry has been built in.
RQ natively supports binding with Sentry by passing your SENTRY_DSN
through rqworker
:
rqworker --sentry-dsn="https://examplePublicKey@o0.ingest.sentry.io/0"
If you want to pass additional information, such as release
, you’ll need to bind your own instance of the Sentry Client
:
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 is an async web framework for Python.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
The first thing you’ll need to do is to initialize Sentry client under your application
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'
)
Once the Sentry client is attached to the application, request handlers can automatically capture uncaught exceptions by inheriting the SentryMixin class.
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.
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.
Copiedfrom raven.contrib.tornado import SentryMixin app.sentry_client = AsyncSentryClient(dsn) BaseHandler.__bases__ = (SentryMixin, ) + BaseHandler.__bases__
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")
Raven includes a simple to use WSGI middleware.
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 provides a configuration mechanism for the Python logging module.
To learn more, see:
To use with Sentry, use the Sentry handler tag:
<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 is a light-weight, reliable and language-agnostic library for distributed communication between server-side processes.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
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:
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:
sentry = SentryMiddleware(hide_zerorpc_frames=False, dsn='https://examplePublicKey@o0.ingest.sentry.io/0')
- ZeroRPC-Python < 0.4.0 is compatible with Raven <= 3.1.0;
- ZeroRPC-Python >= 0.4.0 requires Raven > 3.1.0.
If you haven’t already, start by downloading Raven. The easiest way is with pip:
pip install raven --upgrade
Zope has extensible logging configuration options. A basic instance (not ZEO client) setup for logging looks like this:
<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:
[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:
[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>
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").