web-dev-qa-db-ja.com

ファイルにログを記録して標準出力に出力するロガー構成

私はPythonのloggingモジュールを使っていくつかのデバッグ文字列をファイルに記録します。それに加えて、このモジュールを使って文字列も標準出力に出力したいと思います。どうやってこれをするの?私の文字列をファイルに記録するために、私は以下のコードを使います:

import logging
import logging.handlers
logger = logging.getLogger("")
logger.setLevel(logging.DEBUG)
handler = logging.handlers.RotatingFileHandler(
    LOGFILE, maxBytes=(1048576*5), backupCount=7
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)

その後、次のようなロガー関数を呼び出します。

logger.debug("I am written to the file")

ここで助けてくれてありがとう!

280
cerr

ルートロガーのハンドルを取得してStreamHandlerを追加するだけです。 StreamHandlerはstderrに書き込みます。本当にstderrよりもstdoutが必要かどうかはわかりませんが、これは私がPythonロガーをセットアップするときに使用するものであり、FileHandlerも追加します。それから私のすべてのログは両方の場所に行きます(それはあなたが望むように聞こえるものです)。

import logging
logging.getLogger().addHandler(logging.StreamHandler())

stdoutではなくstderrに出力したい場合は、それをStreamHandlerコンストラクターに指定するだけです。

import sys
# ...
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))

Formatterを追加して、すべてのログ行に共通のヘッダーを付けることもできます。

すなわち:

import logging
logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s")
rootLogger = logging.getLogger()

fileHandler = logging.FileHandler("{0}/{1}.log".format(logPath, fileName))
fileHandler.setFormatter(logFormatter)
rootLogger.addHandler(fileHandler)

consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
rootLogger.addHandler(consoleHandler)

以下の形式で印刷します。

2012-12-05 16:58:26,618 [MainThread  ] [INFO ]  my message
365
Waterboy

logging.basicConfig() はPython 3.3からキーワード引数handlersを取ることができます。これはロギング設定を非常に単純化します。

handlers - 指定された場合、これはルートロガーに追加するために既に作成されたハンドラのイテラブルであるべきです。まだフォーマッタセットを持っていないハンドラには、この関数で作成されたデフォルトのフォーマッタが割り当てられます。

したがって、受け入れられた答えからのかなり長くて冗長な例のコードはまさにこれになります:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s",
    handlers=[
        logging.FileHandler("{0}/{1}.log".format(logPath, fileName)),
        logging.StreamHandler()
    ])

(または、元の質問の要件に応じてimport sys + StreamHandler(sys.stdout)で)

ロガーを取得するには、

logger = logging.getLogger()

スクリプトの後半で、便利なロギングメッセージを出力するためにlogger.info()を使用してください。

148
Yirkha

引数なしでStreamHandlerを追加すると、標準出力ではなく標準エラー出力になります。他のプロセスが標準出力ダンプに依存している場合(つまりNRPEプラグインを作成するとき)、明示的に標準出力を指定するようにしてください。そうしないと予期しない問題が発生する可能性があります。

質問からの想定値とLOGFILEを再利用する簡単な例を示します。

import logging
from logging.handlers import RotatingFileHandler
from logging import handlers
import sys

log = logging.getLogger('')
log.setLevel(logging.DEBUG)
format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")

ch = logging.StreamHandler(sys.stdout)
ch.setFormatter(format)
log.addHandler(ch)

fh = handlers.RotatingFileHandler(LOGFILE, maxBytes=(1048576*5), backupCount=7)
fh.setFormatter(format)
log.addHandler(fh)
62
Hazok

他のハンドラの設定やメッセージのロギングの前に、引数としてstream=sys.stdoutを指定してbasicConfigを実行するか、または標準出力にメッセージをプッシュするStreamHandlerを手動でルートロガー(または、その他の任意のロガー)に追加します。

19
Silas Ray

Waterboyのコードを複数のPythonパッケージで何度も使用した後、私はついにそれを小さなスタンドアロンのPythonパッケージにキャストしました。

https://github.com/acschaefer/duallog

コードはよく文書化されていて使いやすいです。単に.pyファイルをダウンロードしてあなたのプロジェクトに含めるか、pip install duallogを通してパッケージ全体をインストールしてください。

2
Lexxer