5

ログを追加する必要がある Python コードがいくつかあります。

私は常に、ロギング用に "DEBUG()"、"ERROR()" などの大きな C マクロのように見えるステートメントを好んでいました。トレースポイントが実際のコードと視覚的に区別できると、コードが読みやすくなります (オブジェクトはありません)。

また、モジュールごとのレベルでログ レベルを設定できるようにしたいと考えています。

これを実行できる「ログ」というモジュールを作成するにはどうすればよいですか (Python std ライブラリのログ モジュールを使用しながら)。

例えば:

ファイル: main.py

# This imports LOG_MODULE_NAME, DEBUG, WARN, etc
from log import *
import my_module

LOG_MODULE_NAME("main")

log.set_level("main", log.LVL_DEBUG)
log.set_level("my_module", log.LVL_WARN)

if __name__ == "__main__":
    foo = my_module.myFunc(2)

DEBUG("Exiting main.py")

ファイル: my_module.py

from log import *

LOG_MODULE_NAME("my_module")


def myFunc(x):
    DEBUG("Entering function")
    if x != 1:
         WARN("I thought it would be 1")
    DEBUG("Exiting function")
    return x+1

出力は次のようになると思います。

[WARN:my_module - my_module.py:9] I thought it would be 1
[DEBUG:main - main.py:11] Exiting main.py
4

4 に答える 4

4

@2rs2ts の概念を拡張するには、Python logging HOWTOに示されているように、モジュールごとにログを記録することもできます。

ロガーに名前を付けるときに使用する適切な規則は、ログを使用する各モジュールで、次のように名前を付けたモジュール レベルのロガーを使用することです。

logger = logging.getLogger(__name__) 

これは、ロガー名がパッケージ/モジュール階層を追跡することを意味し、ロガー名からイベントがログに記録される場所が直感的に明らかです

すべてのファイルの最初の 2 行を次のようにします。

import logging
logger = logging.getLogger(__name__) 

次に、簡単にカスタマイズできるモジュールごとのログを作成します。

次の方法でさまざまなレベルにログインできます。

logger.debug("I just saw this %s" , var )
logger.info("I just saw this %s" , var )
logger.warn("I just saw this %s" , var )

文字列テンプレート変数を として渡したことに注意してください。文字列をすぐにテンプレート化するためのもの*argではありません。%ロガーがログに記録するレベルよりも高く設定されている場合は、CPU サイクルを節約できます。loggingドキュメントには、そのようなトリックがいくつかあります。

ログレベルと、実行するアプリ/スクリプトにログオンする場所を設定できます。logging モジュールが残りを処理します。

于 2013-07-17T21:22:36.443 に答える
3

ロガーの名前でそれが使用されたモジュールを示したい場合は、ここでlogger.getLogger([name])説明されているように、モジュール関数を使用__name__して (オプションの) 引数として渡すことができます。

のような名前を使用したい場合はDEBUG()ファイルで次のようにします...

LOG_MODULE_NAME = logging.getLogger(__name__)

def DEBUG(msg):
    global LOG_MODULE_NAME
    LOG_MODULE_NAME.debug(msg)

グローバル名前空間が実際にPythonで機能する方法については明確ではありません...この回答は言う

各モジュールには独自の「グローバル」名前空間があります。

LOG_MODULE_NAMEモジュール間で衝突しないので、そのようにうまくいくと思います。

このアプローチにより、行が次のようになる1つのログファイルが得られると思います。

DEBUG:my_module:Entering function
WARN:my_module:I thought it would be 1
DEBUG:my_module:Exiting function
DEBUG:root:Exiting main.py

十分に内省的ではありませんか?inpsectプログラムの実行中にプログラムに関する多くの情報を提供するモジュールが必要です。たとえば、これは現在の行番号を取得します。

「モジュールごとのレベルでログレベルを設定する」というあなたのメモは、あなたがgetEffectiveLevel(). 次のように押しつぶすことができます。

LOG_MODULE_NAME = logging.getLogger(__name__)
MODULE_LOG_LEVEL = log.LVL_WARN

def DEBUG(msg):
    if MODULE_LOG_LEVEL = log.LVL_DEBUG:
        global LOG_MODULE_NAME
        LOG_MODULE_NAME.debug(msg)

loggingただし、各モジュールのログのレベルを動的に変更する方法を説明できるほどモジュールの経験がありません。

于 2013-07-17T21:10:04.680 に答える
1

よりクリーンなソリューションは、この他の質問にあります。ライブラリのログを構成するよりクリーンな方法は、各モジュールでこれらの数行を使用することです。

import logging
logging.getLogger(__name__).addHandler(logging.NullHandler())

あなたのメイン スクリプト (例: my script.py) は次のことを担当します。


あなたの例を見てください:

def myFunc(x):
    DEBUG("Entering function")
    if x != 1:
         WARN("I thought it would be 1")
    DEBUG("Exiting function")
    return x+1

そして期待される出力:

[WARN:my_module - my_module.py:9] I thought it would be 1
[DEBUG:main - main.py:11] Exiting main.py

DEBUG("Existing main.py")に起こったことをどのように把握しmain.py:11ますか? 明らかな答えは、フレームを調べて発信者が誰であるかを確認しない限り、できないということです。DEBUG()モジュールで関数を定義したい場合log.py、正しいレコードを取得できません。関数はマクロとは大きく異なります。関数を定義する必要があり、インライン置換がないため、実質的に同じフレームにいることはできません。

念のため、モジュールでイントロスペクションをinspect使用するソリューションを作成しました (注: これを製品コードとして実行しないでください) が、現実には、「この関数はどこで、どの行で呼び出されたのか?」という課題に答えるためにあります。いくつかの作業を行う必要があります。

  • bar.py

    # file: bar.py
    # this is just a module to show DEBUG works when used in a different module
    from log import DEBUG
    
    def baz():
        DEBUG('oh hai from baz')
    
  • log.py

    # file: log.py
    import inspect
    import logging
    
    def DEBUG(msg, *args):
        curframe = inspect.currentframe()
        try:
            # http://docs.python.org/2/library/inspect.html#inspect.getouterframes
            _, filename, _, code, _, _ = inspect.getouterframes(curframe, 2)[1]
            logging.debug('[%s:%s] '+msg, filename, code, *args)
        finally:
            del curframe
    
  • メインスクリプトscript.py

    # file: script.py
    # responsible for the logging setup.
    import logging
    from log import DEBUG
    from bar import baz
    
    def foo():
        DEBUG('oh hai')
    
    if __name__ == '__main__':
        logging.basicConfig()
        logging.root.setLevel(logging.DEBUG)
        foo()
        baz()
    

私のソリューションの明らかな問題は、rootロガーのみを使用することです。

$ python script.py 
DEBUG:root:[script.py:foo] oh hai
DEBUG:root:[/Users/dnozay/Desktop/bar.py:baz] oh hai from baz

これらすべての要素を考えると、 で既に利用可能な機能を再実装することはお勧めできませんlogging

于 2013-07-17T23:32:52.547 に答える