python ロギング dictConfigの使い方　

pythonでLOGしたことなかったのでやってみた。
ログの設定内容は`settings/config.py`にまとめて、`main.py(root)`から`import`して使うかたちを取ることにした。

`info`は頻繁にログ出力することからログローテーションをつかう。これにより、ログサイズが指定サイズ(`maxByte`)を超えたら自動的に新しいログファイルが作成されることになる。`backupCount`回まで作成したら、後ろから上書き(厳密には違うが)されていくので１ファイルがデカくなりすぎることはない。



```python:settings/config.py
import os
"""
参考にした書き方
https://stackoverflow.com/questions/7507825/where-is-a-complete-example-of-logging-config-dictconfig

"""
import os
"""
参考にした書き方
https://stackoverflow.com/questions/7507825/where-is-a-complete-example-of-logging-config-dictconfig

"""
"""
ログ設計指針
https://qiita.com/nanasess/items/350e59b29cceb2f122b3

◆バッチ処理の例◆
INFO 処理開始時
INFO 途中経過
INFO 処理終了時
WARN イベント発生時
ERROR 例外発生時
INFO その他、必要に応じて

◆WEBアプリケーションの例◆
INFO リクエスト開始時 - 処理概要、実行クラス名、メソッド名
INFO 途中経過 - 実行条件、処理対象オブジェクトのキーとなる値等(customer_id, order_id 等)
INFO 処理終了時 - 実行結果(OK/NG 等)、リダイレクト先
WARN イベント発生時 - 画面に表示したエラーメッセージ等
ERROR 例外発生時 - 例外クラス、例外メッセージ
INFO その他、必要に応じて
"""

"""    ★ Python　ログレベルについて　★
DEBUG	10	問題探求に必要な詳細な情報を出力したい場合
INFO	20	想定内の処理が行われた場合
WARNING	30	想定外の処理やそれが起こりそうな場合
ERROR	40	重大な問題により、機能を実行出来ない場合
CRITICAL	50	プログラムが実行不可となるような重大なエラーが発生した場合
"""

# PATH
SETTINGS_DIR = __file__  # ここのパス
ROOT_DIR = '/'.join(SETTINGS_DIR.split('/')[:-2])   # rootは１つ上の階層
LOG_DIR = os.path.join(ROOT_DIR, 'logs')
MAIN_LOG_DIR = os.path.join(LOG_DIR, 'main')        # main.py用
NB_LOG_DIR = os.path.join(LOG_DIR, 'notebook')      # jupytenotebook用
# ディレクトリ作成
if not os.path.exists(LOG_DIR):
    os.mkdir(LOG_DIR)
if not os.path.exists(MAIN_LOG_DIR):
    os.mkdir(MAIN_LOG_DIR)
if not os.path.exists(NB_LOG_DIR):
    os.mkdir(NB_LOG_DIR)

LOGGING_CONFIG = {
    'version': 1,
    # loggersで''として指定してもOK
    # 'root': {
    #     'level': 'NOTSET',
    #     'handlers': ['debug_console_handler', 'info_rotating_file_handler', 'error_file_handler'],
    # },
    'loggers': {
        '': {  # root
            'level': 'NOTSET',
            'handlers': ['debug_console_handler', 'info_rotating_file_handler', 'error_file_handler'],
        },
        'notebook': {
            'level': 'NOTSET',
            'handlers': ['info_notebook', 'error_notebook'],
        },
    },
    'handlers': {
        'debug_console_handler': {
            'level': 'DEBUG',
            'formatter': 'info',
            'class': 'logging.StreamHandler',
            'stream': 'ext://sys.stdout',
        },
        # ログ・ファイルのサイズがmaxBytes以上になったらinfo1.2.3..nと
        # 新しいログファイルを作成(rotating)する
        # backupCount回まで作成したら、後ろから上書きされていく(厳密には違うが)
        'info_rotating_file_handler': {
            'level': 'INFO',
            'formatter': 'info',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(MAIN_LOG_DIR, 'info.log'),
            'mode': 'a',
            'maxBytes': 1048576,  # 1MBまで
            'backupCount': 10    # 10ローテ
        },
        'error_file_handler': {
            'level': 'ERROR',
            'formatter': 'error',
            'class': 'logging.FileHandler',
            'filename': os.path.join(MAIN_LOG_DIR, 'error.log'),
            'mode': 'a',
        },
        'info_notebook': {
            'level': 'INFO',
            'formatter': 'info',
            'class': 'logging.handlers.RotatingFileHandler',
            'filename': os.path.join(NB_LOG_DIR, 'info.log'),
            'mode': 'a',
            'maxBytes': 1048576,  # 1MBまで
            'backupCount': 10    # 10ローテ
        },
        'error_notebook': {
            'level': 'ERROR',
            'formatter': 'error',
            'class': 'logging.FileHandler',
            'filename': os.path.join(NB_LOG_DIR, 'error.log'),
            'mode': 'a',
        },
    },
    'formatters': {
        'info': {
            'format': '%(asctime)s-%(levelname)s-%(name)s::%(module)s|%(lineno)s:: %(message)s'
        },
        'error': {
            'format': '%(asctime)s-%(levelname)s-%(name)s-%(process)d::%(module)s|%(lineno)s:: %(message)s'
        },
    },

}
```
https://blog.hiros-dot.net/wp-content/uploads/2021/01/ScreenShot_55.jpg
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282788/06b62026-45d6-0f0d-dd26-0664fe56b539.png)


```python:main.py
from logging import getLogger,config
from settings.config import LOGGING_CONFIG 

config.dictConfig(LOGGING_CONFIG)
logger = getLogger()

for i in range(1000):
    if i % 2 ==0:
        logger.info(i)
    if i % 3 == 0:
        logger.error(i)
```
```terminal:出力
2022-01-10 12:09:55,249-INFO-root::899213607|14:: 0
2022-01-10 12:09:55,250-ERROR-root::899213607|16:: 0
2022-01-10 12:09:55,251-INFO-root::899213607|14:: 2
2022-01-10 12:09:55,252-ERROR-root::899213607|16:: 3
2022-01-10 12:09:55,253-INFO-root::899213607|14:: 4
2022-01-10 12:09:55,253-INFO-root::899213607|14:: 6
2022-01-10 12:09:55,254-ERROR-root::899213607|16:: 6
2022-01-10 12:09:55,256-INFO-root::899213607|14:: 8
2022-01-10 12:09:55,256-ERROR-root::899213607|16:: 9
2022-01-10 12:09:55,257-INFO-root::899213607|14:: 10
2022-01-10 12:09:55,258-INFO-root::899213607|14:: 12
2022-01-10 12:09:55,258-ERROR-root::899213607|16:: 12
2022-01-10 12:09:55,260-INFO-root::899213607|14:: 14
2022-01-10 12:09:55,260-ERROR-root::899213607|16:: 15
2022-01-10 12:09:55,262-INFO-root::899213607|14:: 16
2022-01-10 12:09:55,262-INFO-root::899213607|14:: 18
2022-01-10 12:09:55,263-ERROR-root::899213607|16:: 18
2022-01-10 12:09:55,264-INFO-root::899213607|14:: 20
2022-01-10 12:09:55,265-ERROR-root::899213607|16:: 21
2022-01-10 12:09:55,266-INFO-root::899213607|14:: 22
2022-01-10 12:09:55,267-INFO-root::899213607|14:: 24
2022-01-10 12:09:55,268-ERROR-root::899213607|16:: 24
2022-01-10 12:09:55,269-INFO-root::899213607|14:: 26
2022-01-10 12:09:55,270-ERROR-root::899213607|16:: 27
2022-01-10 12:09:55,271-INFO-root::899213607|14:: 28
2022-01-10 12:09:55,272-INFO-root::899213607|14:: 30
2022-01-10 12:09:55,272-ERROR-root::899213607|16:: 30
2022-01-10 12:09:55,274-INFO-root::899213607|14:: 32
2022-01-10 12:09:55,275-ERROR-root::899213607|16:: 33
2022-01-10 12:09:55,275-INFO-root::899213607|14:: 34
2022-01-10 12:09:55,277-INFO-root::899213607|14:: 36
2022-01-10 12:09:55,278-ERROR-root::899213607|16:: 36
2022-01-10 12:09:55,279-INFO-root::899213607|14:: 38
2022-01-10 12:09:55,280-ERROR-root::899213607|16:: 39
2022-01-10 12:09:55,281-INFO-root::899213607|14:: 40
2022-01-10 12:09:55,281-INFO-root::899213607|14:: 42
2022-01-10 12:09:55,282-ERROR-root::899213607|16:: 42
2022-01-10 12:09:55,284-INFO-root::899213607|14:: 44
2022-01-10 12:09:55,285-ERROR-root::899213607|16:: 45
2022-01-10 12:09:55,286-INFO-root::899213607|14:: 46
2022-01-10 12:09:55,287-INFO-root::899213607|14:: 48
2022-01-10 12:09:55,288-ERROR-root::899213607|16:: 48
2022-01-10 12:09:55,288-INFO-root::899213607|14:: 50
2022-01-10 12:09:56,121-INFO-root::899213607|14:: 994
2022-01-10 12:09:56,122-INFO-root::899213607|14:: 996
2022-01-10 12:09:56,124-ERROR-root::899213607|16:: 996
2022-01-10 12:09:56,125-INFO-root::899213607|14:: 998
2022-01-10 12:09:56,126-ERROR-root::899213607|16:: 999
```