Python での Log 収集

Python
スポンサーリンク

プロジェクトが大きくなるにつれて、プログラムの不備を見つけるのにログの構成、ログデザインを考えることが重要になってくる。上手なログの書き方を覚えれば、プリントデバッグがとても用意になるので、習慣づける価値はある。

システムトレードの取引をしていると、サーバーの遅延や分散処理による非同期処理が増えて全体としてのフローが複雑になって、取引残高がずれた時の原因究明が容易ではなくなっていく。その時に、ログを上手に使ってトラッキングできるようにしておくと、不具合が起こった時の対処が楽になる。

Logging Module

LogBook

  • mitsuhiko (Flaskの開発者) が開発にいた
  • スター数一位
  • 追加の情報や、logをサーバーに収集させる機能が標準で備わってる
    • 他の主要ライブラリで使われていない
    • logging との親和性は悪そう?

structlog

  • 変数の確認に使いやすくなっている。
  • ターミナルに色付けできる

logzero

  • 色をつける
  • FileRatation
  • unicode
  • logging との親和性高め

logzero を使うことにする

基本的には標準のloggingを用いて、拡張機能を利用したい時だけlogzeroを使うという形が取れるのがlogzeroのメリット。

logging を使う上でのお勧め機能

Formatter を定義

呼び出し元のファイルや行数までログに出力できる。

お勧め Format 設定

"%(color)s%(asctime)s-%(threadName)s|%(filename)s:%(lineno)d|%(levelname)-7s%(end_color)s : %(message)s"

同一テキストの書き出しを行っても、呼び出し元が違うことが分かるだけで十分なヒントになる。

colorというのは、 logzero.LogFormatter独自のもの。

必要に応じてここからパラメータを引っ張ると良い

stdout と stderr も出力させる

stderr で落ちたときの処理もpython側でloggingに流せるようにしたい。

ライブラリ化してみた。

logging の設定が終わったあとに下記を追加するだけ。

import stdlogging
stdlogging.enable()

これで、terminalでログの確認をしなくて良くなる。

Logging Config File

ファイルからLOGLEVELの設定を行えるようにする。

ログ用サーバー

  • Elasticsearch
  • LogStash

ネットワークを使ったログ収集で、これらを使うと統計情報の利用などの連携ソフトが使いやすくなるが、個人的にはそこまでの必要は今のところない。

LogViewer

SnakeTail

  • 一致するものに色をつけることができるなど大体の要望は満たす。
    • ただ、表示するものをフィルタリングで選べない(DEBUGは表示しないなど)

サンプルコード

pip install stdlogging logzero

必要モジュールをインストール。

import logging
import logzero
import time
import threading
import stdlogging
from logzero import logger

def test_log(logger):
    logger.error("log from thread")

if __name__ == '__main__':
    formatter = logzero.LogFormatter(
            fmt="%(color)s%(asctime)s-%(threadName)s|%(filename)s:%(lineno)d|%(levelname)-7s%(end_color)s : %(message)s",
            datefmt=None)
    logging.basicConfig(level=logging.DEBUG)
    root_logger = logging.getLogger()
    handler = root_logger.handlers[0]
    handler.setFormatter(formatter)
    logging.info("log")

    threading.current_thread().name = 'LogMain'
    logger = logzero.setup_logger(formatter=formatter)
    logger.debug("hello")
    logger.info("info")
    logger.warn("warn")
    logger.error("error")
    t = threading.Thread(target=test_log, args=(logger,), name="LogThread")
    t.start()
    t.join()

    stdlogging.enable()
    print "test comment"
    raise RuntimeError("Runtime Error")

コメント

タイトルとURLをコピーしました