查看源代码 配置指标历史记录

如果您希望使用从遥测或其他数据源保存的历史记录填充指标,请修改仪表板配置(在“my_app_web/router.ex”中)以包含一个名为 metrics_history 的键,如下所示

live_dashboard "/dashboard",
  metrics: MyAppWeb.Telemetry,
  metrics_history: {MyApp.MetricsStorage, :metrics_history, []}

其中 MetricsStorage 是一个模块,:metrics_history 是一个函数,在本例中接受一个参数,该参数始终是指标。

该函数必须返回一个列表,如果没有数据则返回空列表,或者返回一个包含 :label:measurement:time 键的映射列表。该函数 Phoenix.LiveDashboard.extract_datapoint_for_metric/4 将以这种格式返回一个映射(如果要覆盖默认的 System.system_time(:microsecond),则可以选择时间参数),或者它可能返回 nil,在这种情况下,数据点不应保存。

您可以将数据存储在 ETS 表、Redis、数据库或其他任何地方,但在此示例中,我们将使用一个带有 循环缓冲区 的 GenServer,以在每个客户端连接时发出最近的遥测数据。

在您的 mix.exs 中,将以下内容添加到您的 deps

  {:circular_buffer, "~> 0.4.0"},

然后添加以下模块“lib/my_app_web/metrics_storage.ex”

  defmodule MyAppWeb.MetricsStorage do
    use GenServer

    @history_buffer_size 50

    def metrics_history(metric) do
      GenServer.call(__MODULE__, {:data, metric})
    end

    def start_link(args) do
      GenServer.start_link(__MODULE__, args, name: __MODULE__)
    end

    @impl true
    def init(metrics) do
      Process.flag(:trap_exit, true)

      metric_histories_map =
        metrics
        |> Enum.map(fn metric ->
          attach_handler(metric)
          {metric, CircularBuffer.new(@history_buffer_size)}
        end)
        |> Map.new()

      {:ok, metric_histories_map}
    end

    @impl true
    def terminate(_, metrics) do
      for metric <- metrics do
        :telemetry.detach({__MODULE__, metric, self()})
      end

      :ok
    end

    defp attach_handler(%{event_name: name_list} = metric) do
      :telemetry.attach(
        {__MODULE__, metric, self()},
        name_list,
        &__MODULE__.handle_event/4,
        metric
      )
    end

    def handle_event(_event_name, data, metadata, metric) do
      if data = Phoenix.LiveDashboard.extract_datapoint_for_metric(metric, data, metadata) do
        GenServer.cast(__MODULE__, {:telemetry_metric, data, metric})
      end
    end

    @impl true
    def handle_cast({:telemetry_metric, data, metric}, state) do
      {:noreply, update_in(state[metric], &CircularBuffer.insert(&1, data))}
    end

    @impl true
    def handle_call({:data, metric}, _from, state) do
      if history = state[metric] do
        {:reply, CircularBuffer.to_list(history), state}
      else
        {:reply, [], state}
      end
    end
  end

最后,将新模块添加到您的应用程序子项中,并使用您的一些或所有指标对其进行初始化,例如来自 MyAppWeb.Telemetry.metrics/0 的指标。

  # Start genserver to store transient metrics
  {MyAppWeb.MetricsStorage, MyAppWeb.Telemetry.metrics()},

现在,当您在指标仪表板中选择一个选项卡时,LiveDashboard 将调用您的模块以获取该选项卡的指标历史记录。