Pythonフレームワーク Flask のロギング機能 メモ

* Python フレームワークFlaskのロギング機能についてメモする。



## 標準ログ

* Python の`logging`モジュールを利用している。
* `Flask.logger`でアクセスする。



## 標準ログ出力

* `debug`、`error`のようにログレベルを指定して出力する。

```python
from flask import Flask, request, session
 
app = Flask(__name__)
app.logger.debug('DEBUG')
app.logger.info('INFO')
app.logger.warning('WARNING')
app.logger.error('ERROR')
app.logger.critical('CRITICAL')
```



## デフォルト設定

* `logger.basicConfig`でロガーのデフォルト設定を行う。
* 以下はデフォルトログ出力レベルをINFOに変更する例

```python
import logging
from flask import Flask

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)
```



## フォーマット指定

* アプリケーションのオブジェクトを作成する前に`dictConfig`を使用してプロジェクト全体のデフォルト設定として定義できる。

```python
from logging.config import dictConfig

dictConfig({
    'version': 1,
    'formatters': {'default': {
        'format': '[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
    }},
    'handlers': {'wsgi': {
        'class': 'logging.StreamHandler',
        'stream': 'ext://flask.logging.wsgi_errors_stream',
        'formatter': 'default'
    }},
    'root': {
        'level': 'INFO',
        'handlers': ['wsgi']
    }
})

app = Flask(__name__)
```



## ファイル出力

* `DEBUG.log`というログファイルに出力する例

```python
from flask import Flask, request, session
import logging
 
LOGFILE_NAME = "DEBUG.log"
 
app = Flask(__name__)

app.logger.setLevel(logging.DEBUG)
log_handler = logging.FileHandler(LOGFILE_NAME)
log_handler.setLevel(logging.DEBUG)
app.logger.addHandler(log_handler)
```



## リクエスト情報出力

* 接続元IPアドレスなどリクエスト情報を取得したい場合、`logging.Formatter`のサブクラスを定義し、ハンドラーに対してフォーマッターを変更する。

```python
from flask import has_request_context, request
from flask.logging import default_handler

class RequestFormatter(logging.Formatter):
    def format(self, record):
        if has_request_context():
            record.url = request.url
            record.remote_addr = request.remote_addr
        else:
            record.url = None
            record.remote_addr = None

        return super().format(record)

formatter = RequestFormatter(
    '[%(asctime)s] %(remote_addr)s requested %(url)s '
    '%(levelname)s in %(module)s: %(message)s'
)

default_handler.setFormatter(formatter)
```



## werkzeug Logger

* [werkzeug](https://github.com/pallets/werkzeug) : Flask内部で使用されるライブラリ。

  * ルーティング定義したアプリへのリクエストを受けて以下のようなログを出力しているもの。

    ```txt
    127.0.0.1 - - [30/Oct/2020 10:25:37] "GET / HTTP/1.1" 200 -
    ```

    

* フォーマッターを変更したい場合

  ```python
  import logging
  from flask import has_request_context, request
  from flask.logging import default_handler
  
  class RequestFormatter(logging.Formatter):
      def format(self, record):
          if has_request_context():
              record.url = request.url
              record.remote_addr = request.remote_addr
          else:
              record.url = None
              record.remote_addr = None
  
          return super().format(record)
  
  formatter = RequestFormatter(
      '[%(asctime)s] %(remote_addr)s requested %(url)s '
      '%(levelname)s in %(module)s: %(message)s'
  )
  
  default_handler.setFormatter(formatter)
  default_handler.setLevel(logging.INFO)
  
  werkzeug_logger = logging.getLogger('werkzeug')
  werkzeug_logger.addHandler(default_handler)
  ```

  

## 参考情報

* [ログ処理（Logging）](https://msiz07-flask-docs-ja.readthedocs.io/ja/latest/logging.html)
* [Flask(v1.0.2)のログ機能に関するメモ](https://www.subarunari.com/entry/flask-v1_0_2-logging)
* [flask のロギング機構について調べてみた](https://hawksnowlog.blogspot.com/2020/10/flask-logging-architecture.html)