執筆者:SRE シラト
今回のお話
海外向けコミック配信サービス「Coolmic」では、Prometheus を使用してシステム監視を行っております。
Prometheus のメトリクスを確認すると、Railsで例外発生時にメトリクスが取得できていないことが判明いたしました。
今回は、その解決方法をご紹介いたします。
状況整理
今回取得したかったメトリクスはhttp_server_requests_total
です。
Kibanaのログと照らし合わせると、数値が合わなかったので気が付きました。。。
原因
Rails は標準で ActionDispatch::ShowExceptions の仕組みで例外を捕捉して、エラーページを表示しております。
ソースコードを確認すると、処理の途中で以下の値を上書きしている箇所を発見。
request.path_info = "/#{status}" request.request_method = "GET"
実はこの2つの値、prometheus-client で参照している値だったため、期待する値ではなかったです。
path | method | |
---|---|---|
参照 | path_info | request_method |
実際の値 | /422 | get |
期待する値 | /user/sessions | post |
解決策
ShowExceptions を無効化することもできるみたいですが、レスポンスにデバッグコードが含まれてしまうため却下しました。
ShowExceptions が値を上書きする前の情報も取得することができましたので、モンキーパッチで処理を上書きしました。
module Prometheus module Middleware class Collector def record(env, code, duration) method = if env["action_dispatch.original_request_method"].present? env["action_dispatch.original_request_method"].downcase else env["REQUEST_METHOD"].downcase end counter_labels = { code: code, method: method, path: strip_ids_from_path(env["REQUEST_PATH"], method), } duration_labels = { method: method, path: strip_ids_from_path(env["REQUEST_PATH"], method), } @requests.increment(labels: counter_labels) @durations.observe(duration, labels: duration_labels) rescue StandardError # 例外発生時ここでキャッチできるのでデバッグも可能 nil end end end end
まとめ
実際のところこの方法が適切だったかはわかりません。。。
調べても情報が出てこなかったので、少しでもお役に立てれば幸いです!