---
title: 'Writing a Hoptoad Notifier: Contacting the Toad'
teaser: 'An example of writing a library to hit the Hoptoad error notification API.

  '
tags: web,python,airbrake
author: Mike Burns
published_on: 2010-01-08
---

... in Python.

[Hoptoad](http://hoptoadapp.com/), our app error app, is [a Web service that
accepts XML](http://help.airbrake.io/faqs/api-2/notifier-api-v2). No
Rails-specific tricks going on here; you can have runtime errors in any
programming language and Hoptoad can handle that for you.

Let's build a notifier in some language I don't know. How about Python?

The main step is to actually send the data to Hoptoad. Subsequent steps
(integration testing, [plugins for your
framework](http://help.airbrake.io/faqs/api-2/alternate-plugins-widgets-addons-and-extras),
and so on) are either outside the scope of this tutorial or may be covered in a
future tutorial.

Sending the data is two parts: generating the data to send, then sending it. To
generate the data we can use any library that will produce <abbr
title="Extensible Markup Language">XML</abbr> for us.

## Generating the data

```python
import traceback
import sys
import urllib2
import xmlbuilder

from xmlbuilder import XMLBuilder

def api_key():
  return "YOUR API KEY"

def generate_xml(exn):
  _,_,trace = sys.exc_info()

  xml = XMLBuilder()
  with xml.notice(version = 2.0):
    xml << ('api-key', api_key())
    with xml.notifier:
      xml << ('name', 'Dennis')
      xml << ('version', '0.1')
      xml << ('url', 'http://hoptoadapp.com')
    with xml('server-environment'):
      xml << ('environment-name', 'REPL')
    with xml.error:
      xml << ('class', exn.__class__.__name__)
      xml << ('message', str(exn))
      with xml.backtrace:
        [xml << ('line', {'file':filename, 'number':line_number, 'method':function_name})
            for filename, line_number, function_name, _ in traceback.extract_tb(trace)]

  return str(xml)
```

What we've written here is a method that takes an exception and produces the
<abbr title="Extensible Markup Language">XML</abbr> that should be sent to
Hoptoad. Nothing especially tricky happens here; we pull out the class of
exception and the message describing it, then grab and generate the <abbr
title="Extensible Markup Language">XML</abbr> for the backtrace.

Next up: sending this data.

## Sending this data

Sending the data isn't too tricky. It's a HTTP POST with the text/xml content
type to `/notifier_api/v2/notices`. The only edge case is that paid accounts
support SSL.

```python
def hoptoad_url(use_ssl):
  if use_ssl:
    return "https://hoptoadapp.com/notifier_api/v2/notices"
  else:
    return "http://hoptoadapp.com/notifier_api/v2/notices"

def send_to_hoptoad(xml, use_ssl):
  headers = { 'Content-Type': 'text/xml' }
  request = urllib2.Request(hoptoad_url(use_ssl), xml, headers)
  response = urllib2.urlopen(request)
  status = response.getcode()
  if status == 200:
    pass
  if status == 403:
    raise Exception("Cannot use SSL")
  if status == 422:
    raise Exception("Invalid XML sent to Hoptoad")
  if status == 500:
    raise Exception("Hoptoad has hopped the toad")

def notify_hoptoad(exn, use_ssl):
  send_to_hoptoad(generate_xml(exn), use_ssl)
```

The HTTP response indicates how well it worked; the exceptional cases are 403
(the customer does not have a Hoptoad account that supports SSL),  422 (invalid
XML), and 500 (server error).

So that's it:

    try:
      1/0
    except ZeroDivisionError as exn:
      notify_hoptoad(exn, True)

That is what is needed to send an exception to Hoptoad from Python. To use
Hoptoad with Django there is the full
[django-hoptoad](http://pypi.python.org/pypi/django-hoptoad/0.2) plugin; a [full
list of alternative plugins exists
too](http://help.airbrake.io/faqs/api-2/alternate-plugins-widgets-addons-and-extras).
Perhaps yours can be there soon too!

FYI: _Hoptoad/Airbrake was sold to RackSpace and is now called [Airbrake Bug Tracker](http://airbrake.io)_.
