iMind Developers Blog

iMind開発者ブログ

Pythonのloguruでログ出力

概要

Pythonのログ出力は標準ライブラリがすんなりとは使いづらいので、ログをより簡単に扱えるライブラリ、loguruを使ってみる。

バージョン情報

  • Python 3.7.3
  • loguru==0.3.2

インストール

$ pip install loguru

シンプルな出力

importしてinfoするだけで整形されたフォーマットでログが出てくる。

from loguru import logger

logger.info('ほげ')
    #=> 2019-09-21 16:37:04.942 | INFO     | __main__:<module>:3 - ほげ

フォーマット指定

logger.addでフォーマットを指定できる。

import sys
from loguru import logger

# デフォルトのログをクリア
logger.remove()

# 標準出力にlevelで色分けしたログを出力する
logger.add(
    sys.stdout, 
    colorize=True,
    format="<blue>{time:YYYY-MM-DDTHH:mm:ss}</blue> <level>{level} {message}</level>")

logger.info('ほげ')
logger.warning('ほげ')
logger.error('ほげ')

実行結果。レベルに応じて色分けされたログが出力される。

f:id:imind:20190921203718p:plain

ファイル出力

ファイル名を指定してログを出力する。下記の指定では log.txt というファイルにログが出力される。

from loguru import logger

# ファイル指定でログを出力
logger.add(
    'log.txt',
    format="{time:YYYY-MM-DDTHH:mm:ss} {level} {message}")

logger.info('ほげ')

filterで指定のモジュールのみログに残す

bar.py というファイル名で下記を記述。

from loguru import logger

def bar():
    logger.info('ふが')

続いて __main__ でbarモジュールだけフィルタしてログを呼び出す。

import sys
from loguru import logger

# filterでbarだけ指定
logger.remove()
logger.add(
    sys.stdout,
    filter="bar",
    format="{time:YYYY-MM-DDTHH:mm:ss} {level} {message}")

# ここのmoduleは__main__扱い
logger.info('ほげ')

# barのログ出力を呼び出す
import bar
bar.bar()

これを実行するとbar側の記述だけ標準出力にログが出る。

例外の出力

exceptでlogger.exceptionすると例外の内容がログ出力できる。

try:
    raise Exception('何かしらエラー')
except:
    logger.exception('ほげ')

    #=> 2019-09-21T18:31:36 ERROR ほげ
    #=> Traceback (most recent call last):
    #=> 
    #=> > File "foo.py", line 12, in <module>
    #=>     raise Exception('何かしらエラー')
    #=> 
    #=> Exception: 何かしらエラー

関数内で発生した例外はdecoratorで取得できる。

@logger.catch
def foo():
    raise Exception('何かしらエラー')

try:
    foo()
except:
    pass

    #=> > File "foo.py", line 16, in <module>
    #=>     foo()
    #=>     └ <function foo at 0x7f0e00e348c8>
    #=> 
    #=>   File "foo.py", line 13, in foo
    #=>     raise Exception('何かしらエラー')
    #=> 
    #=> Exception: 何かしらエラー

ログレベルの指定

指定できるログレベルは下記(昇順)。

  • TRACE
  • DEBUG
  • INFO
  • SUCCESS
  • WARNING
  • ERROR
  • CRITICAL

ログの出力レベルを調整はlogger.add時にlevelを指定する。

logger.add(
    sys.stdout,
    level='WARNING',
    format="{time:YYYY-MM-DDTHH:mm:ss} {level} {message}")

logger.info('ほげ')
logger.warning('ふが')
logger.error('ぴよ')

    #=> 2019-09-21T18:38:18 WARNING ふが
    #=> 2019-09-21T18:38:18 ERROR ぴよ

上記の例ではlevelにWARNINGが指定されているのでinfoの出力は省略されている。

フォーマットをdictionaryで指定

下記のようなdictを作って引数に渡すこともできる。この場合、デフォルトの指定を消す為にremoveをする必要はない。

config = {
    'handlers': [
        {'sink': sys.stdout, 'format': '<level>{time:YYYY-MM-DDTHH:mm:ss} {message}</level>'},
        {'sink': log.txt, 'format': '{time:YYYY-MM-DDTHH:mm:ss} {level} {message}'}
    ]
}
logger.configure(**config)

logger.info('ほげ')

カスタムログレベル

ログレベルは自作することもできる。

試しにdebugとinfoの間にenterというレベル(関数が呼び出された時に吐く想定)を作ってみる。

まずはログレベルの確認。

logger.level('INFO')
    #=> Level(no=20, color='<bold>', icon='ℹ️')

logger.level('DEBUG')
    #=> Level(no=10, color='<blue><bold>', icon='🐞')

deubgが10、infoが20らしい。startは18くらいにしておく。

# 新規ログレベルの設定
logger.level('ENTER', no=18, color='<bold>')
logger.enter = lambda message, *args, **kwargs: logger.log('ENTER', message, *args, **kwargs)

# ログ出力
logger.enter('えんたー')

    #=> 2019-09-21 19:38:28.381 | ENTER    | __main__:<lambda>:1 - えんたー

ログローテーション

logger.addする際にrotation指定ができる。

# 10MBごと
logger.add("log.txt", rotation="10 MB")

# 1日ごと
logger.add("log.txt", rotation="1 day")

retantionの指定で世代管理。

# 3日ごとにローテートして3世代分持つ
logger.add("log.txt", rotation="3 days", retantion=3)

試しにrotateを3分、retentionを3世代として様子を見る。

from loguru import logger

logger.add("log.txt", rotation="3 minutes", retention=3)

import time
for i in range(100):
    logger.info('ほげ-{}', i)
    time.sleep(60)

10分経過。3世代分のローテートファイルができている。

log.2019-09-21_19-54-28_018578.txt
log.2019-09-21_19-57-28_160720.txt
log.2019-09-21_20-00-28_278500.txt
log.txt

12分経過。19:54に作られたファイルが削除され、3世代分だけ保たている。

log.2019-09-21_19-57-28_160720.txt
log.2019-09-21_20-00-28_278500.txt
log.2019-09-21_20-03-28_371558.txt
log.txt

ファイル名を指定する場合は下記のようにテンプレートを用いて記述できる。

logger.add("log_{time:YYYY-MM-DDTHH:mm}.txt", rotation="3 minutes", retention=3)

出力されたファイル。

log_2019-09-21T20:20.txt
log_2019-09-21T20:23.txt
log_2019-09-21T20:26.txt
log_2019-09-21T20:29.txt

改定履歴

Author: Masato Watanabe, Date: 2019-09-21, 記事投稿