記事の対象者
- printでlogを出している
- pythonの標準モジュールloggingを使ってみたい
printでのlog出力
例えばログに以下の内容を含めたいとします
- logレベル(debug, info, warn, error, critical)
- 時間
- モジュール名
- 関数名
- 任意のメッセージ
printを使った場合、以下のような関数実装になるかなと思います
from datetime import datetime as dt
def print_log(log_level: str, module_name: str, func_name: str, message: Optional[str] = None):
"""printでlogを出す関数
Args:
log_level (str): logレベル
module_name (str): モジュール名
func_name (str): 関数名
message (Optional[str]): logに出力したいメッセージ
"""
if message is not None:
print("{time} {level} {name} {func} {meg}".format(time=dt.now().strftime('%Y/%m/%d %H:%M:%S'), level=log_level, name=module_name, func=func_name, meg=message))
return
print("{time} {level} {name} {func}".format(time=dt.now().strftime('%Y/%m/%d %H:%M:%S'), level=log_level, name=module_name, func=func_name))
↑の関数を使う場合
import print_log
def print_log_run():
print_log('info', __name__, print_log_run.__name__, 'test')
if __name__ == '__main__':
print_log_run()
# 結果
2024/06/29 10:43:52 info __main__ print_log_run test
出せてはいますが引数多いし、なんか汚いですよね。
messageを工夫したい時もさらに関数が複雑になりそうな予感が現段階でします。
さらにlogfileを出力したいと言われたら、更に複雑な関数になりそうです。
loggingでのlog出力
この問題を簡単に解決できるのがpythonの標準モジュールである「logging 」です。
使い方は更新サイトのものを載せます
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)
logger.debug('This message should go to the log file')
logger.info('So should this')
logger.warning('And this, too')
logger.error('And non-ASCII stuff, too, like Øresund and Malmö')
# 以下のような出力となる
DEBUG:__main__:This message should go to the log file
INFO:__main__:So should this
WARNING:__main__:And this, too
ERROR:__main__:And non-ASCII stuff, too, like Øresund and Malmö
loggingの使い方は更新サイトや分かりやすく記事があるので紹介します
オレオレlogging関数
loggingをいい感じに使える関数を作ったので載せます。
↓オレオレlogging関数
import logging
def get_logger(name: str, log_level: str, log_export_path: str):
"""ロガーの取得
Args:
name (str): モジュール名
log_level (str): ログレベル
log_export_path (str): ログの出力先(名前も含む)
Returns:
_type_: loggingクラス
"""
if(log_level == 'debug'):
level = logging.DEBUG
else:
level = logging.INFO
logging.basicConfig(level=level)
logger = logging.getLogger(name=name)
handler = logging.FileHandler(log_export_path)
handler.setLevel(level=level)
format = '%(asctime)s %(levelname)s [%(name)s] %(funcName)s %(message)s'
formatter = logging.Formatter(format)
handler.setFormatter(formatter)
logger.addHandler(handler)
return logger
関数の他にもget_message関数やmessageListを定義しておくとlog messageも簡単に設定することができます
message_list = {
'TEST_01': 'Start Process {0}',
'TEST_02': 'End Process',
'TEST_03': 'Fail {}'
}
def get_message(log_id: str, *args: str):
"""configのログのmessageリストからメッセージを取得する
Args:
log_id (str): log_id -> message.pyを参照
*args (str): logに出す可変長変数
Returns:
_type_: str
"""
log_message = message_list[log_id]
if(len(args) == 0):
return log_message
return log_message.format(*args)
↑を使用する場合
import get_logger, get_message
def logger_run():
logger = get_logger(name=__name__, log_level='info', log_export_path='./log/test_log.log')
logger.info(msg=get_message('TEST_01', 'test'))
logger.info(msg=get_message('TEST_02'))
if __name__ == '__main__':
logger_run()
log/test_log.logには以下のような形式で出力されている
2024-06-29 10:09:10,736 INFO run [__main__] Start Process test
2024-06-29 10:09:10,736 INFO run [__main__] End Process