目的
Pythonの軽量webフレームワークBottleはログをstderrに出力するが、これをloggingで扱いたい。
Bottle自体のログ
https://github.com/bottlepy/bottle/blob/release-0.12/bottle.py#L74
ここで設定されている_stderr
を改竄する。
import logging
import bottle
logger = logging.getLogger(__name__)
bottle._stderr = logger.info
改行は除いた方が見やすい。
bottle._stderr = lambda x: logger.info(x.replace('\n', ''))
しかしこれだけだと、アクセスログは依然stderrに出る。こちらはbottleの利用するバックエンド(デフォルトではwsgiref)のものなので、別の処置が必要になる。
INFO:__main__:Bottle v0.12.17 server starting up (using WSGIRefServer())...
INFO:__main__:Listening on http://127.0.0.1:8080/
INFO:__main__:Hit Ctrl-C to quit.
127.0.0.1 - - [15/Oct/2019 12:21:22] "GET / HTTP/1.1" 404 720
バックエンド(wsgiref)のログ
https://github.com/bottlepy/bottle/blob/release-0.12/bottle.py#L2773
ここから出力されているので、ServerAdapter.options['handler_class']
を設定する。
https://github.com/bottlepy/bottle/blob/release-0.12/bottle.py#L3113
ここでbottle.run
の残りのキーワード引数がoptions
に引き継がれるので、結局handler_class
をbottle.run
に渡せばよい。
import datetime
import logging
from wsgiref.simple_server import WSGIRequestHandler
import bottle
logger = logging.getLogger(__name__)
bottle._stderr = lambda x: logger.info(x.replace('\n', ''))
class WellLoggedHandler(WSGIRequestHandler):
def address_string(self): # Prevent reverse DNS lookups please.
return self.client_address[0]
def log_request(self, code='-', size='-'):
req = bottle.request
protocol = req.get('SERVER_PROTOCOL')
logger.info(f'{req.address_string()} - - [{datetime.datetime.now()}] "{req.method} {req.path} {protocol}" {code} {size}')
# logging.basicConfig(level=logging.DEBUG)
bottle.run(handler_class=WellLoggedHandler)
という感じになる。(例えばapacheのドキュメントを見るに- -
の部分はユーザーの認証情報などが入るらしい。)
https://github.com/python/cpython/blob/3.7/Lib/http/server.py#L546
log_error
やlog_message
というメソッドもあるので必要に応じて再定義するといいだろう。