Djangoのログ出力について

先週投稿したOneToOneFieldの裏側で発行されているSQLを確認する の中でSQLをログ出力できるようにしていました。

そこについて、コピペで動いた!状態だったので、脱却するために調べました。

結論

DjangoではPythonloggingを利用しています。

logging.config.dictConfigをベースにした設定値を記述しているようでした。

コピペで動いていた設定値について

まず、先週は割愛していたLOGGING の内容を転記します。

LOGGING = {
    'version': 1,
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': False
        },
    },
}

60:Django ORMでどんなSQLが発行されているか気にしよう より引用しています。

定数 LOGGING

そもそもの定数値について。 リファレンスのページはこちら。

https://docs.djangoproject.com/en/5.0/ref/settings/#logging

前提として、Djangoにはデフォルトのログ設定がされています。

何も設定していない場合、例えばrunserver実行時にログが出ると思いますが、以下のリンク先の標準設定によってログ出力の内容が定義されています。

https://github.com/django/django/blob/main/django/utils/log.py#L18-L64

定数LOGGINGを設定することで、このログ設定を上書きするようになっている、という状態でした。

ref

詳細の内容については以下リンクに書かれています。

https://docs.djangoproject.com/en/5.0/ref/logging/

例えば、loggers では django.db.backends の設定がされていましたが、この内容についても書かれていて、SQLがDEBUGレベルで取得できることが分かります。

Messages relating to the interaction of code with the database. For example, every application-level SQL statement executed by a request is logged at the DEBUG level to this logger.

https://docs.djangoproject.com/en/5.0/ref/logging/#loggers

topics

また、概要について記述された以下のページが存在します。

https://docs.djangoproject.com/en/5.0/topics/logging/

ここでは、以下の4つについて触れていて、全体像がわかるように解説されています。

  • Logger
  • Handlers
  • Filters
  • Formatters

個人的にも最初、「それっぽい設定がされてあるのは分かるんだけど・・・」と思ったので、Djangoのloggingについて大まかに知るためには、まずここを読んだら良さそうでした(概要ですしね)。

それ以外にはversion という値についても記述がありました。

Identifies the configuration as being in ‘dictConfig version 1’ format. At present, this is the only dictConfig format version.

dictConfigPythonlogging.config.dictConfigのことで、以下のdictConfigのリファレンスにも書かれている内容がDjangoリファレンスでも書かれていることが確認できました。

version - to be set to an integer value representing the schema version. The only valid value at present is 1, but having this key allows the schema to evolve while still preserving backwards compatibility.

https://docs.python.org/3/library/logging.config.html#dictionary-schema-details

個人的には2, 3なども設定出来るかなと思ってましたが、これは設定できません。 ちなみに、設定した場合 ValueError が発生します。

Watching for file changes with StatReloader
Exception in thread django-main-thread:
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/threading.py", line 1073, in _bootstrap_inner
    self.run()
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/threading.py", line 1010, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/tatsuya/djangoTaskApp/venv/lib/python3.12/site-packages/django/utils/autoreload.py", line 64, in wrapper
    fn(*args, **kwargs)
  File "/Users/tatsuya/djangoTaskApp/venv/lib/python3.12/site-packages/django/core/management/commands/runserver.py", line 125, in inner_run
    autoreload.raise_last_exception()
  File "/Users/tatsuya/djangoTaskApp/venv/lib/python3.12/site-packages/django/utils/autoreload.py", line 87, in raise_last_exception
    raise _exception[1]
  File "/Users/tatsuya/djangoTaskApp/venv/lib/python3.12/site-packages/django/core/management/__init__.py", line 394, in execute
    autoreload.check_errors(django.setup)()
  File "/Users/tatsuya/djangoTaskApp/venv/lib/python3.12/site-packages/django/utils/autoreload.py", line 64, in wrapper
    fn(*args, **kwargs)
  File "/Users/tatsuya/djangoTaskApp/venv/lib/python3.12/site-packages/django/__init__.py", line 19, in setup
    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
  File "/Users/tatsuya/djangoTaskApp/venv/lib/python3.12/site-packages/django/utils/log.py", line 76, in configure_logging
    logging_config_func(logging_settings)
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/logging/config.py", line 912, in dictConfig
    dictConfigClass(config).configure()
  File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/logging/config.py", line 516, in configure
    raise ValueError("Unsupported version: %s" % config['version'])
ValueError: Unsupported version: 2

howto

ref, topics以外にhowtoページも存在します。

https://docs.djangoproject.com/en/5.0/howto/logging/

色々な設定方法についての解説がありますが、ここでは他のページで見られなかった propagate について解説されています。

これは定義したロガーの親に伝播させるかどうかの設定が出来るようなので、特定の子ロガーだけのログ処理を実行させるようなケースに設定出来るようでした。

内部ではPythonのloggingを利用している

dictConfigのくだりでlogging.config.dictConfigだと、少し触れましたが、loggingはPythonの標準組み込みライブラリのlogging が内部的に利用されています。

そのため、class で設定する logging.StreamHandler などはDjango側で定義されたクラスもありますが、ベースは logging.handlersになるようでした。

e.g. https://docs.python.org/ja/3/library/logging.handlers.html#logging.StreamHandler

調べてみて

内部で何を利用しているか?というところの理解が大事だなーと思いました。調べていく上で、謎の設定値が少しずつ読み解けました。

logging もそこまで詳しく無いので調べたい気持ちもありますが、全てを調べるには時間が足りないので一旦このくらいで。

他にも以下ページにはログ出力する方法とかも書かれていて、ケースに応じて利用できると良さそうだなと思いました。

https://docs.djangoproject.com/ja/5.0/topics/logging/#id5