ロギングの設定と利用¶
Django はそのままで動作する デフォルトのロギング設定 を持っており、すぐに拡張可能です。
基本的なロギング呼び出しを作成する¶
ログメッセージをコード内から送信するには、コードにロギングの呼び出しを書く必要があります。
settings.py
でログ呼び出しを使用しようとしないでください。
Django のロギングは setup()
関数の一部として設定されるため、 settings.py
でロギングを呼び出しても期待通りに動作しないかもしれません。ロギングを調べるには、以下の例で推奨されているようにビュー関数を使用してください。
まず、Python の logging ライブラリをインポートし、logging.getLogger()
でロガーのインスタンスを取得します。getLogger()
メソッドに、ロガーとロガーが出力するレコードを識別するための名前を指定します。そのための良い方法は __name__
を使用することです (これについては以下の ロガーの名前空間を使う を参照してください)。これは、次のように、現在の Python モジュールの名前をドット区切りのパスで返します。
import logging
logger = logging.getLogger(__name__)
この宣言はモジュール・レベルで行うのがよいとされています。
そして、ビューなどの関数内で、logger にレコードを送信します。
def some_view(request):
...
if some_risky_state:
logger.warning("Platform is running at risk")
このコードが実行されると、そのメッセージを含む LogRecord
が logger に送られます。Django のデフォルトの logging 設定を使っている場合、メッセージはコンソールに表示されます。
上の例で使われている WARNING
レベルは、いくつかある ログの重大度レベル: DEBUG
, INFO
, WARNING
, ERROR
, CRITICAL
の一つです。したがって、別の例は次のようになります。
logger.critical("Payment system is not responding")
重要
WARNING
より低いレベルのレコードはデフォルトではコンソールに表示されません。この動作を変更するには追加の設定が必要です。
ロギングの設定をカスタマイズする¶
Djangoのロギング設定は初期状態で動作しますが、追加の設定を行うことで、ログを様々な宛先(ログファイル、外部サービス、メールなど)に送信するのを正確にコントロールできます。
以下のものを設定できます。
- どのレコードがどのハンドラに送られるかを決定するためのロガーマッピング
- 受け取ったレコードをどう処理するかを決めるハンドラー
- レコードの転送をさらにコントロールし、レコードをその場で変更することもできるフィルタ
LogRecord
オブジェクトを、人間や他のシステムで利用できるように文字列や他の形式に変換するためのフォーマッタ
ロギングの設定には様々な方法があります。Django では、 LOGGING
設定が最もよく使われます。この設定は dictConfig フォーマット を使い、 デフォルトのロギング設定 を拡張します。
カスタム設定が Django のデフォルトとどのようにマージされるかについては ロギングを設定する を参照してください。
その他のロギングの設定方法の詳細については Python logging documentation
を参照してください。簡単にするために、このドキュメントでは LOGGING
設定による設定のみを考えます。
ロギングの基本的な設定¶
ロギングを設定する場合、以下のようにします。
LOGGING
辞書を作成する¶
settings.py
に以下を追加します:
LOGGING = {
"version": 1, # the dictConfig format version
"disable_existing_loggers": False, # retain the default loggers
}
ほとんどの場合、 disable_existing_loggers
を False
に設定することで、デフォルトのロギング設定を保持し、拡張できます。
ハンドラを設定する¶
この例では、Python の FileHandler
を使って、レベル DEBUG
以上のログを (プロジェクトルート内の) general.log
ファイルに保存する file
という名前のハンドラを設定します:
LOGGING = {
# ...
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
},
},
}
異なるハンドラクラスは異なる設定オプションを取ります。利用可能なハンドラクラスの詳細については、 Django が提供する AdminEmailHandler
や Python が提供する様々な handler class
を参照してください。
ログレベルはハンドラで設定することもできます(デフォルトでは、ハンドラはすべてのレベルのログメッセージを受け取ります)。上の例を使うと、次のように書けます:
{
"class": "logging.FileHandler",
"filename": "general.log",
"level": "DEBUG",
}
これで、レベル DEBUG
以上のレコードだけを受け付けるようにハンドラを設定できます。
ロガーマッピングを設定する¶
このハンドラにレコードを送信するには、ロガーマッピングをそのハンドラを使うように設定します。例えば:
LOGGING = {
# ...
"loggers": {
"": {
"level": "DEBUG",
"handlers": ["file"],
},
},
}
マッピングの名前はどのログレコードを処理するかを決定します。この設定 (""
) は 無名 です。つまり、 すべての ロガーからのレコードを処理します(レコードを処理するロガーを決定するためにマッピング名を使用する方法については、以下の ロガーの名前空間を使う を参照してください)。
これは DEBUG
レベル以上のメッセージを file
というハンドラーに転送します。
ロガーは複数のハンドラーにメッセージを転送できるので、ロガーとハンドラーの関係は多対多であることに注意してください。
このコードを実行したら、:
logger.debug("Attempting to connect to API")
プロジェクトルートの general.log
ファイルにそのメッセージが保存されるでしょう。
フォーマッタを設定する¶
デフォルトでは、最終的なログ出力には各 log record
のメッセージ部分が含まれます。追加データを含めたい場合はフォーマッタを使います。まずフォーマッタに名前を付けて定義します。この例では verbose
と simple
という名前のフォーマッタを定義しています:
LOGGING = {
# ...
"formatters": {
"verbose": {
"format": "{name} {levelname} {asctime} {module} {process:d} {thread:d} {message}",
"style": "{",
},
"simple": {
"format": "{levelname} {message}",
"style": "{",
},
},
}
style
キーワードを使用すると、 str.format()
用の {
または string.Template
フォーマット用の $
を指定できます。デフォルトは $
です。
含めることができる LogRecord
属性については LogRecord attributes を参照してください。
ハンドラにフォーマッタを適用するには、ハンドラの辞書に formatter
エントリを追加します:
"handlers": {
"file": {
"class": "logging.FileHandler",
"filename": "general.log",
"formatter": "verbose",
},
}
ロガーの名前空間を使う¶
無名のロギング設定 ""
は任意の Python アプリケーションからログを取り込みます。名前付きロギング設定は、一致する名前のロガーからだけログを取得します。
logger インスタンスの名前空間は getLogger()
を使って定義します。例えば、 my_app
の views.py
で次のように定義します:
logger = logging.getLogger(__name__)
これは my_app.views
名前空間にロガーを作成します。 __name__
を使うと、プロジェクト内のアプリケーションにおけるログメッセージの出所に基づいて、自動的にそれらを整理できます。また、それによって名前の衝突が起こらなくなります。
my_app.views
という名前のロガーマッピングは、このロガーからレコードを取得します:
LOGGING = {
# ...
"loggers": {
"my_app.views": {...},
},
}
my_app
という名前のロガーマッピングはより広く、 my_app
名前空間内のロガー(my_app.views
、my_app.utils
などを含む)からレコードを取得します:
LOGGING = {
# ...
"loggers": {
"my_app": {...},
},
}
ロガーの名前空間を明示的に定義することもできます:
logger = logging.getLogger("project.payment")
そして、それに応じてロガーマッピングを設定することもできます。
ロガーの階層と伝搬(propagation)を使う¶
ロガーの命名は 階層的 です。 my_app
は my_app.views
の親であり、 my_app.views
は my_app.views.private
の親です。特に指定がない限り、ロガーのマッピングは処理したレコードを親に伝播(propagate)します―― my_app.views.private
名前空間のロガーからのレコードは、 my_app
と my_app.views
の両方のマッピングで処理されます。
この動作を管理するには、定義したマッピングに "propagate"
キーを設定します:
LOGGING = {
# ...
"loggers": {
"my_app": {
# ...
},
"my_app.views": {
# ...
},
"my_app.views.private": {
# ...
"propagate": False,
},
},
}
propagate
のデフォルトは True
です。この例では、my_app.views.private
のログは親プロセスでは処理されませんが、 my_app.views
のログは親プロセスで処理されます。
レスポンシブなロギングを設定する¶
ロギングは、必要な情報ができるだけ多く含まれているときに最も有用であり、目的のために必要な情報だけが含まれているとなお嬉しいです。そして、必要な情報量は、あなたが何をしているかによって異なります。デバッグ中には、本番環境では過剰で役に立たないようなレベルの情報が必要になります。
必要な時に必要な詳細レベルを提供するように、ロギングを設定できます。これを実現するために手動で設定を変更するよりも良い方法は、環境に応じて自動的に設定を適用することです。
例えば、開発環境とステージング環境で環境変数 DJANGO_LOG_LEVEL
を適切に設定し、ロガーマッピングで次のように使用できます:
"level": os.getenv("DJANGO_LOG_LEVEL", "WARNING")
- 環境がより低いログレベルを指定しない限り、このコンフィギュレーションは重大度 WARNING
以上のレコードだけをハンドラに転送します。
設定の他のオプション(ハンドラの level
や formatter
オプションなど)も同様に管理できます。