PrometheusでPhoenixを監視する

以前PrometheusでElixir Plugからメトリクスの収集をできるよう設定をしました。 今回はPhoenixで設定をしていきたいと思います。

ちなみに、下記のものがPlug単体のときに設定したものになります。

kobatako.hatenablog.com

目次

  1. 環境情報
  2. Phoenixのメトリクス収集の設定
  3. カスタムメトリクスに入門する
  4. 終わりに

1. 環境情報

  • Elixir: 1.9.1
  • Phoenix: 1.4.11
  • prometheus_phoenix: 1.3.0
  • prometheus_plugs: 1.1.5

2. Phoenixのメトリクス収集の設定

諸々のインストール

mix.exsprometheus_phoenixprometheus_plugs を追加します

・・・
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:prometheus_phoenix, "~> 1.3.0"},
      {:prometheus_plugs, "~> 1.1.5"}
    ]
  end

追加したら deps.get でインストールしていきます。

$ mix deps.get
・・・
New:
  accept 0.3.5
  prometheus 4.4.1
  prometheus_ex 3.0.5
  prometheus_phoenix 1.3.0
  prometheus_plugs 1.1.5
* Getting prometheus_phoenix (Hex package)
* Getting prometheus_plugs (Hex package)
* Getting accept (Hex package)
* Getting prometheus_ex (Hex package)
* Getting prometheus (Hex package)

必要なもののインストールが完了したので、ExporterとPhoenixのメトリクス収集のための設定をしていきたいと思います。

Exporterとメトリクス収集の設定

まずは、Exporter用のモジュールの作成をしていきます。

defmodule SamplePhoenix.PrometheusExporter do
  use Prometheus.PlugExporter
end

これはPlugでの設定と同様のものになります。

次に、Phoenixのメトリクス収集のためのモジュールを作成していきます。

defmodule SamplePhoenix.Instrumenter do
  use Prometheus.PhoenixInstrumenter
end

use Prometheus.PhoenixInstrumenter を記述するだけという、簡単なものになります。

ExporterとPhoenixのメトリクス収集用のモジュールが作成できたので application.ex にセットアップ処理を追加します。

  def start(_type, _args) do
  ・・・
    SamplePhoenix.Instrumenter.setup()
    SamplePhoenix.PrometheusExporter.setup()
    
    opts = [strategy: :one_for_one, name: SamplePhoenix.Supervisor]
    Supervisor.start_link(children, opts)

それぞれのモジュールで setup メソッドを呼べば完了となります。

次にExporter用のPlugの設定をしていきます。

Phoenixではよく router.ex にPlugの追加をすると思いますが、PrometheusのPlugの追加は endpoint.ex に追加します。

・・・
  plug SamplePhoenix.PrometheusExporter

  plug SamplePhoenixWeb.Router
end

これで一通り準備完了です。 一度、適当にアクセス(トップページとか)してから /metrics にアクセスし、メトリクスを確認してみましょう。

phoenix_controller_render_duration_microseconds_bucket{format="html",template="index.html",view="Elixir.SamplePhoenixWeb.PageView",le="10"} 0
phoenix_controller_render_duration_microseconds_bucket{format="html",template="index.html",view="Elixir.SamplePhoenixWeb.PageView",le="25"} 0
phoenix_controller_render_duration_microseconds_bucket{format="html",template="index.html",view="Elixir.SamplePhoenixWeb.PageView",le="50"} 0
phoenix_controller_render_duration_microseconds_bucket{format="html",template="index.html",view="Elixir.SamplePhoenixWeb.PageView",le="100"} 8

・・・

phoenix_channel_join_duration_microseconds_bucket{channel="Phoenix.LiveReloader.Channel",topic="phoenix:live_reload",transport="websocket",le="10000000"} 7
phoenix_channel_join_duration_microseconds_bucket{channel="Phoenix.LiveReloader.Channel",topic="phoenix:live_reload",transport="websocket",le="+Inf"} 7
phoenix_channel_join_duration_microseconds_count{channel="Phoenix.LiveReloader.Channel",topic="phoenix:live_reload",transport="websocket"} 7
phoenix_channel_join_duration_microseconds_sum{channel="Phoenix.LiveReloader.Channel",topic="phoenix:live_reload",transport="websocket"} 748.044

・・・

phoenix_controller_call_duration_microseconds_bucket{action="index",controller="SamplePhoenixWeb.PageController",le="+Inf"} 15
phoenix_controller_call_duration_microseconds_count{action="index",controller="SamplePhoenixWeb.PageController"} 15
phoenix_controller_call_duration_microseconds_sum{action="index",controller="SamplePhoenixWeb.PageController"} 7902.988

無事にPhoenixのメトリクス情報を確認することができましたね。

メトリクスですが、phoenix_controller_render_duration_microseconds_bucket では呼ばれたformat、template、viewが確認でき、phoenix_controller_call_duration_microseconds_bucket では呼ばれたactionとcontrollerが確認できます。 これだけでもメトリクスの収集としてはだいぶいい情報が集まってると思います。

Phoenixのメトリクス収集の設定ですが、今回は特にしてなかったですが設定を変更することができます。下記ドキュメントに記載されているので、もしよかったら合わせて確認してみてくださいな。

hexdocs.pm

3. カスタムメトリクスに入門する

次にカスタムメトリクスを追加してみたいと思います。 今回作成してものはトップページにリクエストが来たらカウントアップするだけという単純なものになります。

早速、カウントアップ用のモジュールを用意したいと思います。

defmodule SamplePhoenix.TopHttpRequestInstrumenter do
  use Prometheus.Metric

  def setup do
    Counter.declare([name: :top_request_count,
                   help: "http request count"])
  end

  def add() do
    Counter.inc([name: :top_request_count])
  end
end

setup メソッドでは Counter.declare を呼びます。これで top_request_count メトリクスのCounterを作成します。

add メソッドでは top_request_count メトリクスの値をインクリメントするよう、Counter.inc を呼びます。 ですのでトップページにリクエストがきたタイミングで add メソッドを呼ぶ処理を追加してあげれば top_request_count メトリクスがインクリメントされるようになります。

カスタムモジュールの準備ができたのでセットアップ処理を application.ex 追加します。

  def start(_type, _args) do
  ・・・
    # 追加分
    SamplePhoenix.TopHttpRequestInstrumenter.setup()
    SamplePhoenix.Instrumenter.setup()
    SamplePhoenix.PrometheusExporter.setup()

次にトップページにリクエストが来たときに呼ばれるコントローラに add メソッドを呼ぶよう処理を追加しましょう。

  def index(conn, _params) do
    SamplePhoenix.TopHttpRequestInstrumenter.add()
    render(conn, "index.html")
  end

これで準備が完了しました。Phoenixを起動させ、 /metrics にアクセスしてみましょう。

# TYPE top_request_count counter
# HELP top_request_count http request count
top_request_count 0

まだ一度もトップページにリクエストしてないので、カウントは0の状態ですね。

試しに、5回ほど、トップページにリクエストした後にメトリクスを確認してみます。

# TYPE top_request_count counter
# HELP top_request_count http request count
top_request_count 5

無事にカウントアップされてるのが確認できました。 以上で、カスタムメトリクスの設定は完了となります。

補足ですが、今回カスタムメトリクスで Counter を使ってみましたが、ほかにも GaugeSummaryHistogram Boolean などがあります。

それぞれの用途は下記のようにあります。

  • Counter: カウンタアップしていくもの(リクエスト数など)
  • Gauge: 瞬間的な値(メモリ利用量など)
  • Summary: 平均値(レイテンシなど)
  • Histogram: データの分布などに使う(レイテンシのパーセントごとに分布させるなど)
  • Boolean: True or Falseでのフラグ(ステータスなど)

4. 終わりに

今回はPhoenixでPrometheus用のExporterの設定とメトリクスの監視、カスタムメトリクスの追加まで行いました。 デフォルトのPhoenixのPrometheusのメトリクスでも十分な部分もありますが、よりアプリケーションよりのメトリクスを監視したい場合はカスタムメトリクスが必要になってくると思います。なので Counter Gauge Summary Histogram Boolean がどのようにメトリクスを収集するのか性質を把握しておく必要があります。

ただ、カスタムメトリクスの設定自体は簡単なものだったので他のも機会を見つけて試していきたいと思います。