概要
エラーの発生件数を計測するため、ログレベル別にログ出力を計測する処理をPythonで実装しました。
環境
この記事では、Python 3.9.1 で以下のパッケージを使って動作確認をしました。
tornado==6.1
prometheus_client==0.8.0
実装
ログを出力するときに意識しなくてもいいように、フィルタオブジェクトでカウントする処理を行います。フィルタではカウント処理だけを行うので、常にTrue
を返します。
動作確認用にWebアプリケーションにしています。
import logging
import random
import tornado.ioloop
import tornado.web
from prometheus_client.metrics import Counter
from prometheus_client.registry import REGISTRY
from prometheus_client.exposition import choose_encoder
class LogLevelCountFilter(logging.Filter):
counter = Counter(
name='log_events',
documentation='Number of error level events that made it to the logs',
labelnames=('level',))
def filter(self, record: logging.LogRecord) -> bool:
LogLevelCountFilter.counter.labels(
level=record.levelname
).inc()
return True
class MetricsHandler(tornado.web.RequestHandler):
def get(self):
encoder, content_type = choose_encoder(
self.request.headers.get('Accept'))
self.set_header('Content-Type', content_type)
self.write(encoder(REGISTRY))
class TestHandler(tornado.web.RequestHandler):
def get(self) -> None:
# ランダムにステータスコードを返す
self.set_status(random.choice([200, 400, 500]))
def on_finish(self) -> None:
message = (f'{self.request.method} {self.request.uri} '
f'{self.get_status()}')
if self.get_status() == 200:
logging.info(message)
elif self.get_status() == 400:
logging.warning(message)
elif self.get_status() == 500:
logging.error(message)
def main():
logging.basicConfig()
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# フィルタを設定
logger.addFilter(LogLevelCountFilter())
app = tornado.web.Application([
(r'/test', TestHandler),
(r'/metrics', MetricsHandler),
])
app.listen(8080)
tornado.ioloop.IOLoop.current().start()
if __name__ == '__main__':
main()
動作確認
# 適当にリクエストして、レスポンスステータスの数をカウントする
$ for i in $(seq 100);
do
curl -o /dev/null -w '%{http_code}\n' -s http://localhost:8080/test
done | sort | uniq -c
30 200
35 400
35 500
# メトリクスを確認
$ curl http://localhost:8080/metrics
...
# HELP log_events_total Number of error level events that made it to the logs
# TYPE log_events_total counter
log_events_total{level="WARNING"} 35.0
log_events_total{level="ERROR"} 35.0
log_events_total{level="INFO"} 30.0
# HELP log_events_created Number of error level events that made it to the logs
# TYPE log_events_created gauge
log_events_created{level="WARNING"} 1.617544123928205e+09
log_events_created{level="ERROR"} 1.6175441239456499e+09
log_events_created{level="INFO"} 1.617544123958624e+09