はじめに
だんないよ、nikkieです。
6/9の pyhack 成果発表をもとにブログにしました。
今回はMarkdownで書いているので、いつもと体裁が異なります。
勉強会の概要
(第89回)Python mini Hack-a-thon - connpass
スプリントのゆるい版みたいな感じで各自自分でやりたいことを持ってきて、勝手に開発を進めています。
取り組んだこと
#pyhack
— nikkie (@ftnext) 2018年6月9日
今日のやることは2つ。18時くらいに退出予定です。よろしくお願いします
- Flaskのログの出し方、例外処理を調べる(importしたファイルの中でログ出したり、例外上げたりしてみたい。今後仕事で使いそうなので)
- LINE BotのSDK調べる
成果
- Flaskのログ出力について疑問は解決できた
- LINE Botでオウム返しできた
Flaskのログ出力から書いていきます。
疑問
Flaskインスタンスをrunしているファイル(app.py
)では以下のようにしてdebug.log
にログ出力ができます。1
app.py
にimportしているファイル(logtest.py
)のログをdebug.log
に出力するにはどうすればいいのか調べてみました。
# app.py import logging from logging.handlers import RotatingFileHandler import os from flask import Flask from logtest import fabulous_message app = Flask(__name__) formatter = logging.Formatter( '%(asctime)s %(levelname)s: %(message)s ' '[in %(pathname)s:%(lineno)d]' ) debug_log = os.path.join(app.root_path, 'debug.log') debug_file_handler = RotatingFileHandler( debug_log, maxBytes=100000, backupCount=1 ) debug_file_handler.setLevel(logging.INFO) debug_file_handler.setFormatter(formatter) app.logger.setLevel(logging.INFO) app.logger.addHandler(debug_file_handler) @app.route('/') def hello(): app.logger.info('GET Access') message = fabulous_message() return message if __name__ == '__main__': app.run()
わかったこと
- ロガーの子孫構造を使う
- 子孫構造を使わない場合、ロガーを設定して使えばよさそう(ロギング設定ファイルも導入したい)
ロガーの子孫構造を使う2
# logtest.py import logging logger = logging.getLogger('__main__.'+__name__) def fabulous_message(): logger.info('fabulous message create start') return 'Hello, World!'
2018-06-09 15:30:34,008 INFO: GET Access [in app.py:25] 2018-06-09 15:30:34,009 INFO: fabulous message create start [in /Users/.../logtest.py:21]
ロガーの子孫構造について https://docs.python.jp/3/howto/logging.html#loggers
たとえば、名前が foo であるロガーがあったとして、 foo.bar, foo.bar.baz, foo.bam といった名前のロガーはすべて foo の子孫になります。
ロガーの子孫構造を使っているため、logtest.py
の中でロガーの設定は不要と理解しました。
app.logger
は標準モジュール logging のロガーを使っていると確認できました。3
python app.py
と実行したとき、app = Flask(__name__)
の__name__
は__main__
が入るため、
logtest.py
でlogger = logging.getLogger('__main__.'+__name__)
としたことで子孫構造が設定できました。4
logtest.py
でlogger = logging.getLogger(__name__)
としたところ
debug.log
にはログ出力されませんでした。(子孫構造が設定されていないためと考えています)
ロガーを設定して使う
以下のようにロガーを設定しても、importしたファイルからdebug.log
にログ出力できました。5
(これだと「他のファイルにも同じように書かないといけないじゃん!」と思い、同じようなコードを繰り返さない方法を探して、子孫構造に至りました)
# logtest.py import logging from logging.handlers import RotatingFileHandler logger = logging.getLogger(__name__) formatter = logging.Formatter( '%(asctime)s %(levelname)s: %(message)s ' '[in %(pathname)s:%(lineno)d]' ) debug_file_handler = RotatingFileHandler( 'debug.log', maxBytes=100000, backupCount=1 ) debug_file_handler.setLevel(logging.INFO) debug_file_handler.setFormatter(formatter) logger.setLevel(logging.INFO) logger.addHandler(debug_file_handler) def fabulous_message(): logger.info('fabulous message create start') return 'Hello, World!'
2018-06-09 15:58:07,321 INFO: GET Access [in app.py:25] 2018-06-09 15:58:07,323 INFO: fabulous message create start [in /Users/.../logtest.py:21]
ロギング設定ファイル
importするファイル全てに書くのは大変そうなので、ロギング設定ファイルを使ってみようと思います。(宿題事項)
https://docs.python.jp/3/howto/logging.html#configuring-logging
ロギング設定ファイルを作り、それを fileConfig() 関数を使って読み込む。
動作環境
- Python 3.6.5
- flask==0.12.4
LINE Bot でオウム返し
#pyhack
— nikkie (@ftnext) 2018年6月9日
LINEが公開しているSDKのコードを動かせばオウム返しBotは作れました。(2回返すようにもできた)https://t.co/aPVRQpPEqf
コーディングより、LINEでの環境構築に手間がかかる印象。2ヶ月前に参加した勉強会の資料が参考になりました!https://t.co/9Oar8xXuq0
感想
takanoryさんから「Logging HOWTO — Python 3.6.5 ドキュメント」を教えていただき、ロギングの理解を深めることができました。教えていただきありがとうございました!
次の1週間を乗り切る準備ができたかなと思います。(勤務先でソロでPython使い続けるために毎週末に翌週の準備をしています。例外は直近では使わなさそうだから、またの機会に調べよう)
今回ははじめて来られた方がいつもより多かったと思います。
先日の #PyNyumon から来られた方もいて、メンターにトライした身として嬉しかったです。
来月は合宿ということで、私も思い切って飛び込んでみようと思います。(申込みました!)
脚注
-
ロギングは次のコードを参考にしています。 http://study-flask.readthedocs.io/ja/latest/07.html#logging↩
-
StackOverflowの次の回答を参考にしています。 https://stackoverflow.com/a/39863901↩
-
python app.py
の実行ではない本番環境で子孫構造が想定どおり働くかは検証の必要があります。↩ -
RotatingFileHandlerに'debug.log'と直に渡しているのが気になるので、pathlibのPathを使うやり方に今後アップデートします。(ソフトウェアデザイン2018年2月号を参考にします)↩