Pythonでtomlファイルを用いたlogging

## 概要
- エラーレベルに応じてloggerを使い分ける実装例
- loggerの設定はtomlファイルで実施
- Python3.11.0以降に追加されたtomlを読み込むライブラリを使用

| logger | 備考 |
| --- | --- |
| applicationlogger | application.logにINFO  以上を記録 |
| emergencylogger | emergency.logにERROR 以上を記録 |

## バージョン
- Python 3.11.0以降
- poetry

## ディレクトリ構成
```sh
.
├── pyproject.toml   # Poetryプロジェクトの設定ファイル
└── template
    ├── __init__.py
    └── example.py   # ログの使用例
```

## 実装

### Poetryプロジェクトの設定ファイル
```toml:pyproject.toml
[tool.poetry]
name = "template"
version = "1.0.2"
description = "ロガー使用例"
authors = ["Snorlax"]

[tool.poetry.dependencies]
python = "^3.11.0"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

# logの設定
[logging]
version = 1
[logging.formatters.simple]
format = "[%(levelname)s] %(name)s %(asctime)s - %(message)s "
[logging.handlers.consoleHandler]
class = "logging.StreamHandler"
level = "DEBUG"
formatter = "simple"
stream = "ext://sys.stdout"
[logging.handlers.applicationHandler]
class = "logging.handlers.TimedRotatingFileHandler"
when = "D"
level = "INFO"
formatter = "simple"
filename = "./target/application.log"
[logging.handlers.errorHandler]
class = "logging.handlers.TimedRotatingFileHandler"
when = "D"
level = "ERROR"
formatter = "simple"
filename = "./target/emergency.log"
[logging.loggers.console]
level = "DEBUG"
handlers = ["consoleHandler"]
propagate = "no"
[logging.loggers.application]
level = "DEBUG"
handlers = ["consoleHandler","applicationHandler"]
propagate = "no"
[logging.loggers.emergency]
level = "DEBUG"
handlers = ["consoleHandler","errorHandler"]
propagate = "no"
```

### 実装
```python:template/example.py
#!/usr/bin/env python3
# -*- coding: utf_8 -*-
"""ロガー使用例
"""

__author__ = "Snorlax"
__version__ = "1.0.2"
__date__ = "2022/01/28(Created: 2022/12/09)"

import tomllib
from enum import Enum
from logging import getLogger
from logging.config import dictConfig
from pathlib import Path


class LoggerName(Enum):
    """ロガー名"""

    CONSOLE = "console"
    APPLICATION = "application"
    EMERGENCY = "emergency"


def read_logger(filename):
    """ロガーの設定を読み込む

    Args:
        filename (str, optional): ログの設定ファイル（toml形式）
    """
    with open(filename, mode="rb") as file:
        dictConfig(tomllib.load(file).get("logging"))


def prepare_logger(output_directory="target", conf_file="pyproject.toml"):
    """ロガーの事前準備

    Args:
        output_directory (str, optional): ログの出力先ディレクトリ
        conf_file (str, optional): ログの設定ファイル（toml形式）. defualt: pyproject.toml
    """
    output_path = Path(output_directory)
    if not output_path.exists():
        output_path.mkdir()

    read_logger(conf_file)


if __name__ == "__main__":

    prepare_logger()

    logger = getLogger(LoggerName.CONSOLE.value)
    logger.debug("デバッグ")
    logger.info("情報")
    logger.warning("警告")
    logger.error("エラー")
    logger.critical("致命的")

    logger = getLogger(LoggerName.APPLICATION.value)
    logger.debug("デバッグ")
    logger.info("情報")
    logger.warning("警告")
    logger.error("エラー")
    logger.critical("致命的")

    logger = getLogger(LoggerName.EMERGENCY.value)
    logger.debug("デバッグ")
    logger.info("情報")
    logger.warning("警告")
    logger.error("エラー")
    logger.critical("致命的")

```

## 実行結果
### コンソール
```sh
$ poetry run python template/example.py
[DEBUG] console 2023-01-28 09:11:57,021 - デバッグ 
[INFO] console 2023-01-28 09:11:57,021 - 情報 
[WARNING] console 2023-01-28 09:11:57,021 - 警告 
[ERROR] console 2023-01-28 09:11:57,021 - エラー 
[CRITICAL] console 2023-01-28 09:11:57,021 - 致命的 
[DEBUG] application 2023-01-28 09:11:57,021 - デバッグ 
[INFO] application 2023-01-28 09:11:57,021 - 情報 
[WARNING] application 2023-01-28 09:11:57,021 - 警告 
[ERROR] application 2023-01-28 09:11:57,021 - エラー 
[CRITICAL] application 2023-01-28 09:11:57,021 - 致命的 
[DEBUG] emergency 2023-01-28 09:11:57,021 - デバッグ 
[INFO] emergency 2023-01-28 09:11:57,021 - 情報 
[WARNING] emergency 2023-01-28 09:11:57,021 - 警告 
[ERROR] emergency 2023-01-28 09:11:57,021 - エラー 
[CRITICAL] emergency 2023-01-28 09:11:57,021 - 致命的 
```

### 実行後ディレクトリ
```sh
.
├── pyproject.toml   # Poetryプロジェクトの設定ファイル
├── target                        # ログの出力ファイル
│   ├── application.log           # アプリケーションロガーの生成物
│   └── emergency.log             # エマージェンシーロガーの生成物
└── template
    ├── __init__.py
    └── example.py   # ログの使用例
```

### 生成物
```application.log 
[INFO] application 2023-01-28 09:11:57,021 - 情報 
[WARNING] application 2023-01-28 09:11:57,021 - 警告 
[ERROR] application 2023-01-28 09:11:57,021 - エラー 
[CRITICAL] application 2023-01-28 09:11:57,021 - 致命的 
```

```emergency.log
[ERROR] emergency 2023-01-28 09:11:57,021 - エラー 
[CRITICAL] emergency 2023-01-28 09:11:57,021 - 致命的 
```

## 参考
- [Logging HOWTO](https://docs.python.org/ja/3/howto/logging.html)