defmodule Microwaveprop.PromEx.Plugins.Phoenix do @moduledoc """ Local fork of `PromEx.Plugins.Phoenix` that normalizes the `:transport` tag value in socket and channel event metrics so non-`String.Chars` transport values (e.g., `Phoenix.ChannelTest`'s tuple `{Module, pid}`) are not silently dropped as "bad tag value" by `telemetry_metrics_prometheus_core`. All other metric groups are delegated to the built-in plugin unchanged. """ use PromEx.Plugin alias Phoenix.Socket alias PromEx.Plugins.Phoenix, as: BuiltinPhoenix @impl true def event_metrics(opts) do # Delegate everything to the built-in plugin (which also attaches the # telemetry proxy handlers), then patch only the transport tag in the # two affected groups. opts |> BuiltinPhoenix.event_metrics() |> Enum.map(fn %{group_name: :phoenix_channel_event_metrics} = event -> %{event | metrics: fix_channel_transport(event.metrics)} %{group_name: :phoenix_socket_event_metrics} = event -> %{event | metrics: fix_socket_transport(event.metrics)} event -> event end) end # ── Channel event metrics ────────────────────────────────────────────── defp fix_channel_transport(metrics) do Enum.map(metrics, fn %{event_name: [:phoenix, :channel_joined]} = metric -> %{ metric | tag_values: fn %{ result: result, socket: %Socket{transport: transport, endpoint: endpoint} } -> %{ transport: normalize_transport(transport), result: result, endpoint: normalize_module_name(endpoint) } end } other -> other end) end # ── Socket event metrics ─────────────────────────────────────────────── defp fix_socket_transport(metrics) do Enum.map(metrics, fn %{event_name: [:phoenix, :socket_connected]} = metric -> %{ metric | tag_values: fn %{result: result, endpoint: endpoint, transport: transport} -> %{ transport: normalize_transport(transport), result: result, endpoint: normalize_module_name(endpoint) } end } other -> other end) end # ── Helpers ──────────────────────────────────────────────────────────── defp normalize_transport(transport) do if String.Chars.impl_for(transport) do to_string(transport) else inspect(transport) end end defp normalize_module_name(name) when is_atom(name) do name |> Atom.to_string() |> String.trim_leading("Elixir.") end defp normalize_module_name(name) do String.trim_leading(name, "Elixir.") end end