Python logging 使い方

Pythonのloggingについてどこよりも簡潔に有用な解説をします。

> [Python - logging 公式ドキュメント](https://docs.python.org/ja/3/howto/logging.html)

###loggingメインプログラム

```python:appLogger.py
import os
import time
import threading
import logging
import logging.handlers

_logger = None

def initLogging(isPrinted: bool):
    """ロギングの初期設定
    （ログは指定したフォルダに保管される）

    Args:
        isPrinted (bool): コンソール画面に表示するときTrue
    """    """
    ロギング設定
    """    
    global _logger

    _logger = logging.getLogger('App')
    _logger.setLevel(logging.INFO)

    ''' ログファイル保存用のディレクトリ '''
    if os.path.exists('./log') == False:
        os.makedirs('./log')

    ''' ログをファイルに出力するための設定 '''
    rfh = logging.handlers.RotatingFileHandler(
        filename='./log/App.log',
        maxBytes=1024*1024,
        backupCount=5
    )

    _logger.addHandler(rfh)
    formatter = logging.Formatter('%(asctime)s,%(name)s,%(threadName)s,%(lineno)d,%(levelname)s,%(message)s')
    rfh.setFormatter(formatter)

    ''' ログをコンソールに出力するための設定 '''
    if isPrinted:
        handler = logging.StreamHandler()
        handler.setLevel(logging.INFO)
        _logger.addHandler(handler)
        handler.setFormatter(formatter)

    _logger.info('initLogging fin.')

def func1():
    """Thread 1 Mehotd
    """    
    while True:
        _logger.info("Thread1: Heartbeat...")
        time.sleep(1)

def func2():
    """Thread 2 Mehotd
    """    
    while True:
        _logger.info("Thread2: Heartbeat...")
        time.sleep(1)

if __name__ == '__main__':

    ''' ロギング設定の初期化 '''
    initLogging(True)

    ''' ロギング出力テスト '''
    _logger.info("INFO")
    _logger.warning("WARNING")
    _logger.error("ERROR")
    _logger.critical("CRITICAL")

    ''' 読み込み用スレッド '''
    thread1 = threading.Thread(target=func1)
    thread1.start()

    ''' 書き込み用スレッド '''
    thread2 = threading.Thread(target=func2)
    thread2.start()
```

簡単にプログラムの解説をします。

####RotatingFileHandler
ログファイルの出力と世代管理をします。上記の場合、logフォルダにApp.logというログファイルが生成されます。

 filename	出力ファイル名
 maxBytes	１ファイルの最大サイズ
 backupCount	世代管理数

maxBytesを超えると自動的に「App.log」 -> 「App.log1」 に変換され、以降のログは「App.log」に保存されます
上記の場合、世代管理は5なので、「App.log5」まで行くと古いものから削除されます。

出力形式は Formatter() で設定が可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586845/1bd93f4f-8949-bf8c-319e-ced032f545a0.png)

####StreamHandler
ここではコンソール画面への出力設定をします。出力内容は上記と同じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586845/80e33392-ff80-b6f4-7205-518b047d4af1.png)

---
###getChild()による子ロガー作成
loggingメインプログラムで作成したLogging設定を使って、子ロガーを作成します。

これはPythonプログラムが複数に渡るときに便利です。

以下サンプルプログラムになります。親プログラムは上記とほぼ同じです。

```python:LoggerParent.py
''' ---------------------------
    Python Logging Parent
---------------------------'''
import os
import logging
import logging.handlers

_logger = None

def initLogging(isPrinted: bool):
    """ロギングの初期設定
    （ログは指定したフォルダに保管される）

    Args:
        isPrinted (bool): コンソール画面に表示するときTrue
    """    """
    ロギング設定
    """    
    global _logger

    _logger = logging.getLogger('App')
    _logger.setLevel(logging.INFO)

    ''' ログファイル保存用のディレクトリ '''
    if os.path.exists('./log') == False:
        os.makedirs('./log')

    ''' ログをファイルに出力するための設定 '''
    rfh = logging.handlers.RotatingFileHandler(
        filename='./log/App.log',
        maxBytes=1024*1024,
        backupCount=1
    )

    _logger.addHandler(rfh)
    formatter = logging.Formatter('%(asctime)s,%(name)s,%(threadName)s,%(lineno)d,%(levelname)s,%(message)s')
    rfh.setFormatter(formatter)

    ''' ログをコンソールに出力するための設定 '''
    if isPrinted:
        handler = logging.StreamHandler()
        handler.setLevel(logging.INFO)
        _logger.addHandler(handler)
        handler.setFormatter(formatter)

    _logger.info('initLogging fin.')

if __name__ == '__main__':

    ''' ロギング設定の初期化 '''
    initLogging(True)

    ''' ロギング出力テスト '''
    _logger.info("INFO")
    _logger.warning("WARNING")
    _logger.error("ERROR")
    _logger.critical("CRITICAL")

    ''' Childアプリの起動 '''
    import LoggerChild
    LoggerChild.Start()
```

続いて、子ロガー側の紹介です。
実はたった1行で子ロガーは親ロガーの設定を引き継いで作成できます。

```python:LoggerChild.py
''' ---------------------------
    Python Logging Child
---------------------------'''
import logging

def Start():

    ''' 子ロガーの設定 '''
    _logger = logging.getLogger("App").getChild("Child")
    _logger.info("logging child fin.")
```

Parent側を実行したときの結果です。
出力結果は以下となります。子ロガーの方は、nameが「App.Child」になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/586845/426c5536-a4cb-5309-9779-cbeba53e82de.png)

以上でloggingの解説は終了します。
※実務で利用する場合は、適宜例外処理などは追加してください。