概要
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('ほげ')
実行結果。レベルに応じて色分けされたログが出力される。
ファイル出力
ファイル名を指定してログを出力する。下記の指定では 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, 記事投稿