# Django 5.2.9 ドキュメント

# ロギング

参考

- ロギングの設定と利用

- Django ロギング リファレンス

Python プログラマは、素早く便利なデバッグツールとして、コード内で `print()` をよく使います。ロギングフレームワークを使用するのはわずかな手間がかかるだけですが、それよりはるかにエレガントで柔軟です。デバッギングに便利であることに加えて、ロギングは、アプリケーションの状態と健全性に対して、よりよく構造化されたより多くの情報も提供してくれます。

## 概要

Django は、システムのロギングを実行するために、Python 組み込みの `logging` モジュールを使用・拡張しています。このモジュールは、Python 自体のドキュメントで詳細に解説されています。このセクションでは、簡単な概要を説明します。

### 登場人物

Pythonのロギングは4つの部分で構成されます。

- ロガー

- ハンドラ

- フィルタ

- フォーマッタ

#### ロガー

ロガー は、ロギングシステムのエントリーポイントです。各ロガーは処理が記述されたメッセージの名前付けされたバケットです。

ロガーには ログレベル が設定されています。このログレベルはハンドリングされたログメッセージの深刻さを表しています。Pythonは下記のログレベルを定義しています。

- `DEBUG`: デバッグのための低レベルシステム情報

- `INFO`: 一般的なシステム情報

- `WARNING`: 重要度の小さい問題が発生したことを示す情報

- `ERROR`: 大きな問題が発生したことを示す情報

- `CRITICAL`: 重大な問題が発生したことを示す情報

ロガーに記載された各メッセージは ログレコード です。各ログレコードは、特定のメッセージの重要性を表す ログレベル を持ちます。ログレコードには、記録されたイベントを説明するメタデータを含むことができます。これには、スタックトレースやエラーコードと言った詳細を含めることができます。

ロガーにメッセージが渡されたとき、メッセージのログレベルはロガーのログレベルと比較されます。メッセージのログレベルがロガー自体のログレベルと同等以上の場合、メッセージは次の処理に進みます。それ以外の場合、メッセージは無視されます。

ロガーによってメッセージの処理が必要だと判断された場合、メッセージは ハンドラ に渡されます。

#### ハンドラ

ハンドラ は、ロガー上で書くメッセージに何をするかを決定するための原動力です。ここで、メッセージを表示する、ファイルに書き込む、ネットワークソケットに送信する、といった特定のロギング動作を記述します。

ロガーと同様に、ハンドラもログレベルを持ちます。ログレコードのログレベルがハンドラのレベルに満たない場合、ハンドラはメッセージを無視します。

ロガーには複数のハンドラを設定でき、また各ハンドラは異なるログレベルを持つことができます。この方法により、メッセージの重要性に応じて通知方法を変えることができます。たとえば、`ERROR` と `CRITICAL` メッセージを呼び出しサービスに転送するハンドラを設定する一方で、後で分析するために (`ERROR` や `CRITICAL` も含む) すべてのメッセージをファイルに記録する 2 つめのハンドラを設定できます。

#### フィルタ

フィルタ は、どのログレコードがロガーからハンドラへ渡されるかについて、追加的なコントロールを提供します。

デフォルトでは、ログレベル要件を満たしたすべてのログメッセージが処理されます。しかし、フィルタを使用することで、ロギングのプロセスに追加的な要件を設定できます。たとえば、特定のソースからの `ERROR` のみを処理するようにフィルタを設定することができます。

フィルタは、処理前にログレコードを修正するためにも使えます。たとえば、特定の条件を満たした場合に `ERROR` ログレコードを `WARNING` レコードに格下げさせるようなフィルタを設定できます。

フィルタは、ロガーもしくはハンドラに対して設定できます; 複数のフィルタを使って複数のフィルタ動作を連鎖させることも可能です。

#### フォーマッタ

最終的には、ログレコードはテキストとして表現される必要があります。 フォーマッタ はこのテキストの書式を定義します。フォーマッタは、通常は Python の文字列フォーマットで、LogRecord 属性 を含みます; しかし、特定の書式設定を行うような独自のフォーマッタを記述することもできます。

## セキュリティへの影響

ロギングシステムは潜在的にセンシティブな情報を取り扱うことになります。たとえば、ログレコードにはウェブリクエストやスタックトレースに関する情報が含まれることがありますが、ロガーで収集されたデータの一部にはセキュリティへの影響もあるかもしれません。あなたは次のことを理解しておく必要があります。

- どの情報を収集するか

- 最終的にその情報はどこに保存されることになるか

- その情報の転送はどのように行われるか

- その情報にアクセスする可能性があるのは誰か

センシティブな情報の収集をコントロールするために、特定のセンシティブな情報をエラーレポートからフィルタリングするように明示的に指定できます。その方法については エラーレポートをフィルタリングする を参照してください。

### `AdminEmailHandler`

組み込みの `AdminEmailHandler` はセキュリティの文脈で言及に値します。もし `include_html` オプションが有効なら、送信するメールには、スタックの各レベルのローカル変数の名前と値、そして Django の設定値（言い換えれば、 `DEBUG` が `True` のときに Web ページで公開されるのと同じレベルの詳細）が完全なトレースバックとして含まれます。

通常、このような潜在的にセンシティブな情報を電子メールで送信するのは良くないとされています。その代わりに、詳細なログを送信できる多くのサードパーティ・サービスを利用することで、完全なトレースバックによる豊富な情報、通知先や情報へのアクセス権の明確な管理など、複数の利点が得られます。

## ロギングを設定する

Python のロギングライブラリは、実用的なインターフェースから設定ファイルまで、ロギング設定のテクニックを提供しています。デフォルトでは、Django は dictConfig フォーマット を使用します。

ロギングを設定するためには、`LOGGING` を使用してロギング設定の辞書を定義します。この設定には、ロギングセットアップで使いたいロガー、ハンドラ、フィルタ、フォーマッタを記述し、それらのコンポーネントで使用したいログレベルとその他のプロパティを記述します。

デフォルトでは、`LOGGING` 設定は、以下のスキームを使って Django のデフォルトロギング設定 に統合されています。

`LOGGING` の `disable_existing_loggers` キーの値を `True` にすると、全てのデフォルトの設定が無効になります（キーが存在しない場合は `dictConfig` のデフォルトになります）。このため、 `'disable_existing_loggers': True` を使う場合は注意してください。 `True` を設定する必要は殆どないでしょう。 `disable_existing_loggers` を `False` に設定して、デフォルトのロガーの一部、または全てを定義しなおすこともできます。あるいは、 `LOGGING_CONFIG` を `None` に設定して、 ロギングの設定を自分で行うこと も出来ます。

ロギングは、一般的な Django の `setup()` 関数の一部として設定されます。したがって、ロガーが常にプロジェクトコード内で使用準備ができていることが保証されています。

### 例

dictConfig フォーマット に関する完全なドキュメントが、ロギング設定ディクショナリの最高の教材です。とはいえ、どんなことが可能なのか知ってもらうため、以下にいくつかの例を示します。

最初に、全てのログメッセージをコンソールに出力するための最低限の設定がこちらです。

`settings.py`

    import os

    LOGGING = {
        "version": 1,
        "disable_existing_loggers": False,
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
            },
        },
        "root": {
            "handlers": ["console"],
            "level": "WARNING",
        },
    }

この設定では、 `root` という名前の親のロガーがあり、 `WARNING` レベル以上のメッセージを受け取ったら、 console ハンドラに送るようになっています。 level を `INFO` または `DEBUG` にすると、より詳細なメッセージも表示されるようになります。この設定は開発中に役に立ちます。

次に、より詳細なロギングを追加します。次の例は、ロギングシステムが django という名前のロガーからより多くのメッセージを出力するようにする方法を示しています。

`settings.py`

    import os

    LOGGING = {
        "version": 1,
        "disable_existing_loggers": False,
        "handlers": {
            "console": {
                "class": "logging.StreamHandler",
            },
        },
        "root": {
            "handlers": ["console"],
            "level": "WARNING",
        },
        "loggers": {
            "django": {
                "handlers": ["console"],
                "level": os.getenv("DJANGO_LOG_LEVEL", "INFO"),
                "propagate": False,
            },
        },
    }

デフォルトでは、この設定は、`INFO` 以上のメッセージを `django` ロガーからコンソールに送信します。このレベルは、デフォルト設定ではログレコードを表示するのが `DEBUG=True` のときだけであること以外、Django のデフォルトのロギング設定と同じです。Django はそのような `INFO` レベルのログはそこまで多くログ出力しません。しかし、この設定では、環境変数 `DJANGO_LOG_LEVEL=DEBUG` を設定することで、Django のすべての debug ログを表示できます。これにはすべてのデータベースクエリが含まれるため、非常に冗長です。

必ずしもコンソールに出力する必要はありません。django という名前のロガーをファイルに書き込むには、次のように設定します。

`settings.py`

    LOGGING = {
        "version": 1,
        "disable_existing_loggers": False,
        "handlers": {
            "file": {
                "level": "DEBUG",
                "class": "logging.FileHandler",
                "filename": "/path/to/django/debug.log",
            },
        },
        "loggers": {
            "django": {
                "handlers": ["file"],
                "level": "DEBUG",
                "propagate": True,
            },
        },
    }

この例を使用するときは、`'filename'` のパスを Django アプリケーションを実行しているユーザーが書き込み可能な場所に変更してください。

最後に、かなり複雑なロギングの設定の例です。

`settings.py`

    LOGGING = {
        "version": 1,
        "disable_existing_loggers": False,
        "formatters": {
            "verbose": {
                "format": "{levelname} {asctime} {module} {process:d} {thread:d} {message}",
                "style": "{",
            },
            "simple": {
                "format": "{levelname} {message}",
                "style": "{",
            },
        },
        "filters": {
            "special": {
                "()": "project.logging.SpecialFilter",
                "foo": "bar",
            },
            "require_debug_true": {
                "()": "django.utils.log.RequireDebugTrue",
            },
        },
        "handlers": {
            "console": {
                "level": "INFO",
                "filters": ["require_debug_true"],
                "class": "logging.StreamHandler",
                "formatter": "simple",
            },
            "mail_admins": {
                "level": "ERROR",
                "class": "django.utils.log.AdminEmailHandler",
                "filters": ["special"],
            },
        },
        "loggers": {
            "django": {
                "handlers": ["console"],
                "propagate": True,
            },
            "django.request": {
                "handlers": ["mail_admins"],
                "level": "ERROR",
                "propagate": False,
            },
            "myproject.custom": {
                "handlers": ["console", "mail_admins"],
                "level": "INFO",
                "filters": ["special"],
            },
        },
    }

このロギング設定は、以下のことを行います:

- 設定が「dictConfig バージョン 1」形式であることを明示します。 現在、これが唯一の dictConfig 形式のバージョンです。

- 2 つのフォーマッタを定義します:

  - `simple` は、ログレベル名 (例: `DEBUG`) とログメッセージを出力します。

    この `format` 文字列は標準の Python 文字列フォーマットで、各ログ行で出力される詳細を定義します。出力可能な詳細の全リストは Formatter Objects で確認できます。

  - `verbose` は、ログレベルの名称とログメッセージに加えて、時刻、プロセス、スレッド、ログメッセージを生成したモジュールを出力します。

- 2 つのフィルタを定義します:

  - `project.logging.SpecialFilter` は、エイリアス `special` を使っています。もしこのフィルタが追加の引数を必要とする場合、フィルタ設定の辞書に追加のキーとして提供できます。今回の場合、`SpecialFilter` をインスタンス化するときに、引数 `foo` に `bar` の値が与えられます。

  - `django.utils.log.RequireDebugTrue` は、`DEBUG` が `True` のときにレコードの処理を進めます。

- 2 つのハンドラを定義します:

  - `console` は、すべての `INFO` 以上のメッセージを `sys.stderr` に表示 (print) する `StreamHandler` クラスです。このハンドラは `simple` 出力フォーマットを使用します。

  - `mail_admins` は、`ERROR` (またはそれより上) のすべてのメッセージをサイトの `ADMINS` にメール送信する `AdminEmailHandler` クラスです。このハンドラは `special` フィルタを使用します。

- 3 つのロガーを設定します:

  - `django` は、すべてのメッセージを `console` ハンドラに渡します。

  - `django.request` は、すべての `ERROR` メッセージを `mail_admins` ハンドラに渡します。加えて、このロガーはメッセージを親に 伝えない よう設定されています。これは、`django.request` 内に記述されたログメッセージは `django` ロガーで処理されないことを意味します。

  - `myproject.custom` は `INFO` もしくはそれ以上のすべてのメッセージを渡し、`special` フィルタを 2 つのハンドラに引き渡します -- `console` と `mail_admins` です。これは、`INFO` 以上のレベルのメッセージがコンソールで表示され、さらに `ERROR` と `CRITICAL` のメッセージはメールでも出力されることを意味します。

### カスタムのロギング設定

ロガーの設定に Python の dictConfig フォーマットを使用したくない場合は、あなた自身の設定スキームを定義できます。

The `LOGGING_CONFIG` setting defines the callable that will be used to configure Django's loggers. By default, it points at Python's `logging.config.dictConfig()` function. However, if you want to use a different configuration process, you can use any other callable that takes a single argument. The contents of `LOGGING` will be provided as the value of that argument when logging is configured.

### ロギング設定を無効化する

ロギングを全く設定したくない (あるいは、自分のやり方でロギング手動で設定したい) なら、 `LOGGING_CONFIG` を `None` に設定することもできます。これにより、Django のデフォルトのロギング設定 を無効化できます。

`LOGGING_CONFIG` を `None` に設定すると、自動でロギングの設定が行われなくなるだけです。ロギング自体が使えなくなるわけではありません。自動でのロギング設定を無効化しても、Django はロギングのメソッドを呼び、もしログ設定がされていれば、そこに出力されます。

Django の自動でのロギング設定を無効化し、手動で設定する場合はこのようにします。

`settings.py`

    LOGGING_CONFIG = None

    import logging.config

    logging.config.dictConfig(...)

デフォルトの設定処理は、設定が完全にロードされた後にのみ `LOGGING_CONFIG` を呼ばないことに注意してください。対照的に、設定ファイル内で手動で設定するロギングは、ロギング設定を直ちにロードします。そのため、ロギング設定は、必ずロギングが依存しているすべての設定の 後に 書く必要があります。