11

Python アプリ内からログを実行するための標準的な設定は何かと思っていました。

私は Logging クラスを使用しており、Logging クラスをインスタンス化する独自のロガー クラスを作成しました。次に、メインがロガー ラッパー クラスをインスタンス化します。ただし、私のメインは他のクラスをインスタンス化し、それらの他のクラスもメインのロガーオブジェクトを介してログファイルに書き込めるようにしたいと考えています。

そのロガーオブジェクトを他のクラスから呼び出せるようにするにはどうすればよいですか? これを機能させるには、ある種の静的ロガー オブジェクトが必要なようです。

質問の要点は次のとおりだと思います。メイン内からインスタンス化されたすべてのクラスが同じログ ファイルに書き込むことができるように、コード構造内にログを実装するにはどうすればよいでしょうか。同じファイルを指す各クラスで新しいログ オブジェクトを作成する必要がありますか?

4

2 に答える 2

34

クラスが何を意味するのかわかりませんLogging-Pythonの組み込みロギングにはそのようなクラスはありません。ラッパーは実際には必要ありません。作成した任意のクラスからログを記録する方法の例を次に示します。

import logging

# This class could be imported from a utility module
class LogMixin(object):
    @property
    def logger(self):
        name = '.'.join([__name__, self.__class__.__name__])
        return logging.getLogger(name)


# This class is just there to show that you can use a mixin like LogMixin
class Base(object):
    pass

# This could be in a module separate from B
class A(Base, LogMixin):
    def __init__(self):
        # Example of logging from a method in one of your classes
        self.logger.debug('Hello from A')

# This could be in a module separate from A
class B(Base, LogMixin):
    def __init__(self):
        # Another example of logging from a method in one of your classes
        self.logger.debug('Hello from B')

def main():
    # Do some work to exercise logging
    a = A()
    b = B()
    with open('myapp.log') as f:
        print('Log file contents:')
        print(f.read())

if __name__ == '__main__':
    # Configure only in your main program clause
    logging.basicConfig(level=logging.DEBUG,
                        filename='myapp.log', filemode='w',
                        format='%(name)s %(levelname)s %(message)s')
    main()

通常、クラス レベルでロガーを使用する必要はありません。Python では、たとえば Java とは異なり、プログラム (分解) 構成の単位はモジュールです。ただし、上で示したように、それを止めるものは何もありません。スクリプトを実行すると、次のように表示されます。

Log file contents:
__main__.A DEBUG Hello from A
__main__.B DEBUG Hello from B

両方のクラスのコードが同じファイル myapp.log に記録されることに注意してください。これは、異なるモジュールの A と B でも機能します。

于 2013-04-05T13:58:19.030 に答える
6

logging.getLogger() を使用して、ロギング オブジェクト インスタンスを取得してみてください。

http://docs.python.org/3/library/logging.html#logging.getLogger

指定された名前でこの関数を呼び出すと、同じロガー インスタンスが返されます。これは、アプリケーションの異なる部分間でロガー インスタンスを渡す必要がないことを意味します。

更新

これを行うための推奨される方法は、getLogger() 関数を使用して構成することです (ハンドラー、フォーマッターなどの設定)。

# main.py
import logging
import lib


def main():
    logger = logging.getLogger('custom_logger')
    logger.setLevel(logging.INFO)
    logger.addHandler(logging.FileHandler('test.log'))
    logger.info('logged from main module')
    lib.log()

if __name__ == '__main__':
    main()

# lib.py
import logging


def log():
    logger = logging.getLogger('custom_logger')
    logger.info('logged from lib module')

本当にロガー クラスを拡張する必要がある場合は、 logging.setLoggerClass(klass)を見てください。

更新 2 :

Logging クラスを変更せずにカスタム ログ レベルを追加する方法の例:

# main.py
import logging
import lib


# Extend Logger class
CUSTOM_LEVEL_NUM = 9
logging.addLevelName(CUSTOM_LEVEL_NUM, 'CUSTOM')
def custom(self, msg, *args, **kwargs):
    self._log(CUSTOM_LEVEL_NUM, msg, args, **kwargs)
logging.Logger.custom = custom

# Do global logger instance setup
logger = logging.getLogger('custom_logger')
logger.setLevel(logging.INFO)
logger.addHandler(logging.FileHandler('test.log'))


def main():
    logger = logging.getLogger('custom_logger')
    logger.custom('logged from main module')
    lib.log()

if __name__ == '__main__':
    main()

カスタム レベルの追加は推奨されないことに注意してください: http://docs.python.org/2/howto/logging.html#custom-levels

カスタム ハンドラーを定義し、複数のロガーを使用することで、他の要件 (stderr へのオプションの出力) のトリックを実行できる場合があります。

于 2013-04-03T06:30:47.107 に答える