Error Tracking in Django

Klaas van Schelven
Klaas van Schelven; December 19 - 4 min read
Error Tracking in Django with Bugsink

TL;DR: Django provides built-in error tracking that sends email reports for unhandled exceptions. While this is a good starting point, it lacks the features needed to effectively manage and debug errors in a live application. For a more robust solution, consider using a bug tracking service like Bugsink. Bugsink provides a centralized dashboard to manage and review all errors, smart grouping to identify root problems, and detailed stack traces to understand issues at a glance.

Django’s Built-In Error Tracking

While developing a Django application, you’ll typically run it with DEBUG set to True. Any unhandled exception will trigger a detailed error page, showing the traceback, request information, and local variables. This is invaluable for debugging, as it provides immediate feedback on what went wrong and where.

Here’s an example of Django’s error page with DEBUG=True:

Django error page with DEBUG=True

In production, however, you should set DEBUG to False. This disables the detailed error pages, which is a good security practice. While the end user won’t see anything in this case, Django will log the error to the console and will also send an email to the addresses listed in your settings’ ADMINS.

While email notifications can alert you quickly when something goes wrong, they can become overwhelming in production environments. For example, a misconfigured API endpoint might trigger hundreds of identical error emails during peak traffic, burying other critical alerts. These notifications also lack important context, like user data or breadcrumbs, making it harder to reproduce and diagnose the root cause of an issue.

Furthermore, Django’s email-based tracking offers no way to track whether an issue has been resolved. Once you fix a bug, emails for the same error continue until the fix is deployed and confirmed, which can result in unnecessary noise. There’s also no way to mute low-priority issues or ignore known non-critical errors, leading to a flood of information that dilutes attention on what really matters.

This makes Django’s email-based error tracking useful as a basic safety net, but it lacks the advanced features needed to effectively manage errors at scale. It doesn’t track past occurrences of the same issue, group similar errors, or provide a centralized view to prioritize, resolve, and silence issues efficiently. For these reasons, a more robust error-tracking solution is often necessary

A More Robust Solution

For managing errors effectively at scale, a more robust solution is necessary. Bug tracking services like Bugsink go beyond simple email notifications by providing tools to organize and prioritize issues, making it easier to focus on what matters most.

Here’s how Bugsink improves upon Django’s built-in error tracking:

  • Centralized dashboard: View all errors in one place, with clear overviews of unresolved and resolved issues.
  • Smart grouping: Automatically group related errors to identify root causes, reducing duplication and noise.
  • Issue tracking: Mark issues as resolved or mute low-priority problems, ensuring your team focuses only on active concerns.
  • Detailed stack traces: Gain deeper insights with stack traces that include local variables, making debugging faster and more effective.
  • Context-rich reports: User data, request information, and breadcrumbs provide the necessary context to reproduce and diagnose issues.

By addressing the limitations of Django’s built-in system, Bugsink ensures your team can prioritize, resolve, and manage errors more efficiently, all while minimizing unnecessary distractions.

Here’s an annotated picture of an error-event in Bugsink:

Annotated error event in Bugsink

As you can see, Bugsink provides a detailed overview of the error event, including the error message, stack trace, and additional context like user data and request information. This makes it easier to understand the issue at a glance and take appropriate action. The fact that this is “Event 1” indicates that Bugsink has grouped similar errors together.

Bugsink’s Django Integration

In addition to the benefits listed above, the Django integration provides additional context to error events. This includes:

  • User information: If you use django.contrib.auth and have set send_default_pii=True, user data (such as the current user ID, email address, and username) will be attached to error events.

  • Request data: HTTP method, URL, headers, form data, and JSON payloads will be attached to all events.

  • Logs as breadcrumbs: Logs emitted by any logger will be recorded as breadcrumbs by the Logging integration.

  • Database queries: Database queries will be recorded as breadcrumbs by the Django integration.

  • Templates:: It’s possible to attach the template information to the error event as if it were a part of the stack trace. This can be useful for debugging template-related issues.

Client-Server Model

Bugsink’s centralized approach is made possible by its client-server model. Your application sends error reports to the Bugsink server, which processes and organizes. This allows you to view and manage all errors in a single dashboard.

The server in Bugsink’s client-server model is itself a Django application that you can host yourself. This gives you full control over your data and deployment. By contrast, Sentry (the biggest player in the error tracking space) is a SaaS solution, requiring you to send all error data to their servers. Bugsink avoids this dependency, making it ideal for security-conscious environments where self-hosting is a priority.

Installation is straightforward, and you can have a Dockerized Bugsink up and running in minutes. Since you are already familiar with Python/Django, the local installation guide may be even more straightforward.

Integrating your Django Application

Once you’ve set up Bugsink, you can create your first project. The quickstart guide will walk you through creating a project and generating a DSN (Data Source Name): a unique identifier that tells your application where to send its error reports.

The final step is to tell your Django application to send errors to Bugsink. Integrating Bugsink into your Django project is done through the sentry-sdk package. (Sentry is an error-tracking service similar to Bugsink, but it’s offered as a SaaS solution)

pip install --upgrade sentry-sdk

Then, in settings.py:

import sentry_sdk
sentry_sdk.init(
    dsn="http://your-bugsink-server/your-dsn",
)

From here, Bugsink will capture, organize, and present errors from your Django application in a way that’s more productive than simply receiving emails.

Django configuration

The sentry-sdk package provides a Django-specific integration that captures errors and logs them to Bugsink. This integration also captures additional context, such as user information, request data, and database queries. The integration is enabled by default, so you don’t need to manually turn it on.

Assuming you use Django’s built-in template engine, you can also include template information in the error event. This includes the filename, offending line, and surrounding lines. This can be useful for debugging template-related issues.

To enable this feature, set TEMPLATES[..]['OPTIONS']['debug'] to True in your settings.py:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        # ...
        'OPTIONS': {
            # ...
            'debug': True,
        },
    },
]

Conclusion

Django’s built-in error tracking provides a good starting point for identifying issues in your application, but it falls short when managing errors at scale. Without features like error grouping, tracking resolved issues, or providing rich context, it can overwhelm developers with noise and hinder efficient debugging.

Bugsink offers a modern, developer-friendly alternative tailored to the needs of Django applications. With tools like smart grouping, issue tracking, and detailed stack traces, it helps teams focus on fixing problems instead of managing them. Bugsink’s self-hosted model ensures full control over your data, making it an excellent choice for security-conscious environments.

By integrating Bugsink, you can streamline your error management workflow, reduce downtime, and spend more time building great features—confident that your errors are being tracked and resolved effectively.