【Python】loggre ログ出力を、JSON形式で設定する
はじめに
ログ出力するHandler を複数設定する方法をまとめていきます。
やりたいことは、「コンソール出力・ファイル出力」を同時にログ出力することです !!
経緯
実運用するときは、ログ出力のパターンを複数設定する必要性があります。
異常検知で調査する時、意図した実行処理ができているか監視する時などです。
- コンソール出力: StreamHandler
- ファイル出力: FileHandler
他にも、SysLogHandler
, SocketHandler
, TimedRotatingFileHandler
などがあるようです。
手順
公式ドキュメントを参考に、StreamHandler
, FileHandler
の handler を設定できるように調整します。
コードに直接記述する方法もありますが、今回は、設定ファイルで作成しています。
メリットとしては、呼び出し側のファイル名を変えるだけで、任意の設定ファイルを使えることですかね。
- 設定ファイルをログ出力したい設定に記述する
- 呼び出し側で、logger 名を指定
- ログが、意図した結果で出力できるか検証
詳細
{
"version": 1,
"formatters": { ... 1
"detailed": {
"class": "logging.Formatter",
"format": "%(asctime)s %(name)-15s %(levelname)-13s %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S"
}
},
"handlers": {
"console": { ... 2
"class": "logging.StreamHandler",
"level": "INFO",
"formatter": "detailed"
},
"file": {
"class": "logging.FileHandler",
"filename": "log/mplog.log",
"mode": "a",
"formatter": "detailed"
},
"testfile": {
"class": "logging.FileHandler",
"filename": "log/testfile.log",
"level": "ERROR",
"mode": "a",
"formatter": "detailed"
},
"errors": { ... 3
"class": "logging.FileHandler",
"filename": "log/mplog-errors.log",
"mode": "a",
"level": "ERROR",
"formatter": "detailed"
}
},
"loggers": { ... 4
"testfile": {
"handlers": ["testfile"]
}
},
"root": { ... 5
"level": "DEBUG",
"handlers": ["console", "file", "errors"]
}
}
1. formatters : 出力するフォーマットを設定
-
detailed: 好きな名前をつけてformatter 名をつけれます
-
class: Formatter インスタンスを指定
-
format: ログ出力するフォーマットパターン
-
datefmt:
%(asctime)s
の表示を調整"formatters": { "detailed": { "class": "logging.Formatter", "format": "%(asctime)s %(name)-15s %(levelname)-13s %(message)s", "datefmt": "%Y-%m-%d %H:%M:%S" }
2. handlers: 出力する項目を設定( StreamHandler )
-
console: 好きな handler 名
-
level: 出力レベルを設定
-
formatter: formatters で指定したい フォーマット名
"handlers": { "console": { "class": "logging.StreamHandler", "level": "INFO", "formatter": "detailed" },
3. handlers: 出力する項目を設定 ( FileHandler )
-
errors: 好きな handler 名
-
filename: <ディレクトリパス>/< ファイル出力名>
-
mode: 書き込むモード w: 新規書込み、a: 追記 など
"errors": { "class": "logging.FileHandler", "filename": "log/mplog-errors.log", "mode": "a", "level": "ERROR", "formatter": "detailed" }
4. loggers: logger 名に指定
logger 名を 指定すると、出力反映されます。以下の設定だと testfile
の handler が選択されます。
-
testfile: 好きな名前をつける
-
handlers: handlers でつけた名前の設定を指定
"loggers": { "testfile": { "handlers": ["testfile"] }
呼び出し側の logging で指定することで、
"testfile"
が採用されます👇こんな感じ
import logging logger = logging.getLogger("testfile")
5. root: 設定
-
handlers に ログ出力したい対象名を、リスト格納することで、常にログ出力に反映されます
"root": { "level": "DEBUG", "handlers": ["console", "file", "errors"] }
ログ生成・出力
main() で呼び出し処理を書いています。細かい説明は割愛します。
import configparser
import os
import json
import logging
import logging.config
# 実行ファイル名を取得
_EXEC_FILE_NAME = os.path.basename(__file__)[:-3]
def read_conf_file(conf_file='conf/conf.json'):
""" 設定ファイルの読み込む """
with open(conf_file, 'r', encoding='utf-8') as f:
f_ = json.load(f)
logging.config.dictConfig(f_)
def get_logger(logger_='simpleDefault'):
""" ロガー生成 """
return logging.getLogger(logger_)
def set_conf(conf_file='conf/msg_format.ini'):
""" Read the format file you set. """
conf = configparser.ConfigParser()
conf.read(conf_file)
return conf
def get_conf(conf, sec: str, option: str, format1=None, format2=None):
""" Get the section name and key. """
conf = conf.get(section=sec, option=option)
return conf.format(format1, format2)
def main():
""" 実行ファイル """
# formater ファイル呼び出し
read_conf_file(conf_file='conf/conf.json')
# logger 名を設定
logger = get_logger(logger_=_EXEC_FILE_NAME)
# メッセージ一覧設定ファイルの読み込み
set_conf_ = set_conf(conf_file='conf/msg_format.ini')
# ------------------------
# ログ出力
# ------------------------
# Debug
msg1 = get_conf(conf=set_conf_, sec='message', option='DAP0001', format1=[1, 2, 3], format2=[1, 2, 3])
logger.debug(msg1)
# Info
msg2 = get_conf(conf=set_conf_, sec='message', option='IAP0001', format1=[1, 2, 3], format2=[1, 2, 3])
logger.info(msg2)
# Warning
msg3 = get_conf(conf=set_conf_, sec='message', option='WAP0001', format1=[1, 2, 3], format2=[1, 2, 3])
logger.warning(msg3)
# Error
msg4 = get_conf(conf=set_conf_, sec='message', option='EAP0001', format1=[1, 2, 3], format2=[1, 2, 3])
logger.error(msg4)
# Critical
msg5 = get_conf(conf=set_conf_, sec='message', option='CAP0001', format1=[1, 2, 3], format2=[1, 2, 3])
logger.critical(msg5)
if __name__ == '__main__':
main()
- ログ出力. メッセージ一覧の設定ファイル
[message]
DAP0001=Debug Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]} err_id: {1[0]}
DAP0002=Debug Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]}
DAP0003=Debug Message user_id: {0[0]} tr_id: {0[1]}
IAP0001=Info Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]} err_id: {1[0]}
IAP0002=Info Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]}
IAP0003=Info Message user_id: {0[0]} tr_id: {0[1]}
WAP0001=Warning Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]} err_id: {1[0]}
WAP0002=Warning Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]}
WAP0003=Warning Message user_id: {0[0]} tr_id: {0[1]}
EAP0001=Error Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]} err_id: {1[0]}
EAP0002=Error Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]}
EAP0003=Error Message user_id: {0[0]} tr_id: {0[1]}
CAP0001=Critical Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]} err_id: {1[0]}
CAP0002=Critical Message user_id: {0[0]} tr_id: {0[1]} param_id: {0[2]}
CAP0003=Critical Message user_id: {0[0]} tr_id: {0[1]}
実行結果
やりたい事ができているようです!
console: INFO レベル以上をコンソール出力
2021-12-11 20:12:40 format INFO Info Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format WARNING Warning Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format ERROR Error Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format CRITICAL Critical Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
mplog.log: DEBUG レベル以上をファイル出力
2021-12-11 20:12:40 format DEBUG Debug Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format INFO Info Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format WARNING Warning Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format ERROR Error Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format CRITICAL Critical Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
mplog-error.log: ERROR 以上をファイル出力
2021-12-11 20:12:40 format ERROR Error Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
2021-12-11 20:12:40 format CRITICAL Critical Message user_id: 1 tr_id: 2 param_id: 3 err_id: 1
まとめ
今回でログ出力設定に関しては理解できたかなっと思います。
後は、以下を進めていくと良さそうです!!
- クラス化して使いやすく改変
- 運用しやすいように的確な箇所に、ログ出力を設定
以上になります。ありがとうございました!
Discussion