70
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

pythonのlogをコンソールとファイル両方に出力する

Last updated at Posted at 2021-01-09

はじめに

ファイルにログを残すためにlogger.~を使い、コンソールにログを出すためにprint()を使う。
面倒臭いと思ったことはないでしょうか。

会社でツールを作る際にコンソールとファイル両方にログを出力したいと思い、loggingモジュールを調べていたらコンソールにログを出力するStreamHandlerとファイルに出力するFileHandlerの両方使用すれば、コンソール出力とファイル出力の両方が簡単にできることがわかったので、その時の備忘録を残します。

参考文献

環境

  • python 3.8.5

ロガーのセットアップ

logging.basicConfig()でファイルやコンソールのどちらかに出力すれば良い場合はfilename=stream=を指定すれば良いですが、ファイルとコンソール両方に出力したい場合などのハンドラを複数使用するときは指定せずにhandlers=にハンドラをリストで与えて初期化します。
ファイルハンドラは保存パスに存在しないフォルダを指定するとエラーになってしまうので、ない場合は作成する処理を入れます。

import os
import sys
from datetime import datetime
import logging
from logging import StreamHandler, FileHandler, Formatter
from logging import INFO, DEBUG, NOTSET

# ストリームハンドラの設定
stream_handler = StreamHandler()
stream_handler.setLevel(INFO)
stream_handler.setFormatter(Formatter("%(message)s"))

# 保存先の有無チェック
if not os.path.isdir('./Log'):
    os.makedirs('./Log', exist_ok=True)

# ファイルハンドラの設定
file_handler = FileHandler(
    f"./Log/log{datetime.now():%Y%m%d%H%M%S}.log"
)
file_handler.setLevel(DEBUG)
file_handler.setFormatter(
    Formatter("%(asctime)s@ %(name)s [%(levelname)s] %(funcName)s: %(message)s")
)

# ルートロガーの設定
logging.basicConfig(level=NOTSET, handlers=[stream_handler, file_handler])

これでloggingモジュールをコンソールとファイル両方に出力する設定ができました。
注意するのはlogging.basicConfig()で設定する出力レベルです。ログはルートロガー→ハンドラの順に渡されます。なので、ルートロガーの設定であるlogging.basicConfig()で出力レベルをINFO等にしてしまうと、ルートロガーの時点で出力レベルがDEBUGのログは弾かれてしまいます。そのため、ファイルハンドラの設定で出力レベルをDEBUGにしても出力レベルがDEBUGのログがファイルに保存されません。

ここではプログラムをベタで書いていますが、なにか適当に関数に入れておくと良いと思います。ほかでこれらのオブジェクトは使用する場所がないので。

ロガーを使用する

ロガーを使用する場合は、logging.getLogger(__name__)でロガーオブジェクトを取得して使用します。
また、関数やファイルをまたぐ場合でも、一度ルートロガーの設定をしてしまえば、どこでも使えるので、使用したい場所でlogging.getLogger(__name__)を呼び出してあげれば使用できます。

logger = logging.getLogger(__name__)

logger.debug("debug")
logger.info("info")
logger.warn("warn")
logger.error("error")
logger.critical("critical")

ファイルには全部のログが、コンソールにはinfoからのログが出力されていると思います。

コンソール出力をリッチにする

ついでにrichを使用して、コンソール出力をリッチにします。方法は簡単でlogging.StreamHandlerrich.logging.RichHandlerに変えてあげるだけです。

richをインストールします。

$ pip install rich

インストールしたら、ロガーのセットアップの章のStreamHandlerRichHandlerに書き換えます。

from rich.logging import RichHandler

# ストリームハンドラの設定
rich_handler: RichHandler = RichHandler(rich_tracebacks=True)
rich_handler.setLevel(INFO)
rich_handler.setFormatter(Formatter("%(message)s"))

# ファイルハンドラの設定
# 省略

# ルートロガーの設定
logging.basicConfig(level=NOTSET, handlers=[rich_handler, file_handler])

出力がリッチになりましたね。

70
51
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
70
51

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?