Python 3.3.5とロギングモジュールを使用して、(異なるスレッドからの)ローカルファイルに情報を記録しています。知らないうちに追加情報を出力したい場合があります。その情報が正確にどのようになるか(たとえば、1行のテキストまたはdictの場合があります)。
私がやりたいのは、ログレコードが書き込まれた後、この追加情報をログファイルに追加することです。さらに、追加情報は、ログレベルがエラー(またはそれ以上)の場合にのみ必要です。
理想的には、次のようになります。
2014-04-08 12:24:01 - INFO - CPU load not exceeded
2014-04-08 12:24:26 - INFO - Service is running
2014-04-08 12:24:34 - ERROR - Could not find any active server processes
Additional information, might be several lines.
Dict structured information would be written as follows:
key1=value1
key2=value2
2014-04-08 12:25:16 - INFO - Database is responding
カスタムログフォーマッターを作成する以外に、自分の要件に合うものを見つけることができませんでした。フィルタとコンテキストについて読んだことがありますが、これもよく一致していないようです。
または、標準のI/Oを使用してファイルに書き込むこともできますが、ほとんどの機能はすでにLoggingモジュールに存在し、さらにスレッドセーフです。
任意の入力をいただければ幸いです。カスタムログフォーマッターが本当に必要な場合は、どこから始めればよいかを示すポインターがあれば素晴らしいでしょう。
出力テキストに\n
記号を追加するだけです。
多くの人が複数行のログメッセージを悪い習慣だと考えていることを念頭に置いて、extra
属性で遊んで、カスタムフォーマッターを使用して、表示されるメッセージに内容を追加できます(見てください)ロギングパッケージの「extra」の使用法へ ドキュメント )。
import logging
class CustomFilter(logging.Filter):
def filter(self, record):
if hasattr(record, 'dct') and len(record.dct) > 0:
for k, v in record.dct.iteritems():
record.msg = record.msg + '\n\t' + k + ': ' + v
return super(CustomFilter, self).filter(record)
if __name__ == "__main__":
logging.getLogger().setLevel(logging.DEBUG)
extra_logger = logging.getLogger('extra_logger')
extra_logger.setLevel(logging.INFO)
extra_logger.addFilter(CustomFilter())
logging.debug("Nothing special here... Keep walking")
extra_logger.info("This shows extra",
extra={'dct': {"foo": "bar", "baz": "loren"}})
extra_logger.debug("You shouldn't be seeing this in the output")
extra_logger.setLevel(logging.DEBUG)
extra_logger.debug("Now you should be seeing it!")
そのコードは以下を出力します:
DEBUG:root:Nothing special here... Keep walking
INFO:extra_logger:This shows extra
foo: bar
baz: loren
DEBUG:extra_logger:Now you should be seeing it!
カスタムフィルターでsuper
のfilter
関数を呼び出すことをお勧めします。これは主に、メッセージを表示するかどうかを決定する関数であるためです(たとえば、ロガーのレベルがlogging.INFO
に設定されている場合、 extra_logger.debug
を使用して何かをログに記録すると、上記の例に示すように、そのメッセージは表示されないはずです)
LogFormatter文字列を定義するときに小さなタイプミスをしたようです。誤って改行文字をエスケープしたため、ログファイルに複数行の出力を書き込むことができないと誤って想定していました。
これを指摘してくれた@Barafuに乾杯(それが私が彼に正しい答えを割り当てた理由です)。
サンプルコードは次のとおりです。
import logging
lf = logging.Formatter('%(levelname)-8s - %(message)s\n%(detail)s')
lh = logging.FileHandler(filename=r'c:\temp\test.log')
lh.setFormatter(lf)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
log.addHandler(lh)
log.debug('test', extra={'detail': 'This is a multi-line\ncomment to test the formatter'})
結果の出力は次のようになります。
DEBUG - test
This is a multi-line
comment to test the formatter
ログに記録する詳細情報がなく、空の文字列を渡した場合でも、ロガーは改行を出力します。したがって、残りの質問は、これをどのように条件付きにすることができるかということです。
1つのアプローチは、説明されているように、実際に情報をログに記録する前に、ログフォーマッターを更新することです ここ 。
私は小さなアプリケーションで単純なラインスプリッターを使用しています:
_for line in logmessage.splitlines():
writemessage = logtime + " - " + line + "\n"
logging.info(str(writemessage))
_
これはスレッドセーフではなく、おそらくログボリュームロギングアプリケーションでのみ使用する必要があることに注意してください。
ただし、フォーマットが保持されるため、ほとんど何でもログに出力できます。たとえば、json.dumps(parsed, indent=4, sort_keys=True)
を使用してフォーマットされたJSONAPI応答を出力するために使用しました。