DjangoでのPythonロギングのエレガントなセットアップ


101

私は満足できるDjangoでPythonロギングを設定する方法をまだ見つけていません。私の要件はかなり単純です:

  • イベントごとに異なるログハンドラー-つまり、異なるファイルにログを記録できるようにしたい
  • 私のモジュールのロガーへの簡単なアクセス。モジュールは少しの労力でロガーを見つけることができるはずです。
  • コマンドラインモジュールに簡単に適用できるはずです。システムの一部は、スタンドアロンのコマンドラインまたはデーモンプロセスです。ロギングはこれらのモジュールで簡単に使用できるはずです。

私の現在のセットアップは、logging.confログに記録する各モジュールでファイルとセットアップログを使用することです。それは正しくありません。

あなたが好きなログ設定はありますか?詳細を教えてください:どのように構成をセットアップするlogging.confか(コードで使用またはセットアップします)、どこで/いつロガーを開始するか、モジュールでどのようにロガーにアクセスするかなどです。


1
次のスクリーンキャストが役に立つかもしれません-ericholscher.com/blog/2008/aug/29/…。また、Djangoへのログインに対するより良いサポートがSimon Willisonによって提案されました(simonwillison.net/2009/Sep/28/poniesを参照)。
ドミニクロジャー

@Dominic Rodger-すでにDjangoでアプリの柔軟なロギングを行うことができます。これは主にDjango内部でのロギングを容易にするためのSimonの提案です。Pythonには辞書ベースの構成をPythonロギングに追加する作業が進んでおり、Djangoからそれを利用できます。
Vinay Sajip、2009年

回答:


57

これまでに見つけた最良の方法は、settings.pyでロギング設定を初期化することです-他にはありません。構成ファイルを使用するか、プログラムで段階的に行うことができます。これは、要件に依存します。重要なことは、通常はレベルロガーを使用して、必要に応じてハンドラーをルートロガーに追加することです。フィルターを使用して、適切なファイル、コンソール、syslogなどにイベントを取得します。もちろん、ハンドラーを他のロガーに追加することもできます。また、私の経験では、これは通常必要ありません。

各モジュールで、私はロガーを定義します

logger = logging.getLogger(__name__)

モジュールでイベントをログに記録するために使用します(さらに区別したい場合は)上記で作成したロガーの子であるロガーを使用します。

私のアプリが、settings.pyでログを設定しないサイトで使用される可能性がある場合は、次のようにNullHandlerをどこかに定義します。

#someutils.py

class NullHandler(logging.Handler):
    def emit(self, record):
        pass

null_handler = NullHandler()

そして、そのインスタンスが、ロギングを使用するアプリのモジュールで作成されたすべてのロガーに追加されていることを確認します。(注:NullHandlerはすでにPython 3.1のロギングパッケージに含まれており、Python 2.7に含まれる予定です。)したがって、

logger = logging.getLogger(__name__)
logger.addHandler(someutils.null_handler)

これは、settings.pyでのロギングを設定していないサイトでモジュールが適切に再生され、迷惑な「ロガーXYZのハンドラーが見つかりませんでした」というメッセージ(潜在的な警告)が表示されないようにするために行われます。誤って構成されたログ)。

このようにすると、指定した要件を満たします。

  • 現在のように、さまざまなイベントに対してさまざまなログハンドラーを設定できます。
  • モジュール内のロガーへの簡単なアクセス-使用getLogger(__name__)
  • コマンドラインモジュールに簡単に適用できます-それらもインポートしsettings.pyます。

更新:バージョン1.3以降、Djangoにはロギングのサポートが組み込まれていることに注意してください。


これには、すべてのモジュールに構成で定義されたハンドラーが必要です(fooのハンドラーを使用してfoo.barを処理することはできません)。groups.google.com/group/comp.lang.python/browse_thread/thread/…
アンドリュークック

1
クック@andrew:あなたはできるのハンドラを使用するfooハンドルイベントにに記録foo.bar。再 そのスレッド-fileConfigとdictConfigの両方に、古いロガーを無効にできないようにするオプションがあります。この問題を参照してください:bugs.python.org/issue3136は、問題bugs.python.org/issue2697の2か月後に発生しました -とにかく、2008
。– Vinay Sajip

null_handlerがすでに追加されているロガーを返すlogger = someutils.getLogger(__name__)場所を実行する方が良いのではないでしょうか?someutils.getLoggerlogging.getLogger
7yl4r 2016年

1
@ 7yl4r すべてのロガーをNullHandler追加する必要はありません-通常、パッケージ階層の最上位のロガーだけです。IMO、それはやりすぎです。
Vinay Sajip

122

私はこれがすでに解決された答えであることを知っていますが、django> = 1.3に従って、新しいロギング設定があります。

古いものから新しいものへの移行は自動ではないので、ここに書き留めておきます。

そしてもちろん、django docをチェックアウトしてください。

これは基本的にdjango-admin createproject v1.3で作成されたconfです-djangoの最新バージョンでは走行距離が変わる可能性があります:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'class': 'django.utils.log.AdminEmailHandler',
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        }
    }
}

この構造は、次のブロックを指示する標準のPythonロギングdictConfigに基づいています。

  • formatters -対応する値は、各キーがフォーマッターIDであり、各値が対応するFormatterインスタンスの構成方法を説明するディクテーションであるdictです。
  • filters -対応する値は、各キーがフィルターIDであり、各値が対応するFilterインスタンスの構成方法を説明するディクテーションであるdictになります。
  • handlers-対応する値は、各キーがハンドラーIDであり、各値が、対応するハンドラーインスタンスを構成する方法を説明するディクテーションであるdictです。各ハンドラには次のキーがあります。

    • class(必須)。これは、ハンドラクラスの完全修飾名です。
    • level(オプション)。ハンドラーのレベル。
    • formatter(オプション)。このハンドラーのフォーマッターのID。
    • filters(オプション)。このハンドラーのフィルターのIDのリスト。

私は通常、少なくともこれを行います:

  • .logファイルを追加する
  • このログに書き込むようにアプリを構成する

これは次のように変換されます:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
        },
        'simple': {
            'format': '%(levelname)s %(message)s'
        },
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'null': {
            'level':'DEBUG',
            'class':'django.utils.log.NullHandler',
        },
        'console':{
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'simple'
        },
        # I always add this handler to facilitate separating loggings
        'log_file':{
            'level': 'DEBUG',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(VAR_ROOT, 'logs/django.log'),
            'maxBytes': '16777216', # 16megabytes
            'formatter': 'verbose'
        },
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler',
            'include_html': True,
        }
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        'apps': { # I keep all my of apps under 'apps' folder, but you can also add them one by one, and this depends on how your virtualenv/paths are set
            'handlers': ['log_file'],
            'level': 'INFO',
            'propagate': True,
        },
    },
    # you can also shortcut 'loggers' and just configure logging for EVERYTHING at once
    'root': {
        'handlers': ['console', 'mail_admins'],
        'level': 'INFO'
    },
}

編集する

参照要求の例外は、現在常にログインしているチケット#16288

上記のサンプル設定を更新して、mail_adminsの正しいフィルターを明示的に含めるようにしたので、デフォルトでは、debugがTrueの場合にメールは送信されません。

フィルターを追加する必要があります:

'filters': {
    'require_debug_false': {
        '()': 'django.utils.log.RequireDebugFalse'
    }
},

そして、それをmail_adminsハンドラーに適用します。

    'mail_admins': {
        'level': 'ERROR',
        'filters': ['require_debug_false'],
        'class': 'django.utils.log.AdminEmailHandler',
        'include_html': True,
    }

それ以外の場合、django.core.handers.base.handle_uncaught_exceptionsettings.DEBUGがTrueの場合、エラーは 'django.request'ロガーに渡されません。

Django 1.5でこれを行わないと、

DeprecationWarning: 'mail_admins'ロギングハンドラーにフィルターが定義されていません:暗黙のdebug-false-onlyフィルターを追加しています

ただし、django 1.4とdjango 1.5のどちらでも、正常に機能します。

**編集を終了**

そのconfはdjango docのサンプルconfに強く触発されていますが、ログファイルの部分が追加されています。

私はしばしば次のことも行います:

LOG_LEVEL = 'DEBUG' if DEBUG else 'INFO'

...
    'level': LOG_LEVEL
...

次に、私のPythonコードで、ロギング設定がまったく定義されていない場合に備えて、常にNullHandlerを追加します。これにより、ハンドラが指定されていない場合の警告が回避されます。必ずしもDjangoでのみ呼び出されるわけではないライブラリ(ref)に特に有用

import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
class NullHandler(logging.Handler): #exists in python 3.1
    def emit(self, record):
        pass
nullhandler = logger.addHandler(NullHandler())

# here you can also add some local logger should you want: to stdout with streamhandler, or to a local file...

[...]

logger.warning('etc.etc.')

お役に立てれば!


ステファノ、詳細な回答をありがとう、とても役に立ちました。これは、1.3にアップグレードする価値があるかもしれません。
パランド

パランド、それは間違いなく(私見です!)django 1.3にステップアップする価値がありますが、スムーズな移行にはいくつかの注意点があります-問題が発生した場合は、新しいSOの質問を開いてください;-)
Stefano

ちなみに、私はまだこの種の設定とファイルログを使用していますが、制作のために歩哨に移動しました!
ステファノ

@climeよく私は答え自体でそれを説明しようとしました:logging confがまったく定義されていない場合に備えて。これにより、ハンドラが指定されていない場合の警告が回避されます。必ずしもDjangoでのみ呼び出されるわけではないライブラリ(参考文献)に特に役立ちます
Stefano

この定義の使い方がわかりません: 'null':{'level': 'DEBUG'、 'class': 'django.utils.log.NullHandler'、}
clime

9

ファイルurls.pyを使用して、トップレベルでのロギングを初期化しlogging.iniます。

の場所logging.iniはで提供されていますがsettings.py、それだけです。

次に、各モジュールは

logger = logging.getLogger(__name__)

テスト、開発、本番のインスタンスを区別するために、logging.iniファイルは異なります。ほとんどの場合、エラーのみでstderrに送られる「コンソールログ」があります。ログディレクトリに移動する通常のローリングログファイルを使用する「アプリケーションログ」があります。


最終的には、urls.pyの代わりにsettings.pyで初期化することを除いて、これを使用しました
Parand

logging.iniファイルでsettings.pyの設定をどのように使用しますか?たとえば、BASE_DIR設定が必要なので、ログファイルの保存場所を指定できます。
slypete

@slypete:logging.iniの設定は使用しません。ロギングはほとんど独立しているため、Django設定は使用しません。はい、何かを繰り返す可能性があります。いいえ、実用的な違いはあまりありません。
S.Lott

その場合、アプリのインストールごとに個別のlogging.iniファイルを使用します。
slypete

@slypete:インストールごとにsettings.pyがあります。また、インストールごとにlogging.iniがあります。さらに、おそらくインストールごとにApache confファイルもあるはずです。さらに、wsgiインターフェースファイル。あなたの言いたいことがよくわかりません。
S.Lott

6

現在、自分で作成したロギングシステムを使用しています。ロギングにはCSV形式を使用します。

django-csvlog

このプロジェクトはまだ完全なドキュメントを持っていませんが、私はそれに取り組んでいます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.