エラーレポートの管理

サイトを公開している場合、DEBUG 設定は常にオフにしておかなければなりません。これにより、サーバー動作は高速になり、エラーページによって明らかになるアプリケーションの詳細が悪意あるユーザーに漏れるのを防ぎます。

しかし、 DEBUGFalse にセットして実行すると、サイトによって生成されるエラーが見られなくなります――表示されるのは万人向けのエラーページだけです。そこで、本番サイトで起きたエラーを追跡するために、Django ではこれらのエラーに関する詳細なレポートを作成するように設定できます。

E メールのレポート

サーバーエラー

DEBUGFalse であるとき、コードがハンドリングされない例外を起こして内部サーバーエラーが起きると (厳密には、500 以上の HTTP ステータスコードを持つ全てのレスポンスが返ってくると)、Django は ADMINS 設定のリストに含まれるユーザーにメールを送信します。これにより、管理者はすぐにエラーの通知を受け取ることができます。メールには、ADMINS はエラーの説明、Python のトレースバック全体、エラーを引き起こした HTTP リクエストの詳細について書かれています。

注釈

メールを送信するために、Django はメールサーバーへの接続方法をいくつか設定する必要があります。最低限 EMAIL_HOST と、おそらく EMAIL_HOST_USEREMAIL_HOST_PASSWORD を指定する必要がありますが、メールサーバーの設定によっては他の設定も必要かもしれません。メール関連の設定の一覧は Django の設定のドキュメント を参照してください。

デフォルトでは、 Django は root@localhost からメールを送信します。しかし、メールプロバイダによっては、このアドレスからのメールを全て拒否します。別の送信者アドレスを使うには、 SERVER_EMAIL 設定を変更してください。

この動作を有効にするには、受信者のメールアドレスを ADMINS 設定に含めます。

参考

サーバーエラーのメールはロギングフレームワークを使って送信されるので、 ロギングの設定をカスタマイズする ことで動作を変更できます。

404 エラー

Django は、リンク切れに関するエラー (404 "page not found" エラー) をメールで送信するように設定することもできます。Django は以下の場合に 404 エラーに関するメールを送ります:

これらの条件が満たされると、Django はあなたのコードが 404 を発生させ、そのリクエストがリファラを持っている場合、 MANAGERS 設定にリストされているユーザにメールを送ります。リファラを持たない 404 にはわざわざメールを送りません。それは大抵、壊れた URL を入力したユーザか、壊れた Web ボットです。また、リファラがリクエストされた URL と同じ場合の 404 も無視します。

注釈

BrokenLinkEmailsMiddleware は、 LocaleMiddlewareFlatpageFallbackMiddleware のような 404 エラーを検出する他のミドルウェアよりも前に表示する必要があります。これを MIDDLEWARE 設定の一番上に置いてください。

特定の 404 を報告しないように Django に指示するには、 IGNORABLE_404_URLS 設定をいじります。これはコンパイルされた正規表現オブジェクトのリストでなければなりません。例えば:

import re

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

この例では、 .php または .cgi で終わる URL への 404 は報告されません。また、 /phpmyadmin/ で始まるURLも報告されません。

以下は、ブラウザやクローラがよくリクエストする従来の 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 は発生した例外の full traceback や、各 traceback frame のローカル変数、 HttpRequest属性 を記録します。

しかし、例えばユーザのパスワードやクレジットカード番号のように、ある種の情報は機密性が高すぎるため、記録するのが適切でない場合があります。そこで Django では、 DEBUG ドキュメントで説明されているように、機密性が高そうな設定をフィルタリングすることに加えて、本番環境 (つまり、 DEBUGFalse に設定されている場合) でエラーレポートからフィルタリングされる情報を制御するのに役立つ関数デコレータを提供しています。 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
    ...

上記の例では、 userpwcc の値は非表示になり、エラーレポートではアスタリスク (*******) に置き換えられますが、 name 変数の値は公開されます。

関数のすべてのローカル変数をエラーログから徹底的に隠す場合は、引数なしで 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)

もしビューの 1 つが 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_wordcredit_card_number のPOSTパラメータの値は隠され、エラーレポート内のリクエストの表現ではアスタリスク (*******) に置き換えられますが、 name パラメータの値は公開されます。

エラーレポートでリクエストの全てのPOSTパラメータを徹底的に隠す場合は、 引数なしで sensitive_post_parameters デコレータを使います:

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

特定の django.contrib.auth.views のビュー (auth admin 内の login, password_reset_confirm, password_change, auth admin の add_viewuser_change_password) のエラーレポートから、すべての POST パラメータが徹底的にフィルタされ、ユーザパスワードのような機密情報の漏洩を防ぎます。

Changed in Django 5.0:

async 関数のラップをサポートしました。

カスタムエラーレポート

sensitive_variables()sensitive_post_parameters() がすることは、それぞれ、装飾された関数にセンシティブな変数名をアノテートし、HttpRequest オブジェクトにセンシティブな POST パラメータ名をアノテートするだけです。実際のフィルタリングは Django のデフォルトのエラーレポートフィルタ ( django.views.debug.SafeExceptionReporterFilter ) で行われます。このフィルタはデコレータのアノテーションを使い、エラーレポートが生成される際に、対応する値をアスタリスク (*******) に置き換えます。このデフォルトの動作を上書きしたり、サイト全体でカスタマイズしたい場合は、独自のフィルタクラスを定義し、 DEFAULT_EXCEPTION_REPORTER_FILTER 設定でそれを使うように Django に指示する必要があります:

DEFAULT_EXCEPTION_REPORTER_FILTER = "path.to.your.CustomExceptionReporterFilter"

また、 HttpRequestexception_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)
Changed in Django 4.2:

HTTP_COOKIE が追加されました。

is_active(request)

get_post_parameters()get_traceback_frame_variables() のフィルタリングを有効にする場合は True を返します。デフォルトでは DEBUGFalse の場合に有効になります。 DEBUG のドキュメントにあるように、センシティブな request.META の値は常に、センシティブな設定値とともにフィルタリングされることに注意してください。

get_post_parameters(request)

フィルタリングされた POST パラメータの辞書を返します。センシティブな値は cleansed_substitute で置換されます。

get_traceback_frame_variables(request, tb_frame)

与えられたトレースバックフレームのローカル変数のフィルタリングされた辞書を返します。センシティブな値は cleansed_substitute で置き換えられます。

フィルタリングの他にエラーレポートをカスタマイズする必要がある場合は、 DEFAULT_EXCEPTION_REPORTER 設定を定義することでカスタムエラーレポータークラスを指定できます:

DEFAULT_EXCEPTION_REPORTER = "path.to.your.CustomExceptionReporter"

例外レポーターは例外レポートデータをコンパイルし、テキストまたはHTMLとして適切にフォーマットする責任があります。(例外報告レポーターは、例外レポートデータを作成する際に DEFAULT_EXCEPTION_REPORTER_FILTER を使用します)。

カスタムレポータークラスは django.views.debug.ExceptionReporter を継承する必要があります。

class ExceptionReporter
html_template_path

例外の HTML 表現をレンダリングするテンプレートへの絶対ファイルシステムパスを表す pathlib.Path を返すプロパティです。デフォルトは 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 版を返します。

デバッグ 500 HTTP エラー・ページの HTML 版に使用されます。

get_traceback_text()

例外レポートのプレーンテキスト版を返します。

デバッグ 500 HTTP エラーページおよび E メールレポートのプレーンテキスト版に使用されます。

フィルタクラスと同様に、 HttpRequestexception_reporter_class 属性を指定することで、任意のビューで使用する例外レポータークラスを制御できます:

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

参考

また、独自の 例外ミドルウェア を書くことで、独自のエラーレポートを設定することもできます。もしカスタムエラー処理を書くのであれば、 Django の組み込みエラー処理を真似て、 DEBUGFalse の場合のみエラーを報告/ログ出力するようにすると良いでしょう。

Back to Top