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

## 概要
- エラーレベルに応じてloggerを使い分ける実装例
- loggerの設定はyamlファイルで実施

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

## 使用ライブラリ
- PyYAML

```sh
# 標準機能
$ pip install PyYAML
# poetryを使用している場合
$ poetry add PyYAML
```

## ディレクトリ構成
```sh
.
├── conf.yaml     # ログの設定ファイル
├── target        # ログの出力ファイル
├── example.py    # ログの使用例
└── logger.py     # ログの定義
```

## 実装

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

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


from enum import Enum
from logging import getLogger
from logging.config import dictConfig

from yaml import FullLoader, load


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

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


def read_logger(filename="conf.yaml"):
    """ロガーの設定を読み込む"""
    with open(filename) as file:
        dictConfig(load(file.read(), FullLoader))


if __name__ == "__main__":
    read_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
$ python example.py
[DEBUG] console 2022-12-12 15:26:26,502 - デバッグ 
[INFO] console 2022-12-12 15:26:26,502 - 情報 
[WARNING] console 2022-12-12 15:26:26,502 - 警告 
[ERROR] console 2022-12-12 15:26:26,502 - エラー 
[CRITICAL] console 2022-12-12 15:26:26,502 - 致命的 
[DEBUG] application 2022-12-12 15:26:26,502 - デバッグ 
[INFO] application 2022-12-12 15:26:26,502 - 情報 
[WARNING] application 2022-12-12 15:26:26,502 - 警告 
[ERROR] application 2022-12-12 15:26:26,502 - エラー 
[CRITICAL] application 2022-12-12 15:26:26,502 - 致命的 
[DEBUG] emergency 2022-12-12 15:26:26,502 - デバッグ 
[INFO] emergency 2022-12-12 15:26:26,502 - 情報 
[WARNING] emergency 2022-12-12 15:26:26,502 - 警告 
[ERROR] emergency 2022-12-12 15:26:26,502 - エラー 
[CRITICAL] emergency 2022-12-12 15:26:26,503 - 致命的 
```

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

### 生成物
```application.log 
[INFO] application 2022-12-12 15:26:26,502 - 情報 
[WARNING] application 2022-12-12 15:26:26,502 - 警告 
[ERROR] application 2022-12-12 15:26:26,502 - エラー 
[CRITICAL] application 2022-12-12 15:26:26,502 - 致命的 
```

```emergency.log
[ERROR] emergency 2022-12-12 15:26:26,502 - エラー 
[CRITICAL] emergency 2022-12-12 15:26:26,503 - 致命的 
```

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