David Cramer's Blog

Keeping your logging compatible with Sentry

Something I've noticed while digging around in various libraries, is the inconsistent use of logging. This creates some problems with Sentry, and in the end gives us some very ugly exception logging.

Let's take a simple example (we're going to use Celery for this one):

if task.eta:
    try:
        eta = to_timestamp(task.eta)
    except OverflowError, exc:
        self.logger.error(
            "Couldn't convert eta %s to timestamp: %r" % (
            task.eta, exc))
task.acknowledge()
The functionality is pretty obvious. The logger is set via something similar to:
self.logger = logging.getLogger('celery')

Now the big issue with this, is it doesnt use the standardized logging storage for exceptions. This isn't an issue if you're logging to a text file, or something that just streams the messages, but once you start using something as powerful as Sentry, it is. To fix this, we need to make one simple adjustment:

# import the sys module
import sys

if task.eta:
try:
    eta = to_timestamp(task.eta)
except OverflowError, exc:
    # append exc_info=sys.exc_info
    self.logger.error(
        "Couldn't convert eta %s to timestamp: %r." % (
        task.eta, exc), exc_info=sys.exc_info())
task.acknowledge()

Now we'll pass along the exception, just like we would had we used logging.exception over logging.error, and apps like Sentry can take advantage of this.

-----

For those unaware, Sentry is a logging application built on top of Django. It allows you to efficiently log exceptions (and other messages, if you want) to a database. This gives you the benefit of being able to have a higher level overview of what's going on in your environment, especially with bug tracking.