Installation
For Python 2.7 compatibility, please opt for versions up to and including 4.4.0.
Requirements
Raygun4py is known to work with Python 2.7, Python 3.1+, and PyPy environments.
It requires the socket
module to be built with SSL support.
Step 1 - Install raygun4py
Grab the module with pip
:
pip install raygun4py
Step 2 - Test the installation
From the command line, run:
raygun4py test paste_your_api_key_here
This will send a test exception to Raygun.
Step 3 - Set up Crash Reporting
Import the module:
from raygun4py import raygunprovider
Initialize a RaygunSender
:
sender = raygunprovider.RaygunSender("paste_your_api_key_here")
Manually sending exceptions
You may catch and manually send an exception like so:
try:
raise Exception("Example exception")
except:
sender.send_exception()
This must be done in the scope of an except
block for the sender to obtain information about the exception via a call to sys.exc_info()
.
Unhandled exception sending
To automatically send unhandled exceptions, you can provide a callback function to sys.excepthook
:
def handle_exception(exc_type, exc_value, exc_traceback):
sender.send_exception(exc_info=(exc_type, exc_value, exc_traceback))
sys.__excepthook__(exc_type, exc_value, exc_traceback)
sys.excepthook = handle_exception
Note that after sending the exception, we invoke the default sys.__excepthook__
to maintain the expected behavior for unhandled exceptions. This ensures the program terminates as it would without the custom exception handler in place.
Error logging
You can send errors/exceptions via a logger by attaching a RaygunHandler
:
logger = logging.getLogger()
raygun_handler = raygunprovider.RaygunHandler("paste_your_api_key_here")
logger.addHandler(raygun_handler)
A RaygunHandler
can also be instantiated from an existing RaygunSender
:
raygun_handler = raygunprovider.RaygunHandler.from_sender(sender)
It is then recommended to use logger.exception()
or logger.error(exc_info=True)
in the scope of an except
block:
try:
raise Exception("Example exception")
except:
logger.exception("Example logger.exception log")
# Or
logger.error("Example logger.error log", exc_info=True)
Note that using a RaygunHandler
outside the scope of an except
block will not allow it to populate a full stack trace.
Step 4 - Release
Deploy Raygun into your production environment for best results, or raise a test exception. Once we detect your first error event, the Raygun app will automatically update.
Web frameworks
Raygun4py includes dedicated middleware implementations for Django and Flask, as well as generic WSGI frameworks (Tornado, Bottle, Ginkgo, etc.). These are available for both Python 2.7 and Python 3.1+.
Django
To configure Django to automatically send all exceptions that are raised in views to Raygun, add the following to settings.py
:
MIDDLEWARE_CLASSES = (
'raygun4py.middleware.django.Provider'
)
RAYGUN4PY_CONFIG = {
'api_key': 'paste_your_api_key_here'
}
The above configuration is the minimal required setup. The full set of options supported by the provider can be declared in the same way:
RAYGUN4PY_CONFIG = {
'api_key': 'paste_your_api_key_here',
'http_timeout': 10.0,
'proxy': None,
'before_send_callback': None,
'grouping_key_callback': None,
'filtered_keys': [],
'ignored_exceptions': [],
'transmit_global_variables': True,
'transmit_local_variables': True,
'userversion': "Not defined",
'user': None
}
Flask
To attach a request exception handler that enhances reports with Flask-specific environment data, use our middleware flask.Provider
:
from flask import Flask, current_app
from raygun4py.middleware import flask
app = Flask(__name__)
flask.Provider(app, 'paste_your_api_key_here').attach()
The flask.Provider
constructor can also take an optional config
argument. This should be a standard Dict
of supported options, as shown in Advanced configuration below. It also returns the underlying RaygunSender
, which you may decide to use elsewhere.
WSGI
An example using Tornado, which will pick up exceptions that occur in the WSGI pipeline:
from raygun4py.middleware import wsgi
class MainHandler(tornado.web.RequestHandler):
def initialize(self):
raise Exception('init')
def main():
settings = {
'default_handler_class': MainHandler
}
application = tornado.web.Application([
(r"/", MainHandler),
], **settings)
wsgiapp = tornado.wsgi.WSGIAdapter(application)
raygun_wrapped_app = wsgi.Provider(wsgiapp, 'paste_your_api_key_here')
server = wsgiref.simple_server.make_server('', 8888, raygun_wrapped_app)
server.serve_forever()
The wsgi.Provider
constructor can also take an optional config
argument. This should be a standard Dict
of supported options, as shown in Advanced configuration below.
FastAPI
An example using FastAPI, which will pick up exceptions that occur in a FastAPI application:
from fastapi import FastAPI, Response
from raygun4py import raygunprovider
app = FastAPI()
@app.exception_handler(Exception)
async def raygun_exception_handler(request, exc):
client = raygunprovider.RaygunSender('paste_your_api_key_here')
client.send_exception()
return Response("Internal server error", status_code=500)
Note that many frameworks (Tornado, Pryramid, Gevent, etc.) will swallow exceptions that occur within their domain.
Attaching raw HTTP request data
If you are in a web server environment and have HTTP request details available, you can pass these to the sender as a Dict
.
Here is an example of HTTP request details structured in a Dict
:
headers = {
"referer": "localhost",
"user-Agent": "Mozilla"
}
request = {
"headers": headers,
"hostName": "localhost",
"url": "/resource",
"httpMethod": "GET",
"ipAddress": "127.0.0.1",
"queryString": None,
"form": None,
"rawData": None,
}
sender.send_exception(request=request)
Advanced configuration
Initialization options
RaygunSender
accepts a config
Dict
which is used to set options on the provider:
from raygun4py import raygunprovider
client = raygunprovider.RaygunSender('paste_your_api_key_here', config={
'http_timeout': 10.0,
'proxy': None,
'before_send_callback': None,
'grouping_key_callback': None,
'filtered_keys': [],
'ignored_exceptions': [],
'transmit_global_variables': True,
'transmit_local_variables': True,
'userversion': "Not defined",
'user': None
})
If 'transmit_global_variables'
or 'transmit_local_variables'
are set to False
, the corresponding variables will not be sent with exception payloads. 'http_timeout'
controls the maximum time the HTTP request can take when POSTing to the Raygun API, and is of type float
.
Sending functions
Call this function from within an except
block to send the current exception to Raygun:
send_exception(exception, exc_info, user_override, tags, userCustomData, httpRequest)
exception
(Exception
, optional): An exception instance to report.exc_info
(tuple
, optional): A 3-tuple containing exception type, exception instance, and traceback.user_override
(Dict
orstr
, optional): Information about the affected user. If not provided,self.user
will be used.tags
(List
, optional): A list of tags relating to the current context which you can define.userCustomData
(Dict
, optional): A dictionary containing custom key-values also of your choosing.httpRequest
(Dict
, optional): Raw HTTP request data that you wish to include with the report.
You can pass in either of these two exception parameters:
exception
should be a subclass of typeException
. Pass this in if you want to manually transmit anException
object to Raygun.exc_info
should be the 3-tuple obtained fromsys.exc_info
. You can pass in thistuple
if you already intend to use it elsewhere.
note:
If neither exception
or exc_info
are provided, the RaygunSender
will call sys.exc_info()
itself. If this occurs outside the scope of an except
block, the exception information and stack trace will be missing. We recommend using a logger with a RaygunHandler
attached for arbitrary error sending such as this.
Configuration and data functions
filtered_keys(keys)
keys
(List
): List of keys to filter out of the payload.
Filters sensitive data from the payload sent to Raygun. Any matching keys on the top level Raygun message object, or within dictionaries on the top level Raygun message object (including dictionaries nested within dictionaries) will have their value replaced with <filtered>
. Useful for sensitive data like passwords, credit card details, etc.
sender.filtered_keys(keys=['credit_card', 'cv2', 'password'])
ignore_exceptions(exceptions)
exceptions
(List
of strings): List of exception types to ignore.
Exceptions matching any type in this list won't be sent when passed to send_exception
.
on_before_send(callback)
callback
(Function callback): A function accepting one parameter.
Allows mutation of the candidate payload immediately before data is sent to Raygun.
on_grouping_key(callback)
callback
(Function callback): A function accepting an instance of RaygunMessage.
Configures custom grouping logic and should return a string between 1 and 100 characters in length. Refer to Custom grouping logic below for more details.
set_proxy(host, port)
host
(str
): Proxy host.port
(int
): Proxy port.
For configurations behind a proxy, use this function to let Raygun4py route the HTTP request to the Raygun endpoint via the specified proxy.
set_version(version)
version
(str
): SemVer version string.
Attaches a SemVer version to each message sent, visible on the dashboard, enabling exception filtering for a specific version, deployment tracking, etc.
set_user(user_info)
user_info
(Dict
): User data dictionary.
User data, as displayed in the Raygun web app. The dictionary should follow the given structure:
sender.set_user({
'firstName': 'Foo',
'fullName': 'Foo Bar',
'email': 'foo@bar.com',
'isAnonymous': False,
'identifier': 'foo@bar.com'
})
'identifier'
should be a unique key used to identify users (e.g., email address). It helps in determining the count of unique affected users. If anonymity is desired, consider generating and storing a UUID or hashing one or more unique login data fields. Note: string properties on a user have a max length of 255 characters. Users exceeding this limit will not be processed.
Features
Custom Grouping Logic
Raygun4py allows for custom exception grouping, giving you the power to override the default automatic grouping. To implement this, provide a callback function that accepts a RaygunMessage
instance as its sole parameter. This instance, sourced from python[2/3]/raygunmsgs.py
, contains all the error and state data set to be sent to the Raygun API.
How it Works:
- In your callback, inspect the provided
RaygunMessage
. - Decide on the fields you want to group by and formulate a grouping key by hashing or concatenating these fields.
- Return this grouping key as a string from the callback.
Note: The grouping key must be between 1 to 100 characters long. If a valid key is not returned, or the callback isn't set, Raygun defaults back to its automatic grouping.
Example:
class MyClass(object):
def my_callback(self, raygun_message):
return raygun_message.get_error().message[:100] # Naive message-based grouping
def create_raygun_and_bind_callback(self):
sender = raygunprovider.RaygunSender('api_key')
sender.on_grouping_key(self.my_callback)
In the example above, the RaygunSender
utilizes the my_callback
for custom grouping whenever an exception is captured. This sample logic uses only the exception message for grouping. For more complex and accurate grouping, consider a method that involves sanitizing or ignoring certain data.
The provider is open source and available at the Raygun4py repository.