PromEx.Plug's internal path check doesn't match when forwarded under /metrics (conn.path_info is [] after the forward strips the prefix), so it silently returned without sending a response. Call PromEx.get_metrics/1 directly and send the text body ourselves — tested, returns 200 with all 23 registered event handlers producing proper Prometheus histogram output.
56 lines
1.3 KiB
Elixir
56 lines
1.3 KiB
Elixir
defmodule MicrowavepropWeb.MetricsPlug do
|
|
@moduledoc """
|
|
Serves PromEx metrics at `/metrics`. Optionally gated by a bearer
|
|
token via `config :microwaveprop, :prometheus_auth_token`, sourced
|
|
from the `PROMETHEUS_AUTH_TOKEN` env var in `runtime.exs`.
|
|
"""
|
|
|
|
@behaviour Plug
|
|
|
|
import Plug.Conn
|
|
|
|
@impl true
|
|
def init(opts), do: opts
|
|
|
|
@impl true
|
|
def call(conn, _opts) do
|
|
case authorized?(conn) do
|
|
:ok ->
|
|
body = PromEx.get_metrics(Microwaveprop.PromEx)
|
|
|
|
conn
|
|
|> put_resp_content_type("text/plain; version=0.0.4")
|
|
|> send_resp(200, body)
|
|
|> halt()
|
|
|
|
:denied ->
|
|
conn
|
|
|> put_resp_header("www-authenticate", ~s(Bearer realm="metrics"))
|
|
|> send_resp(401, "unauthorized")
|
|
|> halt()
|
|
end
|
|
end
|
|
|
|
defp authorized?(conn) do
|
|
case Application.get_env(:microwaveprop, :prometheus_auth_token) do
|
|
token when is_binary(token) and token != "" ->
|
|
check_token(conn, token)
|
|
|
|
_ ->
|
|
:ok
|
|
end
|
|
end
|
|
|
|
defp check_token(conn, expected) do
|
|
conn
|
|
|> get_req_header("authorization")
|
|
|> List.first()
|
|
|> case do
|
|
"Bearer " <> token ->
|
|
if Plug.Crypto.secure_compare(token, expected), do: :ok, else: :denied
|
|
|
|
_ ->
|
|
:denied
|
|
end
|
|
end
|
|
end
|