Current section

Files

Jump to
observer_web lib web components metrics phoenix.ex
Raw

lib/web/components/metrics/phoenix.ex

defmodule Observer.Web.Components.Metrics.Phoenix do
@moduledoc false
use Observer.Web, :html
use Phoenix.Component
alias Observer.Web.Components.Core
attr :title, :string, required: true
attr :service, :string, required: true
attr :metric, :string, required: true
attr :metrics, :list, required: true
attr :cols, :integer, default: 1
attr :transition, :boolean, default: false
attr :supported_metrics, :list,
default: [
"phoenix.endpoint.start.system_time",
"phoenix.endpoint.stop.duration",
"phoenix.router_dispatch.start.system_time",
"phoenix.router_dispatch.exception.duration",
"phoenix.router_dispatch.stop.duration",
"phoenix.socket_connected.duration",
"phoenix.channel_joined.duration",
"phoenix.channel_handled_in.duration"
]
def content(assigns) do
~H"""
<div :if={@metric in @supported_metrics} style={"grid-column: span #{@cols};"}>
<div class="relative flex flex-col min-w-0 break-words bg-white dark:bg-gray-800 w-full shadow-lg rounded border border-blueGray-100 dark:border-neutral-400">
<div class="rounded-t mb-0 px-4 py-3 border-b">
<div class="flex flex-wrap items-center">
<div class="relative w-full px-4 max-w-full flex-grow flex-1">
<h3 class="font-semibold text-base text-blueGray-700 dark:text-neutral-400">
{@title}
</h3>
</div>
</div>
</div>
<%= cond do %>
<% @metric == "phoenix.router_dispatch.start.system_time" -> %>
<Core.table_metrics id={"#{@service}-#{@metric}"} rows={@metrics} transition={@transition}>
<:col :let={{_timestamp, metric}} label="Collected Time">
<.timestamp timestamp={metric.timestamp} />
</:col>
<:col :let={{_timestamp, metric}} label="Start">
<.timestamp timestamp={metric.value} />
</:col>
<:col :let={{_timestamp, metric}} label="Method">
<.method value={metric.tags[:method]} />
</:col>
<:col :let={{_timestamp, metric}} label="Route">{metric.tags[:route]}</:col>
</Core.table_metrics>
<% @metric == "phoenix.router_dispatch.stop.duration" -> %>
<Core.table_metrics id={"#{@service}-#{@metric}"} rows={@metrics} transition={@transition}>
<:col :let={{_timestamp, metric}} label="Collected Time">
<.timestamp timestamp={metric.timestamp} />
</:col>
<:col :let={{_timestamp, metric}} label="Method">
<.method value={metric.tags[:method]} />
</:col>
<:col :let={{_timestamp, metric}} label="Route">{metric.tags[:route]}</:col>
<:col :let={{_timestamp, metric}} label="Duration">
<.duration value={metric.value} unit={metric.unit} />
</:col>
<:col :let={{_timestamp, metric}} label="Status">
<.html_status status={metric.tags[:status]} />
</:col>
</Core.table_metrics>
<% @metric == "phoenix.endpoint.start.system_time" -> %>
<Core.table_metrics id={"#{@service}-#{@metric}"} rows={@metrics} transition={@transition}>
<:col :let={{_timestamp, metric}} label="Collected Time">
<.timestamp timestamp={metric.timestamp} />
</:col>
<:col :let={{_timestamp, metric}} label="Start">
<.timestamp timestamp={metric.value} />
</:col>
<:col :let={{_timestamp, metric}} label="Method">
<.method value={metric.tags[:method]} />
</:col>
</Core.table_metrics>
<% @metric == "phoenix.endpoint.stop.duration" -> %>
<Core.table_metrics id={"#{@service}-#{@metric}"} rows={@metrics} transition={@transition}>
<:col :let={{_timestamp, metric}} label="Collected Time">
<.timestamp timestamp={metric.timestamp} />
</:col>
<:col :let={{_timestamp, metric}} label="Method">
<.method value={metric.tags[:method]} />
</:col>
<:col :let={{_timestamp, metric}} label="Duration">
<.duration value={metric.value} unit={metric.unit} />
</:col>
<:col :let={{_timestamp, metric}} label="Status">
<.html_status status={metric.tags[:status]} />
</:col>
</Core.table_metrics>
<% true -> %>
<Core.table_metrics id={"#{@service}-#{@metric}"} rows={@metrics} transition={@transition}>
<:col :let={{_timestamp, metric}} label="Collected Time">
<.timestamp timestamp={metric.timestamp} />
</:col>
<:col :let={{_timestamp, metric}} label="Duration">
<.duration value={metric.value} unit={metric.unit} />
</:col>
</Core.table_metrics>
<% end %>
</div>
</div>
"""
end
defp timestamp(%{timestamp: timestamp} = assigns) when is_float(timestamp),
do: timestamp(%{assigns | timestamp: trunc(timestamp)})
defp timestamp(assigns) do
~H"""
<div class="flex px-4 py-1 items-center rounded-full bg-gray-200 dark:bg-gray-600">
<span class="text-cyan-600 dark:text-cyan-400 font-semibold text-[9px] ">
{@timestamp |> DateTime.from_unix!(:millisecond) |> DateTime.to_string()}
</span>
</div>
"""
end
defp method(assigns) do
~H"""
<span class="text-black dark:text-neutral-400 font-semibold text-sm ">
{@value}
</span>
"""
end
defp duration(%{unit: unit} = assigns) do
unit =
if unit == " millisecond" do
"ms"
else
unit
end
assigns =
assigns
|> assign(unit: unit)
~H"""
<span class="text-black dark:text-neutral-400 font-semibold text-sm ">
{"#{:erlang.float_to_binary(@value, [{:decimals, 2}])} #{@unit}"}
</span>
"""
end
defp html_status(%{status: status} = assigns) do
color =
cond do
status >= 200 and status < 300 ->
"text-green-600"
status >= 300 and status < 400 ->
"text-yellow-600"
status >= 400 and status < 600 ->
"text-red-600"
true ->
"text-white"
end
assigns =
assigns
|> assign(color: color)
~H"""
<div class="flex px-4 py-1 items-center rounded-full bg-gray-200">
<span class={[@color, "font-semibold text-xs"]}>
{@status}
</span>
</div>
"""
end
end