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 vialogging.StreamHandler. - In Production (
DEBUG = False): Error-level logs are emailed to site administrators viaAdminEmailHandler.
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 whensettings.DEBUGisFalse. It is typically attached to themail_adminshandler to prevent spamming developers with emails during local testing.RequireDebugTrue: Only allows records to pass whensettings.DEBUGisTrue. 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, usuallydjango.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_adminsto 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_backendargument inAdminEmailHandleris deprecated. Use theusingargument to specify a mailer fromsettings.MAILERSinstead.
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:
- Color-coding HTTP Status Codes: It uses
django.core.management.color.color_styleto highlight status codes (e.g., green for 2xx, red for 5xx). - Server Time: It supports a
{server_time}placeholder in the format string, which it populates usingformatTime.
# 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.