Better Customer Support with eventlog

In web apps where users are doing various activities in your site, things can get complicated in a hurry that can make troubleshooting both customer support issues as well as exceptions very tricky. Tracking the flow of user activity is critical to understanding what happened and is not always easy to decipher at granular levels through analytics services such as Google Analytics.

As a compliment to these services, Eldarion wrote eventlog. It’s a simple pluggable app that you add to your site and then log events throughout your code.

The usage of eventlog is pretty simple:

from eventlog.models import log

log(
    user=user,
    action="SOME_ACTION",
    extra={
        "key": "value"
    }
)

Oftentimes, I hook up a bunch of signal receivers from external apps just for logging various activity on the site. In this above contrived example, user is optional, but if you supply it, it should be an authenticated user.

The action is what is used in the Django admin for filtering, so give some consideration in naming. I typically prefix similar actions, or actions from the same app, with the same prefix so they are visually grouped together in the filter list. This is especially important as the number of different actions increase.

One practical example of where this can help you be more proactive with your users is how we have used with with django-user-accounts to spot users that are having difficulty logging in.

By logging essentially all of the signals that django-user-accounts provides we can have a complete view of what particular users did at what timestamp and in what order that we can quickly drill into should the customer/user contact us for support.

An example of hooking up a receiver to log a few of these signals:

from django.dispatch import receiver

from account import signals
from eventlog.models import log


@receiver(signals.user_logged_in)
def handle_user_logged_in(sender, **kwargs):
    log(
        user = kwargs.get("user"),
        action = "USER_LOGGED_IN",
        extra = {}
    )


@receiver(signals.password_changed)
def handle_password_changed(sender, **kwargs):
    log(
        user = kwargs.get("user"),
        action = "PASSWORD_CHANGED",
        extra = {}
    )


@receiver(signals.user_login_attempt)
def handle_user_login_attempt(sender, **kwargs):
    log(
        user = None,
        action = "LOGIN_ATTEMPTED",
        extra = {
            "username": kwargs.get("username"),
            "result": kwargs.get("result")
        }
    )


@receiver(signals.user_sign_up_attempt)
def handle_user_sign_up_attempt(sender, **kwargs):
    log(
        user = None,
        action = "SIGNUP_ATTEMPTED",
        extra = {
            "username": kwargs.get("username"),
            "email": kwargs.get("email"),
            "result": kwargs.get("result")
        }
    )

I hope you find this app as useful as we have found it for both customer support as well as troubleshooting and diagnosing exceptions and/or bugs that crop up.