• 3.1
  • 3.2
  • 6.1
  • Версия документации: 5.0

Как управлять сообщениями об ошибках

Когда вы работаете с публичным сайтом, вам всегда следует отключать параметр DEBUG. Это значительно ускорит работу вашего сервера, а также не позволит злоумышленникам увидеть детали вашего приложения, которые могут быть раскрыты страницами с ошибками.

Однако запуск с DEBUG установленным на False означает, что вы никогда не увидите ошибок, сгенерированных вашим сайтом — вместо этого все будут видеть ваши общедоступные страницы ошибок. Вам необходимо отслеживать ошибки, которые происходят на развернутых сайтах, поэтому Django можно настроить для создания отчетов с подробностями об этих ошибках.

Отчеты по электронной почте

Ошибки сервера

Когда DEBUG имеет значение False, Django будет отправлять электронные письма пользователям, указанным в настройке ADMINS, всякий раз, когда ваш код вызывает необработанное исключение и приводит к внутренней ошибке сервера (строго говоря, для любого ответа с кодом состояния HTTP 500 или выше). Это дает администраторам немедленное уведомление о любых ошибках. ADMINS получит описание ошибки, полную трассировку Python и подробности о HTTP-запросе, вызвавшем ошибку.

Примечание

Для отправки электронной почты Django требуется несколько настроек, сообщающих ему, как подключаться к вашему почтовому серверу. Как минимум, вам нужно будет указать EMAIL_HOST и, возможно, EMAIL_HOST_USER и EMAIL_HOST_PASSWORD, хотя могут потребоваться и другие настройки в зависимости от конфигурации вашего почтового сервера. Ознакомьтесь с документацией по настройкам Django для получения полного списка настроек, связанных с электронной почтой.

По умолчанию Django отправляет почту с root@localhost. Однако некоторые почтовые провайдеры отклоняют всю почту с этого адреса. Чтобы использовать другой адрес отправителя, измените настройку SERVER_EMAIL.

Чтобы активировать это поведение, укажите адреса электронной почты получателей в настройке ADMINS.

См.также

Письма об ошибках сервера отправляются с использованием фреймворка logging, поэтому вы можете настроить это поведение, настроив конфигурацию ведения журнала.

Ошибки 404

Django также можно настроить на отправку сообщений об ошибках, связанных с битыми ссылками (ошибки 404 «page not found»). Django отправляет сообщения об ошибках 404, когда:

При выполнении этих условий, Django вышлет отчёт пользователям, указанным в секции MANAGERS, если код выдаст ошибку 404 и запрос содержит «referer». Это не относится к ошибке 404 на запрос, который не содержит «referer» – как правило, в этом случае ошибка связана с тем, что пользователь вводит неверный адрес, или Web-боты запрашивают неверный адрес. Также игнорируются 404, если запрос содержит «referer» равный запрошенному URL, они обычно так же вызваны Web-ботами.

Примечание

BrokenLinkEmailsMiddleware должен выполняться перед другими мидлварами обрабатывающими 404 ошибки, такими как LocaleMiddleware или FlatpageFallbackMiddleware. Поместите его выше в настройках MIDDLEWARE.

Вы можете отключить отчёты о 404 ошибке, настроив IGNORABLE_404_URLS. Это должен быть список со скомпилированными объектами регулярных выражений. Например:

import re

IGNORABLE_404_URLS = [
    re.compile(r"\.(php|cgi)$"),
    re.compile(r"^/phpmyadmin/"),
]

В этом примере уведомление об ошибке 404 не будет присылаться, если URL страницы заканчивается на .php или .cgi. Также в исключения добавлена директория /phpmyadmin/.

В приведённом ниже примере показано как добавить в исключения некоторые URL, которые часто запрашиваются браузером и поисковыми роботами:

import re

IGNORABLE_404_URLS = [
    re.compile(r"^/apple-touch-icon.*\.png$"),
    re.compile(r"^/favicon\.ico$"),
    re.compile(r"^/robots\.txt$"),
]

(Заметьте, что это регулярные выражения, и нужно ставить обратный слэш, чтобы экранировать значения.)

Если хочется изменить дальнейшее поведение django.middleware.common.BrokenLinkEmailsMiddleware (изначально игнорирует запросы от поисковых роботов), необходимо переопределить методы в его подклассах.

См.также

При отправке 404 ошибки задействуется логгирование. Изначально записи игнорируются, но могут быть использованы для отправки отчётов при записи с помощью обработчика и настройки логгирования.

Фильтрация сообщений об ошибках

Предупреждение

Фильтрация конфиденциальной информации – это сложная задача, и нет никакой гарантии, что она не появится в отчете об ошибке. Поэтому отчеты об ошибках должны быть доступны только доверенным членам команды и не передаваться в открытом виде через интернет(например по почте).

Фильтрация конфиденциальной информации

Отчёты об ошибках весьма полезны для отладки, поэтому лучше записывать как можно больше соответствующей информации о различных инцидентах. Например, изначально Django сохраняет полную трассировочную информацию о вызванных исключениях, каждую локальную переменную кадра трассировки и атрибуты класса HttpRequest.

Однако, некоторая информация может быть конфиденциальной и совершенно не подходит для отслеживания, к таким моментам можно отнести пароль пользователя или номер кредитной карты. Django предлагает несколько декораторов для контроля информации, которая должна быть отфильтрована при отправке отчётов на сервере в продакшене (то есть там, где DEBUG установлен в False): sensitive_variables() и sensitive_post_parameters().

sensitive_variables(*variables)

Если функция (или представление регулярного выражения) в вашем коде использует локальные переменные, содержащие конфиденциальную информацию, вы можете предотвратить появление этих переменных при отправке отчётов при помощи декоратора sensitive_variables:

from django.views.decorators.debug import sensitive_variables


@sensitive_variables("user", "pw", "cc")
def process_info(user):
    pw = user.pass_word
    cc = user.credit_card_number
    name = user.name
    ...

В примере выше значения переменных user, pw и cc будут скрыты и заменены на символы звёздочки (**********) в отчёте, в то время как значение переменной name будет открытым.

Систематическое скрытие всех локальных переменных функции из журнала ошибок (error logs) не требует никаких аргументов декоратора sensitive_variables:

@sensitive_variables()
def my_function(): ...

При использовании нескольких декораторов

Если переменная, значение которой вы хотите скрыть, также является аргументом функции (как „user“ в приведённом примере), и декорируемая функция имеет множество декораторов, убедитесь, что @sensitive_variables находится на самом верху цепочки. Это позволит также скрыть аргументы функции, взаимодействующие с другими декораторами:

@sensitive_variables("user", "pw", "cc")
@some_decorator
@another_decorator
def process_info(user): ...
Changed in Django 5.0:

Добавлена ​​поддержка обёртывания async функций.

sensitive_post_parameters(*parameters)

Если одно из представлений объекта HttpRequest с атрибутом POST parameters подтверждает содержание конфиденциальной информации, вы можете предотвратить включение этих данных в отчёт, используя декоратор sensitive_post_parameters

from django.views.decorators.debug import sensitive_post_parameters


@sensitive_post_parameters("pass_word", "credit_card_number")
def record_user_profile(request):
    UserProfile.create(
        user=request.user,
        password=request.POST["pass_word"],
        credit_card=request.POST["credit_card_number"],
        name=request.POST["name"],
    )
    ...

В данном выше примере значения pass_word и credit_card_number в POST запросе будут скрыты и заменены звёздочками (**********) при представлении запроса в отчёте об ошибках, в то время как параметр name будет открытым.

Чтобы спрятать все POST параметры из журнала ошибок (error logs), не передавайте аргументы декоратору sensitive_post_parameters

@sensitive_post_parameters()
def my_view(request): ...

Все POST параметры систематически фильтруются в отчёте об ошибках в представлении django.contrib.auth.views (login, password_reset_confirm, password_change, и add_view и user_change_password в системе аутентификации) для предотвращения утечки конфиденциальной информации, такой как пароли пользователей.

Changed in Django 5.0:

Добавлена ​​поддержка обёртывания async функций.

Настройка отчета об ошибке

Декораторы sensitive_variables() и sensitive_post_parameters() отмечают небезопасные аргументы и POST аргументы объекта HttpRequest, которые передаются в функцию. При формировании отчета об ошибке эти данные фильтруются. Фильтрация выполняется классом django.views.debug.SafeExceptionReporterFilter. Этот класс заменит отмеченные декоратором данные «звездочками» (**********) при формировании отчета. Вы можете создать собственный класс фильтрации и указать его в настройке DEFAULT_EXCEPTION_REPORTER_FILTER:

DEFAULT_EXCEPTION_REPORTER_FILTER = "path.to.your.CustomExceptionReporterFilter"

Также можно указать класс фильтрации для конкретного HttpRequest определив атрибут exception_reporter_filter:

def my_view(request):
    if request.user.is_authenticated:
        request.exception_reporter_filter = CustomExceptionReporterFilter()
    ...

Ваш класс фильтрации должен наследоваться от django.views.debug.SafeExceptionReporterFilter и может переопределить следующие методы:

class SafeExceptionReporterFilter
cleansed_substitute

Строковое значение, которым следует заменить конфиденциальное значение. По умолчанию оно заменяет значения конфиденциальных переменных на звездочки (**********).

hidden_settings

Скомпилированный объект регулярного выражения, используемый для сопоставления настроек и request"Значения META считаются конфиденциальными. По умолчанию эквивалентно:

import re

re.compile(r"API|TOKEN|KEY|SECRET|PASS|SIGNATURE|HTTP_COOKIE", flags=re.IGNORECASE)
is_active(request)

Возвращает True для активации фильтрации в get_post_parameters() и get_traceback_frame_variables(). По умолчанию фильтр активен, если DEBUG равно False. Обратите внимание, что конфиденциальные значения request.META всегда фильтруются вместе со значениями настроек конфиденциальности, как описано в документации DEBUG.

get_post_parameters(request)

Возвращает отфильтрованный словарь параметров POST. Конфиденциальные значения заменяются на cleansed_substitute.

get_traceback_frame_variables(request, tb_frame)

Возвращает отфильтрованный словарь локальных переменных для заданного кадра трассировки. Конфиденциальные значения заменяются на cleansed_substitute.

Если вам необходимо настроить отчеты об ошибках помимо фильтрации, вы можете указать класс специального отчета об ошибках, определив :setting:параметр DEFAULT_EXCEPTION_REPORTER:

DEFAULT_EXCEPTION_REPORTER = "path.to.your.CustomExceptionReporter"

Репортер исключений отвечает за компиляцию данных отчета об исключениях и форматирование их в виде текста или HTML соответствующим образом. (Репортер исключений использует DEFAULT_EXCEPTION_REPORTER_FILTER при подготовке данных отчета об исключениях.)

Ваш пользовательский класс репортера должен наследоваться от django.views.debug." "ExceptionReporter.

class ExceptionReporter
html_template_path

Свойство, возвращающее pathlib.Path, представляющее абсолютный путь в файловой системе к шаблону для визуализации HTML-представления исключения. По умолчанию используется шаблон, предоставленный Django.

text_template_path

Свойство, возвращающее pathlib.Path, представляющее абсолютный путь в файловой системе к шаблону для рендеринга текстового представления исключения. По умолчанию используется шаблон, предоставленный Django.

get_traceback_data()

Вернуть словарь, содержащий трассировочную информацию.

Это основная точка расширения для настройки отчетов об исключениях, например:

from django.views.debug import ExceptionReporter


class CustomExceptionReporter(ExceptionReporter):
    def get_traceback_data(self):
        data = super().get_traceback_data()
        # ... remove/add something here ...
        return data
get_traceback_html()

Вернуть HTML-версию отчета об исключении.

Используется для HTML-версии отладочной страницы ошибки HTTP 500.

get_traceback_text()

Вернуть текстовую версию отчета об исключении.

Используется для текстовой версии страницы отладки 500 HTTP-ошибки и отчетов по электронной почте.

Как и в случае с классом фильтра, вы можете контролировать, какой класс отчета об исключениях использовать в любом заданном представлении, установив атрибут HttpRequest exception_reporter_class:

def my_view(request):
    if request.user.is_authenticated:
        request.exception_reporter_class = CustomExceptionReporter()
    ...

См.также

Вы также можете настроить пользовательские отчеты об ошибках, написав пользовательский фрагмент exception middleware. Если вы пишете пользовательскую обработку ошибок, хорошей идеей будет эмулировать встроенную обработку ошибок Django и сообщать/регистрировать ошибки только в том случае, если DEBUG имеет значение False.

Back to Top