Reporting handled exceptions

In order to provide error reporting during normal program execution, the BugSnag python library includes functions for sending an exception directly.

The bugsnag.notify function is available to send handled exceptions to BugSnag using the default configuration.

try:
    sign_in()
except Exception as e:
    bugsnag.notify(e)
    show_error_dialog()

Invocations of bugsnag.notify can be customized using the notification options to change report information.

Creating clients

Reporting clients can be created to cache notification and delivery options separate from the defaults used by bugsnag.notify and optionally scoped to specific sections of code.

client = bugsnag.Client(api_key='...')

client.notify(Exception('Oh no'))

Note: By default, a client installs itself as the default exception hook. To avoid duplicating error reports when using multiple clients, set install_sys_hook to False for all but the client which should be used to capture unhandled exceptions.

client = bugsnag.Client(api_key='...', install_sys_hook=False)

Capturing exceptions with context managers

Custom clients support capturing exceptions on specific sections of code using capture. Capture reports any exception thrown during the execution of a provided context, attaching additional report metadata where requested.

try:
    with client.capture(severity='warning'):
        sign_in()
        begin_sync()

    with client.capture():
        load_user_info()
except:
    show_error_dialog()

Captured and reported exceptions can also be further scoped by type to only report specific classes of exceptions.

try:
    with client.capture((LoadError,), severity='warning'):
        sign_in()
        begin_sync()

    with client.capture():
        load_user_info()
except:
    show_error_dialog()

Capturing exception on entire functions

Exceptions thrown within an entire function can be captured by using the capture decorator.

@client.capture
def update(self):
    dialog = show_dialog()
    if not dialog.visible:
        raise LoadError('dialog failed to load')

The decorator also accepts additional arguments for exception type filtering and attaching additional information.

@client.capture((LoadError,), severity='warning')
def update(self):
    dialog = show_dialog()
    if not dialog.visible:
        raise LoadError('dialog failed to load')

Invocations of bugsnag.Client.notify and bugsnag.Client.capture accept notification options to change report information.

Capturing log messages

A client can generate a Handler to attach to a logger to output emitted log messages to BugSnag.

logger = logging.getLogger(__name__)
handler = client.log_handler()
logger.addHandler(handler)

To attach additional information to an error report from the LogRecord, add a callback. A callback is invoked with the LogRecord instance and the options which will be passed to notify:

def attach_custom_fields(record, options):
    if 'metadata' not in options:
        options['metadata'] = {}

    options['metadata']['stats'] = {
        'account_id': record.account_id,
        'slice': record.slice
    }

logger = logging.getLogger(__name__)
handler = client.log_handler()
handler.add_callback(attach_custom_fields)
logger.addHandler(handler)

To filter messages sent to BugSnag, attach a Filter to the handler, returning True only if the message should be sent:

class CustomFilter(logging.Filter)

    def filter(record):
        return record.account_id != 0

logger = logging.getLogger(__name__)
handler = client.log_handler()
handler.addFilter(CustomFilter())
logger.addHandler(handler)

Capturing local variables

You can include the state of local variables when reporting handled exceptions. The values will appear in a tab in BugSnag called “Local variables”.

bugsnag.notify(e, metadata={"local variables": locals()})

Notification options

The bugsnag.notify and bugsnag.Client.capture functions accept several keyword arguments which can be used to override configuration or to send more data to BugSnag. These same fields can be used to customize handled error reports globally.

api_key

Use a specific API key for this event. (defaults to bugsnag.configuration.api_key)

Using the default global client:

bugsnag.notify(e, api_key="YOUR_API_KEY_HERE")

Or with a custom client:

client.notify(e, api_key="YOUR_API_KEY_HERE")
with client.capture(api_key="YOUR_API_KEY_HERE"):
    sign_in()
@client.capture(api_key="YOUR_API_KEY_HERE")
def update(self):
    sign_in()

app_type

Specify the component or configuration affected by this event. This allows filtering and grouping events by the worker queue, HTTP router, and more.

bugsnag.notify(e, app_type="email queue")

Or with a custom client:

client.notify(e, app_type="email queue")
with client.capture(app_type="email queue"):
    process_events()
@client.capture(app_type="email queue")
def update(self):
    process_events()

context

A string representing what was happening in your application at the time of the error. In Django apps, this is automatically set to be the path of the current request.

Using the default global client:

bugsnag.notify(e, context="sign up")

Or with a custom client:

client.notify(e, context="sign up")
with client.capture(context="sign up"):
    sign_in()
@client.capture(context="sign up")
def update(self):
    sign_in()

grouping_hash

A string to use to group errors using your own custom grouping algorithm.

Using the default global client:

bugsnag.notify(e, grouping_hash="Test Slice B Runtime Error")

Using a Logger:

logger.info("This happened", extra={'groupingHash': 'Test Slice B Runtime Error'})

Or With a custom client:

client.notify(e, grouping_hash="Test Slice B Runtime Error")
with client.capture(grouping_hash="Test Slice B Runtime Error"):
    sign_in()
@client.capture(grouping_hash="Test Slice B Runtime Error")
def update(self):
    sign_in()

metadata

A dictionary of dictionaries. Each dictionary will show up as a tab on BugSnag.

Using the default global client:

bugsnag.notify(e, metadata={"account":{"name":"ACME Inc.", "premium": True}})

Or with a custom client:

client.notify(e, metadata={"account":{"name":"ACME Inc.", "premium": True}})
with client.capture(account={"name":"ACME Inc.", "premium": True}):
    sign_in()
@client.capture(account={"name":"ACME Inc.", "premium": True})
def update(self):
    sign_in()

severity

You can set the severity of an error in BugSnag by including the severity option when notifying BugSnag.

Using the default global client:

bugsnag.notify(Exception("Something broke!"), severity="error")

Or with a custom client:

client.notify(Exception("Something broke!"), severity="error")
with client.capture(severity="error"):
    sign_in()
@client.capture(severity="error")
def update(self):
    sign_in()

Valid severities are error, warning, and info.

Severity is displayed in the dashboard and can be used to filter the error list. By default all crashes (or unhandled exceptions) are set to error and all bugsnag.notify() calls default to warning.

traceback

The traceback to use for the exception. If omitted this will be read from sys.exc_info.

Using the default global client:

bugsnag.notify(e, traceback=sys.exc_info()[2])

Or with a custom client:

client.notify(e, traceback=sys.exc_info()[2])

user

Information about the user currently using your app. This should be a dictionary containing id, email and name keys.

Using the default global client:

bugsnag.notify(e, user={"id":"bob", name: "Bob", email: "bob@example.com"})

Or with a custom client:

client.notify(e, user={"id":"bob", name: "Bob", email: "bob@example.com"})
with client.capture(user={"id":"bob", name: "Bob", email: "bob@example.com"}):
    sign_in()