Installation
The Raygun4py provider can send uncaught exceptions by creating a handler and attaching it to sys.excepthook, or automatically by adding the built-in logger. It also supports manual sending from except
blocks. It only takes a few minutes to set up so you can start real time error monitoring and crash reporting from your Python applications quickly and easily.
Installation
Requirements
Raygun4py is known to work with Python 2.6-2.7, Python 3.1+ and PyPy environments.
It requires the socket
module to be built with SSL support.
Grab the module with pip:
pip install raygun4py
Then include and instantiate it:
from raygun4py import raygunprovider
client = raygunprovider.RaygunSender('your_apikey')
Test the installation
From the command line, run:
$ raygun4py test your_apikey
Replace your_apikey
with the one listed on your Raygun dashboard. This will cause a test exception to be generated and sent.
Usage
Automatically send the current exception like this:
try:
raise Exception("foo")
except:
client.send_exception()
See sending functions for more ways to send.
Uncaught exception handler
To automatically pick up unhandled exceptions with custom logic, you can provide a callback function to sys.excepthook:
def handle_exception(exc_type, exc_value, exc_traceback):
sender = raygunprovider.RaygunSender("your_apikey")
sender.send_exception(exc_info=(exc_type, exc_value, exc_traceback))
sys.excepthook = handle_exception
Logging
You can also send exceptions using a logger:
logger = logging.getLogger("mylogger")
rgHandler = raygunprovider.RaygunHandler("your_apikey")
logger.addHandler(rgHandler)
def log_exception(exc_type, exc_value, exc_traceback):
logger.error("An exception occurred", exc_info = (exc_type, exc_value, exc_traceback))
sys.excepthook = log_exception
This uses the built-in RaygunHandler
. You can provide your own handler implementation based on that class if you need custom sending behavior.
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.6/2.7 and Python 3+.
Django
To configure Django to automatically send all exceptions that are raised in views to Raygun:
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
from flask import Flask, current_app
from raygun4py.middleware import flask
app = Flask(__name__)
flask.Provider(app, 'your_apikey').attach()
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, 'your_apikey')
server = wsgiref.simple_server.make_server('', 8888, raygun_wrapped_app)
server.serve_forever()
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('YOUR_API_KEY')
client.send_exception()
return Response("Internal server error", status_code=500)
Note that many frameworks (tornado, pryramid, gevent et al) 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 and the headers through in a dictionary (see sample.py in the GitHub repository). Code running on Google App Engine is supported - this requires a paid account due to required SSL support.
Public API functions
Initialization options
RaygunSender
accepts a config
dict which is used to set options on the provider:
from raygun4py import raygunprovider
client = raygunprovider.RaygunSender('your_apikey', 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
})
For the local/global variables, if their options 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
send_exception(exception, exc_info, tags, userCustomData, httpRequest)
- exception (Exception)
- exc_info (3-tuple)
- tags (List)
- userCustomData (Dict)
- userCustomData (Dict)
All parameters are optional.
Call this function from within a catch block to send the current exception to Raygun:
# Automatically gets the current exception
httpResult = client.send_exception()
# Uses the supplied sys.exc_info() tuple
httpResult = client.send_exception(exc_info=sys.exc_info())
# Uses a supplied Exception object
httpResult = client.send_exception(exception=exception)
# Send tags, custom data and an HTTP request object
httpResult = client.send_exception(tags=[], userCustomData={}, request={})
You can pass in either of these two exception params:
exception
should be a subclass of type Exception. Pass this in if you want to manually transmit an exception object to Raygun.exc_info
should be the 3-tuple returned fromsys.exc_info()
. Pass this tuple in if you wish to use it in other code aside from send_exception().
send_exception also supports the following extra data parameters:
tags
is a list of tags relating to the current context which you can define.userCustomData
is a dict containing custom key-values also of your choosing.httpRequest
is HTTP Request data - see sample.py for the expected format of the object.
Config and data functions
filtered_keys
Arguments
- keys (List)
If you want to filter sensitive data out of the payload that is sent to Raygun, pass in a list of keys here. 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 passwords, credit card data etc. By example:
client.filtered_keys(keys=['credit_card', 'cv2', 'password'])
ignore_exceptions
Arguments
- exceptions (List of strings)
Provide a list of exception types to ignore here. Any exceptions that are passed to send_exception that match a type in this list won't be sent.
on_before_send
Arguments
- callback (Function)
You can mutate the candidate payload by passing in a function that accepts one parameter using this function. This allows you to completely customize what data is sent, immediately before it happens.
on_grouping_key
Arguments
- callback (Function)
Pass a callback function to this method to configure custom grouping logic. The callback should take one parameter, an instance of RaygunMessage, and return a string between 1 and 100 characters in length (see 'Custom Grouping Logic' below for more details).
set_proxy
Arguments
- host (String)
- port (Integer)
Call this function if your code is behind a proxy and want Raygun4py to make the HTTP request to the Raygun endpoint through it.
set_version
Arguments
- version (String)
Call this to attach a SemVer version to each message that is sent. This will be visible on the dashboard and can be used to filter exceptions to a particular version, deployment tracking etc.
set_user
Arguments
- user_info (Dict)
User data can be passed in which will be displayed in the Raygun web app. The dict you pass in should look this this:
client.set_user({
'firstName': 'Foo',
'fullName': 'Foo Bar',
'email': 'foo@bar.com',
'isAnonymous': False,
'identifier': 'foo@bar.com'
})
Identifier should be whatever unique key you use to identify users, for instance an email address. This will be used to create the count of unique affected users. If you wish to anonymize it, you can generate and store a UUID or hash one or more of their unique login data fields, if available.
The string properties on a User have a maximum length of 255 characters. Users who have fields that exceed this amount will not be processed.
Features
Custom grouping logic
You can create custom exception grouping logic that overrides the automatic Raygun grouping by passing in a function that accepts one parameter using this function. The callback's one parameter is an instance of RaygunMessage (python[2/3]/raygunmsgs.py), and the callback should return a string.
The RaygunMessage instance contains all the error and state data that is about to be sent to the Raygun API. In your callback you can inspect this RaygunMessage, hash together the fields you want to group by, then return a string which is the grouping key.
This string needs to be between 1 and 100 characters long. If the callback is not set or the string isn't valid, the default automatic grouping will be used. By example:
class MyClass(object):
def my_callback(self, raygun_message):
return raygun_message.get_error().message[:100] # Use naive message-based grouping only
def create_raygun_and_bind_callback(self):
sender = raygunprovider.RaygunSender('api_key')
sender.on_grouping_key(self.my_callback)
The RaygunSender above will use the my_callback to execute custom grouping logic when an exception is raised. The above logic will use the exception message only - you'll want to use a more sophisticated approach, usually involving sanitizing or ignoring data.
Chained exceptions
For Python 3, chained exceptions are now supported and automatically sent along with their traceback.
This occurs when an exception is raised while handling another exception - see tests_functional.py for an example.
Local, global and environment variables
Raygun4py can automatically send the names of all variables that are in scope and their values if these options are set. Local variables will send the variable state for each stack frame, and global variables will transmit the state of all variables in global scope. System environment variables are also sent. See Initialization Options above if you wish to disable this.
Troubleshooting
To see the HTTP response code from sending the message to raygun, print client.send() (as in line 27 of test.py). It will be 403 if an invalid API key was entered, and 202 if successful.
Create a thread in the official support forums at https://raygun.com/forums, and we'll help you out.
The provider is open source and available at the Raygun4py repository.