wwwave'sTechblog |ウェイブのエンジニアブログ

株式会社ウェイブのエンジニアによるテックブログです。会社の話や Ruby、Vue.jsについてなど技術的な話をしていきたいと思います。

株式会社ウェイブの人事部ブログです。社内の雰囲気やイベント、福利厚生などについてお伝えいたします!

株式会社ウェイブのエンジニアブログです。 エンジニアの目線から会社の話や技術的な話をしていきます。

Railsで例外発生時、prometheus-client のメトリクスが取得できていない問題の解決方法

執筆者: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

まとめ

実際のところこの方法が適切だったかはわかりません。。。
調べても情報が出てこなかったので、少しでもお役に立てれば幸いです!

トップに戻る