2013-04-08 3 views
15

タスクのPython:すべてのモジュール間でのカスタムログ

私は、スクリプトのコレクションを持っていると私は彼らが実際にメッセージをロギングやってモジュールに最小限の変更を加えた統合ログメッセージを生成したいと思います。

メインアプリケーションから一度呼び出す予定の小さなモジュール 'custom_logger'を作成しました。ロガーを返信してから、引き続き使用します。私のサイトに固有のものが必要とされないことを確認して - 私はアプリにインポートされると思い

サブモジュールのみ

  • のみ「ログとしてインポートログが」必要がある(というか私は彼らにしたい)すべきです他の誰かが有用であると判断した場合に実行されます。
  • はちょうどそのすべての書式設定や利きないと根 『ロガー影響を及ぼす"
  • 既に設定を使用する必要があり、それらにサイト固有の何かを追加せずに)』log.info/error('messageでメッセージをログに記録すべきルートロガーの設定

* custom_logger.py *

import logging 
import logging.handlers 
import os 
import sys 


def getLogger(name='root', loglevel='INFO'): 
    logger = logging.getLogger(name) 

    # if logger 'name' already exists, return it to avoid logging duplicate 
    # messages by attaching multiple handlers of the same type 
    if logger.handlers: 
    return logger 
    # if logger 'name' does not already exist, create it and attach handlers 
    else: 
    # set logLevel to loglevel or to INFO if requested level is incorrect 
    loglevel = getattr(logging, loglevel.upper(), logging.INFO) 
    logger.setLevel(loglevel) 
    fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
    fmt_date = '%Y-%m-%dT%T%Z' 
    formatter = logging.Formatter(fmt, fmt_date) 
    handler = logging.StreamHandler() 
    handler.setFormatter(formatter) 
    logger.addHandler(handler) 

    if logger.name == 'root': 
     logger.warning('Running: %s %s', 
        os.path.basename(sys.argv[0]), 
        ' '.join(sys.argv[1:])) 
    return logger 

そして、どのような作品の例とどのようなしないと、いくつかのテストメッセージを持つサブモジュールを付属しています。

submodule.py

import sys 
import custom_logger 
import logging 


class SubClass(object): 

    def __init__(self): 
    # NOK (no idea why since by default (no name parameter), it should return the root logger) 
    #log = logging.getLogger() 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    #log = logging.getLogger('root') 
    #log.info('message from SubClass/__init__') 

    # OK (works as expected) 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/__init__') 


    def SomeMethod(self): 
    # OK but I'd have to define `log` for every method, which is unacceptable 
    # Please see question below all code snippets 
    log = custom_logger.getLogger('root') 
    log.info('message from SubClass/SomeMethod') 

、メインアプリ:ここでは特別なapp.py何も:私は取得しています後とことだ

#!/usr/bin/python 

import custom_logger 
import submodule 

log = custom_logger.getLogger('root', loglevel='DEBUG') 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

出力、非常に醜い方法でちょうど:

% ./app.py 
2013-04-08T03:07:46BST custom_logger.py WARNING : Running: app.py 
2013-04-08T03:07:46BST app.py    DEBUG : debug message 
2013-04-08T03:07:46BST app.py    INFO : info message 
2013-04-08T03:07:46BST app.py    WARNING : warning message 
2013-04-08T03:07:46BST app.py    ERROR : error message 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T03:07:46BST submodule.py  INFO : message from SubClass/SomeMethod 

私はapp.pyでロガーを定義し、サブモジュールでは、標準のPythonロギングライブラリを使用して、app.pyで既に設定されているロガーを使用したいだけです。

また、醜い回避策:私はsubmodule.pyで輸入後に以下のコードを配置する場合:私のロガーを効果的にサブモジュールを作る、app.pyで設定される前に、

log = custom_logger.getLogger('root') 

それが実行されます、私のアプリはロギングを設定しません。

私は見なさ別の回避策:サブクラスクラスのconstuctor以内に、私は

self.log = custom_logger.getLogger('root')

を定義し、self.log.error( '何らかのエラー')使用することができます。より良い方法が必要です - 有用なものを提案したり、私がドキュメントを誤解した箇所を指摘したりすることができれば、非常に感謝しています!

PS。私はPythonのロギング(基本と高度)と料理本を読んでかなりの時間を費やしました。そこで役に立つものがなかったら、それを指摘してください。

ありがとうございました!

答えて

3

ルートロガーを変更したい場合は、どこでも引数なしでgetLogger()を使用できます。

メインモジュールのみのインスタンス設定に関しては、あなたのロガーをインスタンス化し、独自のハンドラを追加し、他のすべてのサブモジュールで使用することができます。 、

import sys 
import logging 

log = logging.getLogger('root') 

class SubClass(object): 

    def __init__(self): 
     log.info('message from SubClass/__init__') 

    def SomeMethod(self): 
     log.info('message from SubClass/SomeMethod') 

その後:

class MyHandler(logging.StreamHandler): 

    def __init__(self): 
     logging.StreamHandler.__init__(self) 
     fmt = '%(asctime)s %(filename)-18s %(levelname)-8s: %(message)s' 
     fmt_date = '%Y-%m-%dT%T%Z' 
     formatter = logging.Formatter(fmt, fmt_date) 
     self.setFormatter(formatter) 

その後、submodule.pyで、私は輸入後のgetLoggerを入れて、方法でそれを次のようにコメントし

私はcustom_logger.pyにStreamHandlerのを継承するクラスを作成しましたapp.pyでLoggerインスタンス(すべてのモジュールで同じ)を作成し、出力をフォーマットするハンドラを追加しました:

#!/usr/bin/python 

import logging 
import custom_logger 
import submodule 

log = logging.getLogger('root') 
log.setLevel('DEBUG') 
log.addHandler(custom_logger.MyHandler()) 

log.debug('debug message') 
log.info('info message') 
log.warning('warning message') 
log.error('error message') 

a = submodule.SubClass() # this should produce a log message 
a.SomeMethod()   # so should this 

出力:

./app.py 
2013-04-08T15:20:05EEST app.py    DEBUG : debug message 
2013-04-08T15:20:05EEST app.py    INFO : info message 
2013-04-08T15:20:05EEST app.py    WARNING : warning message 
2013-04-08T15:20:05EEST app.py    ERROR : error message 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/__init__ 
2013-04-08T15:20:05EEST submodule.py  INFO : message from SubClass/SomeMethod 
+0

はあなたのミハイをありがとうございます。私はそれを調べる時間が増えると思ったが、週末を待つ必要があるだろう。これまでは、submodule.pyでlogをgetLoggerオブジェクトとして定義することで、フォーマッタ、ハンドラ、ログレベルを設定したクラスを動作させることができました。私はクラス定義の外に物事を置くことなくこれを行うことができることを望んでいました。 私の質問は「私が行ったコードが私に渡されるのではなく、その裏の理由を理解したいので、私が作った特定のアプローチが期待どおりに機能しなかった理由はもっとありましたが、 ) –

+0

私の答えを更新しました。それ以外の場合は、モジュールのコードを見ることができます。インポート中にルートロガーがインスタンス化されていることがわかります。 (あなたはsubmodule.pyの中でapp.pyとgetLogger( "root")のgetLogger()を実行し、必要なものを得ることができますが、その逆はできません) – Mihai

+0

stdoutをファイルにリダイレクトする方法例えばpython ./app.py >> file.log? –

関連する問題