Pythonにはログ出力のライブラリとして logging が用意されています。
この logging は様々なフォーマットや出力先に対応しているため、それなりの設定が必要となります。
詳しいことはこちらの記事に記載していますので、興味のある方はご一読頂くとして、この記事では logging を簡単に使えるようにするためのクラスについて紹介したいと思います。
コピペで簡単に使えますので、サクっとログ出力機能を自作プログラムに追加したい場合は、是非ご利用下さい。
使い方
今回作成したクラスには LogMan という名前を付けました。
使い方は、次の通り LogMan() でインスタンスを生成し、後は必要なログレベルのメソッドを呼ぶだけです。
LogMan() には、次の引数を指定できます。
LogMan(filename=ログファイル名,level=出力レベル,stdout=True/False)
引数から分かる通り、ログの出力先はファイルで、stdout をTrueにすることで、同じ内容を標準出力にも出力するようになっています。
以下がサンプルになります。
#インスタンスの生成
mg = LogMan()
#ログ出力
mg.debug("デバッグです")
mg.info("情報です")
mg.warning("警告です")
mg.error("エラーです")
mg.exception("例外です")
mg.critical("クリティカルです")
結果は次の通りです。

例外発生時に critical メソッドを呼ぶと、NoneType:None の部分に詳細メッセージが記録されます。
出力レベルを設定する場合は、 LogMan(level=出力レベル) か、もしくは setLevel(出力レベル) を用います。
#インスタンスの生成
mg = LogMan()
#ログ出力レベルの設定
mg.setLevel(logging.INFO)
#ログ出力
mg.debug("デバッグです")
mg.info("情報です")
mg.warning("警告です")
mg.error("エラーです")
mg.exception("例外です")
mg.critical("クリティカルです")
出力結果は次の通りです。
出力レベルに logging.INFO を設定したので、デバッグのメッセージが表示されなくなりましたね。

尚、LogMan() で filename 引数を省略した場合、下図のフォルダにログを出力します。
また、ログファイル名は __file__ から取得しているので、プログラム毎にログファイルが出来上がります。
もし全てのプログラムのログを1つのファイルに出力したい場合は、 filename を必ず指定してください。

リファレンス
LogManクラスには以下のメソッドが用意されています。
| メソッド名 | 内容 | 引数 |
|---|---|---|
| __init__() | コンストラクタ | filename:str ログファイルのフルパス format:str ログの出力フォーマット level:int ログの出力レベル stdout:bool ログを標準出力に出力するか否かの設定 True:出力する False:出力しない |
| set_handler() | ハンドラの登録 | filename:str ログファイルのフルパス format:str ログの出力フォーマット tdout:bool ログを標準出力に表示するか否かの設定 |
| setLevel() | 出力レベルの設定 | leven:int エラーレベルの指定 (DEBUG=10、INFO=20、 WARINNG=30、 ERROR=40、 CRITICAL=50) |
| info() | インフォメーションの出力 | message:str ログに出力するメッセージ |
| error() | エラーの出力 | message:str ログに出力するメッセージ |
| exception | エラーの出力 (例外時の詳細メッセージ付き) | message:str ログに出力するメッセージ |
| warning | 警告の出力 | message:str ログに出力するメッセージ |
| debug | デバッグ情報の出力 | message:str ログに出力するメッセージ |
クラスのソースコード
下記がLogManのソースコードです。
このままコピペしてお使いいただけます。
あとは、ご自身の用途に合わせてカスタマイズして下さい。
import logging
from posixpath import dirname
import sys
import os
class LogMan() :
'''
ログ管理クラス
'''
def __init__(self,filename = '',format = '',level=10,stdout = False):
'''
コンストラクタ
Parameters
----------
filename:str
ログファイルのフルパス
format:str
ログの出力フォーマット
level:int
ログの出力レベル
DEBUG=10 INFO=20 WARINNG=30 ERROR=40 CRITICAL=50
stdout:bool
ログを標準出力に表示するか否かの設定
'''
#ログファイル名が指定されていなければ、生成する
self.filename = self.__create_log_path() if filename == '' else filename
#フォーマットが指定されていなければ、初期値を設定する。
self.format = '[%(asctime)s] %(name)s (%(levelname)s) %(message)s' if format == '' else format
#ロガーを生成
self.logger = logging.getLogger(os.path.basename(__file__))
#エラーレベルを設定
self.logger.setLevel(level)
#ハンドラを登録
self.set_handler(self.filename,self.format,stdout)
def set_handler(self,filename,format,stdout = False):
'''
ハンドラの登録
Parameters
----------
filename:str
ログファイルのフルパス
format:str
ログの出力フォーマット
stdout:bool
ログを標準出力に表示するか否かの設定
'''
fmt = logging.Formatter(format) #フォーマッタの作成
fh = logging.FileHandler(filename) #ファイルハンドラの生成
fh.setFormatter(fmt) #ファイルハンドラにフォーマッタを登録
self.logger.addHandler(fh) #ロガーにファイルハンドラを登録
#標準出力の出力指示がされていたら、標準出力用のハンドラとフォーマッタを登録
if stdout:
sd = self.logger.StreamHandler(sys.stdout)
sd.setFormatter(fmt)
self.logger.addHandler(sd)
def setLevel(self,level):
'''
ログに出力するエラーレベルを設定する
'''
self.logger.setLevel(level)
def info(self,message):
'''
ログに情報メッセージを出力する
'''
self.logger.info(message)
def error(self,message):
'''
ログにエラーメッセージを出力する
'''
self.logger.error(message)
def exception(self,message):
'''
ログに例外処理のメッセージを付加して出力する
'''
self.logger.exception(message)
def warning(self,message):
'''
ログに警告メッセージを出力する
'''
self.logger.warning(message)
def debug(self,message):
'''
ログにデバッグメッセージを出力する
'''
self.logger.debug(message)
def critical(self,message):
'''
ログにクリティカルメッセージを出力する
'''
self.logger.critical(message)
def __create_log_path(self):
'''
__file__ の内容を使って、ログファイルのパスの初期値を生成する
'''
folder = os.path.join(self.__get_parent(__file__),'logs')
name_without_ext = self.__get_name_without_ext(__file__)
return os.path.join(folder,name_without_ext+'.log')
def __get_parent(self,path):
'''
指定したパスの1つ上のフォルダ(親フォルダ)を返す
'''
return '/'.join(os.path.dirname(path).replace('\\','/').split('/')[0:-1])
def __get_name_without_ext(self,filename):
'''
拡張子を除いたファイル名を返す
'''
return os.path.splitext(os.path.basename(filename))[0]
filename 省略時にログが出力されるフォルダを変更したい場合は、以下の部分を書き換えて下さい。
def __create_log_path(self):
'''
__file__ の内容を使って、ログファイルのパスの初期値を生成する
'''
folder = os.path.join(self.__get_parent(__file__),'logs')
name_without_ext = self.__get_name_without_ext(__file__)
return os.path.join(folder,name_without_ext+'.log')
__get_parent () でプログラムが置かれているフォルダの1つ上を取得していますが、プログラムと同じフォルダに出力したい場合は、 folder = os.path.dirname( __file__ ) と書き換えればOKです。
まとめ
今回は logging を簡単に使えるようになるクラスを紹介しました。
一般的には、ログの出力先はファイルであり、たまに標準出力に同じものを出力するケースが多いので、そういう用途に限定することでクラスの仕様を単純化し、使いやすくしています。
ログの出力フォルダは状況によって変わると思いますので、その部分は適宜修正をお願いします。
今回の記事が、皆様の何らかのヒントになれば光栄です。

コメント