Pythonのロギングで改行を挿入する方法は?

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', datefmt='%H:%M:%S')
logging.info('hello')
logging.warning('\n new hello')

11:15:01 INFO こんにちは。 11:16:49警告  新しいハロー

ログが混み合っているので、asctimelevelnameの前に明示的に改行を挿入したいのです。これは format を変更することなく可能でしょうか?

logging` モジュールを調べ、少しググってみましたが、実行可能な方法は見つかりませんでした。

ソリューション

最初の方法は非常に簡単ですが、出力はあまりきれいではありません。2番目の方法は、あなたが望む正確な出力を生成しますが、少し複雑です。

方法1

空行を生成するには、空文字列を改行でログするだけです。

import logging
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(levelname)s %(message)s', datefmt='%H:%M:%S')
logging.info('hello')
logging.info('\n')
logging.warning('new hello')

出力は空の情報行を持つことになりますが、これはあまりきれいではありません。

16:07:26 INFO hello 16:07:26 INFO

16:07:26 WARNING 新しいhelloです。

方法2

このメソッドでは、2種類のハンドラを作成しました。一番よく使うのは console_handler です。改行が必要なときは、2つ目のハンドラである blank_handler に切り替えます。

import logging
import types

def log_newline(self, how_many_lines=1):
    # Switch handler, output a blank line
    self.removeHandler(self.console_handler)
    self.addHandler(self.blank_handler)
    for i in range(how_many_lines):
        self.info('')

    # Switch back
    self.removeHandler(self.blank_handler)
    self.addHandler(self.console_handler)

def create_logger():
    # Create a handler
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    console_handler.setFormatter(logging.Formatter(fmt="%(name)s %(levelname)-8s: %(message)s"))

    # Create a "blank line" handler
    blank_handler = logging.StreamHandler()
    blank_handler.setLevel(logging.DEBUG)
    blank_handler.setFormatter(logging.Formatter(fmt=''))

    # Create a logger, with the previously-defined handler
    logger = logging.getLogger('logging_test')
    logger.setLevel(logging.DEBUG)
    logger.addHandler(console_handler)

    # Save some data and add a method to logger object
    logger.console_handler = console_handler
    logger.blank_handler = blank_handler
    logger.newline = types.MethodType(log_newline, logger)

    return logger

if __name__ == '__main__':
    logger = create_logger()
    logger.info('Start reading database')
    logger.info('Updating records ...')
    logger.newline()
    logger.info('Finish updating records')

出力されるのは、見たいものだけです。

logging_test INFO    : Start reading database
logging_test INFO    : Updating records ...

logging_test INFO    : Finish updating records

議論

  • 完璧でない出力に我慢できるのであれば、方法1がおすすめです。これはシンプルで最小限の労力で済むという利点があります。
  • 2番目の方法は、正しく仕事をしますが、少し複雑です。これは2つの異なるハンドラを作成し、目標を達成するためにそれらを切り替えます。
  • 2番目の方法のもう一つの欠点は、loggingを検索して、loggerに置き換えることで、コードを変更しなければならないことです。このとき、logging.DEBUGのようなテキストはそのままにして、関連する部分のみを置き換えるように注意しなければなりません。
解説 (1)

異なる時間に異なるフォーマット文字列を使用する、カスタム Formatter を使用します。これは basicConfig() を使用しては行えません。

class MyFormatter(logging.Formatter):
    def format(self, record):
        # set self._fmt to value with or without newline,
        # as per your decision criteria
        # self._fmt = ...
        return super(MyFormatter, self).format(record)

あるいは、super メソッドを呼び出してから、文字列を変更して改行を挿入してから返すこともできます (例えば、行の長さに依存している場合など)。

解説 (1)

このような感じです。logging.basicConfig]1asctimelevelname の間に n を追加してください。

>>> logging.basicConfig(level=logging.DEBUG, format='%(asctime)s\n %(levelname)s %(message)s',datefmt='%H:%M:%S') 
解説 (1)