Get started with Flask

Getting Opbeat set up for your Flask project is easy, and there are various ways you can tweak it to fit to your needs.

Installation

Requirements:

  • pip
  • simplejson (Only if you’re using Python 2.6)

Install the Opbeat module using pip:

$ pip install opbeat[flask]

or add opbeat[flask] to your project’s requirements.txt file.

Note: If you’re using Flask with uwsgi, make sure to enable threads.

Setup

For the setup you need to initialize Opbeat with appropriate settings. You can find the settings needed in your app’s settings page on opbeat.com.

The settings are added either via environment variables, the application’s settings, or as initialization arguments.

To initialize the Opbeat module for your application use:

from opbeat.contrib.flask import Opbeat
opbeat = Opbeat(app)

Environment Variables

By default, we attempt to read the Opbeat settings of <ORGANIZATION-ID>, <APP-ID> and <SECRET-TOKEN> from your environment under the OPBEAT_ORGANIZATION_ID, OPBEAT_APP_ID and OPBEAT_SECRET_TOKEN keys respectively.

Application Settings

You can configure the module using OPBEAT in your application’s settings:

class MyConfig(object):
    OPBEAT = {
        'ORGANIZATION_ID': '<ORGANIZATION-ID>',
        'APP_ID': '<APP-ID>',
        'SECRET_TOKEN': '<SECRET-TOKEN>',
        'INCLUDE_PATHS': ['myproject']
    }

Application Initialization

The final option is to initialize the Opbeat module with the settings as arguments:

from opbeat.contrib.flask import Opbeat
opbeat = Opbeat(app, organization_id='<ORGANIZATION-ID>', app_id='<APP-ID>',
                secret_token='<SECRET-TOKEN>')

Debug Mode

Please note that errors will only be logged to Opbeat if your app is not in debug mode.

To circumvent this and log errors during development set the value of DEBUG in the OPBEAT dictionary to True:

class MyConfig(object):
    OPBEAT = {
        'ORGANIZATION_ID': '<ORGANIZATION-ID>',
        'APP_ID': '<APP-ID>',
        'SECRET_TOKEN': '<SECRET-TOKEN>',
        'INCLUDE_PATHS': ['myproject']
        'DEBUG': True
    }

Building applications on the fly?

You can use the Opbeat module’s init_app hook for adding the application on the fly:

from opbeat.contrib.flask import Opbeat
opbeat = Opbeat(organization_id='<ORGANIZATION-ID>', app_id='<APP-ID>',
                secret_token='<SECRET-TOKEN>')

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

Usage

Once you have configured the Opbeat module, it will automatically capture uncaught exceptions within Flask. If you want to send additional events, a couple of shortcuts are provided on the Opbeat Flask middleware object by raising an exception or logging a generic message.

Capture an arbitrary exception by calling capture_exception:

>>> try:
>>>     1 / 0
>>> except ZeroDivisionError:
>>>     opbeat.capture_exception()

Log a generic message with capture_message:

>>> opbeat.capture_message('hello, world!')

Logging

Passing logging=True to the Opbeat constructor will make Opbeat automatically log errors that are logging using Python’s built-in logging module.

from opbeat.contrib.flask import Opbeat
opbeat = Opbeat(app, organization_id='<ORGANIZATION-ID>', app_id='<APP-ID>',
                secret_token='<SECRET-TOKEN>', logging=True)

For fine-grained control, you can initialize the Opbeat logging handler and add it, just as you would a normal handler.

from flask import Flask

from opbeat.contrib.flask import Opbeat
from opbeat.handlers.logging import OpbeatHandler

app = Flask(__name__)

opbeat = Opbeat(app, organization_id='<ORGANIZATION-ID>', app_id='<APP-ID>',
                secret_token='<SECRET-TOKEN>')

@app.route('/')
def foo():
    app.logger.warning('A warning occurred (%d apples)', 42)
    app.logger.error('An error occurred')
    app.logger.info('Info')  # Not sent due to `setLevel` below.
    return "foo"

if __name__ == '__main__':
    # Create a logging handler and attach it.
    handler = OpbeatHandler(client=opbeat.client)
    handler.setLevel(logging.WARN)
    app.logger.addHandler(handler)

You can also capture exceptions and send them explictly:

@app.route('/')
def bar():
    try:
        1 / 0
    except ZeroDivisionError:
        app.logger.error(
            'There was some crazy error',
            exc_info=True)

Note that exc_info=True adds the exception info to the data that gets sent to Opbeat. Without it, only the message gets sent.

Extra data

If you want to send more data to Opbeat than what you get with the Opbeat module by default, logging can be done like so:

@app.route('/')
def bar():
    try:
        1 / 0
    except ZeroDivisionError:
        logger.error(
            'There was some crazy error',
            exc_info=True,
            extra={
                'datetime': str(datetime.now()),
            }
        )
    )

The Extra tab on detail page for the error group will now have the extra field datetime.

Sanitizing data (removing sensitive information)

Sometimes it is necessary to sanitize the data, e.g. remove sensitive data.

To do this with the Opbeat module, you can create a Processor.

This is an example of a Processor where we remove the function that caused the error:

from opbeat.processors import Processor

class MyProcessor(Processor):
    def process(self, data, **kwargs):
        # 'data' is a dictionary
        if 'extra' in data:
            if 'funcName' in data['extra']:
                data['extra'].pop('funcName', None)
        return data

In this case, update your OPBEAT settings like this:

class MyConfig(object):
    OPBEAT = {
        'ORGANIZATION_ID': '<ORGANIZATION-ID>',
        'APP_ID': '<APP-ID>',
        'SECRET_TOKEN': '<SECRET-TOKEN>',
        'PROCESSORS': (
            'path.to.MyProcessor',
            'opbeat.processors.SanitizePasswordsProcessor',
        ),
    }

Note that we recommend you use 'opbeat.processors.SanitizePasswordsProcessor' (on by default) as this ensures that passwords and secrets get masked.

Logging Celery tasks

The following example shows how to integrate Opbeat with Celery:

from flask import Flask

from opbeat.contrib.flask import Opbeat
from opbeat.handlers.logging import OpbeatHandler
from opbeat.contrib.celery import register_signal

app = Flask(__name__)

opbeat = Opbeat(app, organization_id='<ORGANIZATION-ID>', app_id='<APP-ID>',
                secret_token='<SECRET-TOKEN>')

# Call register_signal to let Opbeat collect exceptions
# that happen in Celery tasks.
try:
    register_signal(opbeat.client)
except Exception as e:
    logger.exception('Failed installing celery hook: %s', e)

Performance Metrics

Metrics requires version 3.1+ of the Opbeat module

If you’ve followed the instructions above, Opbeat has already hooked into the right signals and should be reporting performance metrics. If they don’t show up within a couple of minutes, feel free to contact support.

Instrumenting custom Python code

To gain further insights into the performance of your code, please see instrumenting custom code.

Ignoring specific views

You can use the TRANSACTIONS_IGNORE_PATTERNS configuration option to ignore specific views. The list given should be a list of regular expressions which are matched against the transaction name used in the Opbeat user interface:

class MyConfig(object):
    OPBEAT = {
        ...
        'TRANSACTIONS_IGNORE_PATTERNS': ['^OPTIONS ', 'views.api.v2']
        ...
    }

This would ignore any requests using the OPTIONS method and any requests containing views.api.v2.

Note: make sure you use version 3.3.4 or newer of the Opbeat module for this to work.

Available settings

Below are all the available settings for the OPBEAT dictionary and their default values.

OPBEAT = {
    # ID for the organization
    'ORGANIZATION_ID': '<ORGANIZATION-ID>',

    # ID of the app
    'APP_ID': '<APP-ID>',

    # Secret for the organization
    'SECRET_TOKEN': '<SECRET-TOKEN>',

    # Set to True to enable the Opbeat module even if
    # your app is in DEBUG mode.
    'DEBUG': False,

    # This defines where Opbeat will look when trying to understand
    # where an exception is located. Defaults to `[app.import_name]`
    # which is the first argument to `Flask()`
    'INCLUDE_PATHS': [],

    # Extending this allow you to ignore module prefixes when we attempt to
    # discover which function an error comes from (typically a view)
    'EXCLUDE_PATHS': [],

    # List of exceptions types to be filtered out. Those won't be sent to the server.
    # It accepts both qualified and non qualified names (e.g.: 'KeyError' and 'exceptions.KeyError')
    'FILTER_EXCEPTION_TYPES': [],

    # How many seconds to wait for a response from the Opbeat servers before
    # timing out.
    'TIMEOUT': 20,

    # The hostname of the server emitting the logs
    'HOSTNAME': socket.gethostname(),

    # Automatically log frame stacks from all ``logging`` messages.
    'AUTO_LOG_STACKS': False,

    # The maximum length to store of a string-like structure.
    'MAX_LENGTH_STRING': 400,

    # The maximum number of elements to store for a list-like structure.
    'MAX_LENGTH_LIST': 50,

    # Client-side data processors to apply
    'PROCESSORS': (
        'opbeat.processors.SanitizePasswordsProcessor',
    )

    # How often to send app performance data to Opbeat (in seconds)
    'TRACES_SEND_FREQ_SECS': 60,

    # If data should be sent to Opbeat asynchronously in a separate thread
    'ASYNC': True,

    # Ignore views that match the specified regexp patterns
    'TRANSACTIONS_IGNORE_PATTERNS': []
}

Disable Opbeat during tests

The easiest method to disable the Opbeat module during tests is to simply not initialize Opbeat for your app when running tests.