LoginSignup
20
19

More than 3 years have passed since last update.

【Django】ログ出力機能について簡単にまとめる

Last updated at Posted at 2020-10-14

はじめに

DjangoのLogging機能って初見だとよくわからない内容もありますよね。特に設定ファイル。
簡単・簡潔にまとめていきます。

本番環境想定の設定ファイル

ログの設定ですが、自分で設定を行わない場合(settings.pyにLOGGINGの定義が無い場合)Djangoソース内に含まれているデフォルト設定が使用されます。
しかし、出力されるログがあまり見やすくないので自分で設定する場合がほとんどです。
以下、本番環境を想定した設定例です。settings.pyに以下内容を追記します。

settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    # ログ出力フォーマットの設定
    'formatters': {
        'production': {
            'format': '%(asctime)s [%(levelname)s] %(process)d %(thread)d '
                      '%(pathname)s:%(lineno)d %(message)s'
        },
    },
    # ハンドラの設定
    'handlers': {
        'file': {
            'level': 'INFO',
            'class': 'logging.FileHandler',
            'filename': '/var/log/{}/app.log'.format(PROJECT_NAME),
            'formatter': 'production',
        },
    },
    # ロガーの設定
    'loggers': {
        # 自分で追加したアプリケーション全般のログを拾うロガー
        '': {
            'handlers': ['file'],
            'level': 'INFO',
            'propagate': False,
        },
        # Django自身が出力するログ全般を拾うロガー
        'django': {
            'handlers': ['file'],
            'level': 'INFO',
            'propagate': False,
        },
    },
}

使用例

views.py
import logging

logger = logging.getLogger(__name__)
logger.info("log info test!")
logger.error("log error test!")

ログには重要度に応じた5段階のレベルが設定されています。
上記使用例のようにloggerにログレベルと同名のメソッドを実行させることでログを出力することができます。

名前 用途
DEBUG デバッグの記録
INFO 正常動作の記録
WARNING 警告の記録
ERROR エラーなど重大な問題
CRITICAL システム自体の停止など致命的な問題

主要設定項目を見ていく

disable_existing_loggers

Tureの場合は設定ファイルで定義されていないloggerが全て無効化されます。
この段階だと「設定ファイルで定義されてないloggerってなに?」と思うかもしれませんが、意味としては後述するlogger項目で定義されていない名称のloggerが全て無効化されることになります。
基本的にFalseでOKだと思いますがこちらの記事で詳しく検証されているので気になる方はご確認ください。

formatters

ログ出力の書式設定です。
ここできちんと設定しておくとログの出力フォーマットが揃ってログが見やすくなるので、設定必須と思っても良いです。
%(asctime)や%(levelname)が何を意味しているかは公式ドキュメントに日本語でわかりやすく記載されています。

handlers

ログの出力方法についての設定です。

  • level
    ここで設定したログレベル以下のログは出力されなくなります。
  • class
    ログ出力に使用するクラスです。この例ではファイルに出力するクラスを指定しています。
    ログファイルをローテーションしたい(ファイルサイズや日付単位でファイルが分かれて欲しい)場合は'logging.handlers.RotatingFileHandler'や'logging.handlers.TimedRotatingFileHandler'を使用すると便利です(実際のやり方はこちらの記事に詳しく書かれています)。
    他には例えば'logging.StreamHandler'を指定するとコンソールに出力されます。
  • filename
    ログ出力するファイルのパスとファイル名を指定できます。
  • formatter
    先に定義したformatterのうちどれを使用するかを指定します。

loggers

実際にアプリから使用するloggerの設定です。
「''」で定義しているロガーは出力例にならった記述で

import logging
logger = logging.getLogger(__name__)

各アプリケーションから取得できます。
基本的にはこれとdjango自身が出力するloggerの設定があれば十分です。

  • handlers
    先に定義したhandlersのうちどれを使用するかを指定します。
  • level
    handlersでの定義同様、ここで設定したログレベル以下のログは出力されなくなります。
  • propagate
    これは+αの内容になるので興味が無い方は基本にFalseでOKぐらいに思っておいても問題無いです。

以下、propagateについての解説です。
loggerは実は名前空間を持つことができます
例として下記のような'logA'と'logA.logB'を定義します。

    'logger': {
        'logA': {
            'handlers': ['file'],
            'level': 'INFO',
            'propagate': False,
        },
        'logA.logB': {
            'handlers': ['file'],
            'level': 'INFO',
            'propagate': False,
        },

そしてアプリケーションから以下のようにloggerを取得します。

views.py
import logging

logger = logging.getLogger('logA.logB.logC')
logger.info("log info test!")

この時logCは定義されていないので結果としてlogBが取得されます
指定されたloggerが無い場合は上の名前空間に上がっていって、最初に見つけたものを取得するイメージです。

ここで、もしlogBとlogCも定義されており、かつpropagateがTrueだった場合、logA,logB,logC全てに対して

logger.info("log info test!")

が実行されます。つまり、logA,logB,logCの設定が名前以外同じだった場合、全く同じ内容のログが3重に出力されます
propagate(伝播)の名前通り、上の階層のloggerにもログ出力命令が伝播するんですね。
使いどころとしてはlogAにファイル出力用の設定、logBにコンソール出力用の設定をしておいて、ファイルだけで良い場合はlogAを取得、開発環境等でコンソールにも出したい場合はlogBを取得するようなイメージでしょうか(使ったこと無いですが…)。

 
 

以上です。最後は少し込み入った内容になってしまいましたが、複雑なことをしない限りこの記事に書いてある内容だけで基本的な設定はOKだと思います。
お疲れ様でした:cat2:

20
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
19