defmodule Integrations.MongoDb.Display do @moduledoc """ Dashboard panel for `Integrations.MongoDb` (same package). Nested under the monitor's own namespace deliberately — the package's top-level module name never changes, and this module's name is guaranteed distinct from any separately-published standalone display package. `Display.BundledDefault` auto-hooks this whenever `Integrations.MongoDb` starts, the same as if they were still one module. """ use CodeNameRaven.Display, category: :infrastructure, size_hint: :large @default_port 27017 @impl true def display_name, do: "MongoDB" @impl true def compatible_monitors, do: [Integrations.MongoDb] @impl true def render(assigns) do samples = CodeNameRaven.Runtime.recent_samples(assigns.config.id, limit: 120) local_id = CodeNameRaven.Runtime.instance_id() result = assigns[:result] ops = result && result[:ops] conns = result && result[:connections] mem = result && result[:memory] db_st = result && result[:db_stats] assigns = Map.merge(assigns, %{ samples: samples, local_id: local_id, result: result, ops: ops, conns: conns, mem: mem, db_st: db_st }) ~H"""
<%!-- Header --%>

<%= @config.name || instance_title(@config.params) %>

<%= instance_title(@config.params) %> <%= if @result && @result[:version], do: " · v#{@result.version}" %>

<.status_chip status={@status} /> <%= if @result.is_primary, do: "primary", else: "secondary" %> · <%= @result.replica_set %>
<%!-- Vital stats --%>
<.stat label="Latency" value={"#{(@result && @result.latency_ms) || "–"} ms"} /> <.stat label="Connections" value={conn_label(@conns)} /> <.stat label="Ops/s" value={format_rate(@ops && @ops[:total_rate])} /> <.stat label="Mem" value={format_mb(@mem && @mem[:resident_mb])} />
<%!-- DB stats row --%>
<.stat label="Collections" value={"#{@db_st[:collections] || "–"}"} /> <.stat label="Objects" value={format_count(@db_st[:objects])} /> <.stat label="Data" value={format_bytes(@db_st[:data_size_bytes])} /> <.stat label="Indexes" value={format_bytes(@db_st[:index_size_bytes])} />
<%!-- Charts --%>

Operations / sec

Connections

Latency

Resident Memory (MB)

Checked <%= CodeNameRaven.Timezone.format_datetime(@last_checked_at, __MODULE__) %>

""" end # --------------------------------------------------------------------------- # Private components # --------------------------------------------------------------------------- defp status_chip(%{status: :up} = assigns) do ~H""" Up """ end defp status_chip(%{status: :degraded} = assigns) do ~H""" Degraded """ end defp status_chip(%{status: :down} = assigns) do ~H""" Down """ end defp status_chip(assigns) do ~H""" Unknown """ end defp stat(assigns) do ~H"""

<%= @label %>

<%= @value %>

""" end # --------------------------------------------------------------------------- # Private helpers # --------------------------------------------------------------------------- defp instance_title(params) do host = params[:host] || params["host"] || "?" port = parse_int(params[:port] || params["port"], @default_port) "#{host}:#{port}" end defp conn_label(%{current: c, available: a}) when is_integer(c) and is_integer(a), do: "#{c} (#{a} avail)" defp conn_label(%{current: c}) when is_integer(c), do: to_string(c) defp conn_label(nil), do: "–" defp conn_label(_), do: "–" defp format_rate(nil), do: "–" defp format_rate(r), do: "#{r}/s" defp format_mb(nil), do: "–" defp format_mb(mb), do: "#{mb} MB" defp format_count(nil), do: "–" defp format_count(n) when n >= 1_000_000, do: "#{Float.round(n / 1_000_000, 1)}M" defp format_count(n) when n >= 1_000, do: "#{Float.round(n / 1_000, 1)}K" defp format_count(n), do: to_string(n) defp format_bytes(nil), do: "–" defp format_bytes(b) when b >= 1_073_741_824, do: "#{Float.round(b / 1_073_741_824, 1)} GB" defp format_bytes(b) when b >= 1_048_576, do: "#{Float.round(b / 1_048_576, 1)} MB" defp format_bytes(b) when b >= 1_024, do: "#{Float.round(b / 1_024, 1)} KB" defp format_bytes(b), do: "#{round(b)} B" defp parse_int(nil, default), do: default defp parse_int(v, _) when is_integer(v), do: v defp parse_int(v, default) when is_binary(v) do case Integer.parse(v) do {n, _} -> n :error -> default end end defp parse_int(_, default), do: default end