Skip to main content

Logging and Error Reporting

Django's logging system is designed to provide detailed diagnostic information during development while ensuring that critical server errors are reported to administrators in production. This behavior is primarily controlled through the DEFAULT_LOGGING configuration and specialized handlers and filters found in django/utils/log.py.

Default Logging Philosophy

The framework's default logging configuration, defined in django.utils.log.DEFAULT_LOGGING, establishes a clear separation between development and production environments:

  • In Development (DEBUG = True): Logs are directed to the console via logging.StreamHandler.
  • In Production (DEBUG = False): Error-level logs are emailed to site administrators via AdminEmailHandler.

This environment-aware behavior is implemented using specialized filters that check the settings.DEBUG value.

Environment Filters

Filters determine whether a log record should be processed by a specific handler.

RequireDebugFalse and RequireDebugTrue

These filters are the primary mechanism for environment-specific logging.

  • RequireDebugFalse: Only allows records to pass when settings.DEBUG is False. It is typically attached to the mail_admins handler to prevent spamming developers with emails during local testing.
  • RequireDebugTrue: Only allows records to pass when settings.DEBUG is True. It is used to keep the console output clean in production while providing full visibility during development.
# django/utils/log.py

class RequireDebugFalse(logging.Filter):
def filter(self, record):
return not settings.DEBUG

class RequireDebugTrue(logging.Filter):
def filter(self, record):
return settings.DEBUG

CallbackFilter

For more complex logic, CallbackFilter allows you to provide a custom callable that takes a log record and returns a boolean.

# django/utils/log.py

class CallbackFilter(logging.Filter):
def __init__(self, callback):
self.callback = callback

def filter(self, record):
if self.callback(record):
return 1
return 0

Administrative Error Reporting

The AdminEmailHandler is responsible for notifying administrators when server errors occur.

AdminEmailHandler

When a log record with a level of ERROR or higher is processed, this handler sends an email to every person listed in the settings.ADMINS setting.

If the log record contains a request object (which Django's exception handling middleware automatically provides), the handler includes detailed request information and a full traceback in the email.

Key features of AdminEmailHandler:

  • Exception Reporting: It uses a reporter class (defined by settings.DEFAULT_EXCEPTION_REPORTER, usually django.views.debug.ExceptionReporter) to generate the traceback text and optional HTML.
  • HTML Emails: If initialized with include_html=True, the handler will include an HTML version of the debug page as an attachment or alternative body.
  • Mailer Integration: It uses django.core.mail.mail_admins to send the messages.
# Example of AdminEmailHandler usage in DEFAULT_LOGGING
"mail_admins": {
"level": "ERROR",
"filters": ["require_debug_false"],
"class": "django.utils.log.AdminEmailHandler",
}

Note: The email_backend argument in AdminEmailHandler is deprecated. Use the using argument to specify a mailer from settings.MAILERS instead.

Development Server Formatting

The ServerFormatter class is specifically designed for the django.server logger, which handles output for the runserver command. It enhances the readability of the console output by:

  1. Color-coding HTTP Status Codes: It uses django.core.management.color.color_style to highlight status codes (e.g., green for 2xx, red for 5xx).
  2. Server Time: It supports a {server_time} placeholder in the format string, which it populates using formatTime.
# django/utils/log.py

class ServerFormatter(logging.Formatter):
def format(self, record):
status_code = getattr(record, "status_code", None)
if status_code:
if 200 <= status_code < 300:
msg = self.style.HTTP_SUCCESS(record.msg)
# ... other status code checks ...
elif status_code >= 500:
msg = self.style.HTTP_SERVER_ERROR(record.msg)
record.msg = msg
return super().format(record)

Internal Logging Utilities

Django provides internal helper functions to ensure consistent logging across the framework.

log_response

The log_response function is used by middleware and exception handlers (like django.core.handlers.exception.response_for_exception) to log HTTP responses based on their status code.

  • Responses with status codes >= 500 are logged as ERROR.
  • Responses with status codes >= 400 are logged as WARNING.

To prevent duplicate logs for the same request, log_response sets a _has_been_logged attribute on the response object.

# django/core/handlers/exception.py

log_response(
"Forbidden (Permission denied): %s",
request.path,
response=response,
request=request,
exception=exc,
)

log_message

A lower-level utility, log_message, handles the actual interaction with the logger. It automatically escapes arguments to prevent log injection and ensures that the request and status_code are passed in the extra context for handlers like AdminEmailHandler to use.