Wires PromEx with its built-in Application / BEAM / Phoenix / Ecto /
Oban plugins plus a custom `Microwaveprop.PromEx.InstrumentPlugin`
that registers Prometheus histograms for every
`Microwaveprop.Instrument` span (HRRR/NEXRAD/IEM/GEFS/NARR/UWYO
/Elevation fetches, DB batch upserts, terrain analysis, radar
aggregation, propagation score band). Queue-depth gauges from the
10-second poller land at `microwaveprop_oban_queue_count{queue,state}`.
Router forwards `/metrics` to MicrowavepropWeb.MetricsPlug which
optionally requires a bearer token (`PROMETHEUS_AUTH_TOKEN` env var in
runtime.exs); leave it unset to expose metrics publicly and restrict
at the ingress / Cloudflare Access layer instead.
Example external Prometheus scrape config:
scrape_configs:
- job_name: microwaveprop
scrape_interval: 30s
metrics_path: /metrics
scheme: https
authorization:
type: Bearer
credentials: <token>
static_configs:
- targets: ['prop.w5isp.com:443']
51 lines
1.2 KiB
Elixir
51 lines
1.2 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 ->
|
|
PromEx.Plug.call(conn, prom_ex_module: Microwaveprop.PromEx, path: "/metrics")
|
|
|
|
: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
|