Use a genserver to periodically fetch metrics

Ref https://github.com/beam-telemetry/telemetry_metrics_prometheus_core/issues/52
This commit is contained in:
FloatingGhost 2023-01-01 18:32:14 +00:00
parent 6be3383a09
commit 6e646c4cbc
4 changed files with 71 additions and 5 deletions

View file

@ -0,0 +1,49 @@
defmodule Pleroma.PrometheusExporter do
@moduledoc """
Exports metrics in Prometheus format.
Mostly exists because of https://github.com/beam-telemetry/telemetry_metrics_prometheus_core/issues/52
Basically we need to fetch metrics every so often, or the lib will let them pile up and eventually crash the VM.
It also sorta acts as a cache so there is that too.
"""
use GenServer
require Logger
def start_link(_opts) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def init(_opts) do
schedule_next()
{:ok, ""}
end
defp schedule_next do
Process.send_after(self(), :gather, 60_000)
end
# Scheduled function, gather metrics and schedule next run
def handle_info(:gather, _state) do
schedule_next()
state = TelemetryMetricsPrometheus.Core.scrape()
{:noreply, state}
end
# Trigger the call dynamically, mostly for testing
def handle_call(:gather, _from, _state) do
state = TelemetryMetricsPrometheus.Core.scrape()
{:reply, state, state}
end
def handle_call(:show, _from, state) do
{:reply, state, state}
end
def show do
GenServer.call(__MODULE__, :show)
end
def gather do
GenServer.call(__MODULE__, :gather)
end
end

View file

@ -15,7 +15,7 @@ defmodule Pleroma.Web.AkkomaAPI.MetricsController do
def show(conn, _params) do def show(conn, _params) do
if Config.get([:instance, :export_prometheus_metrics], true) do if Config.get([:instance, :export_prometheus_metrics], true) do
conn conn
|> text(TelemetryMetricsPrometheus.Core.scrape()) |> text(Pleroma.PrometheusExporter.show())
else else
conn conn
|> send_resp(404, "Not Found") |> send_resp(404, "Not Found")

View file

@ -2,6 +2,7 @@ defmodule Pleroma.Web.Telemetry do
use Supervisor use Supervisor
import Telemetry.Metrics import Telemetry.Metrics
alias Pleroma.Stats alias Pleroma.Stats
alias Pleroma.Config
def start_link(arg) do def start_link(arg) do
Supervisor.start_link(__MODULE__, arg, name: __MODULE__) Supervisor.start_link(__MODULE__, arg, name: __MODULE__)
@ -9,14 +10,28 @@ defmodule Pleroma.Web.Telemetry do
@impl true @impl true
def init(_arg) do def init(_arg) do
children = [ children =
{:telemetry_poller, measurements: periodic_measurements(), period: 10_000}, [
{TelemetryMetricsPrometheus.Core, metrics: prometheus_metrics()} {:telemetry_poller, measurements: periodic_measurements(), period: 10_000}
] ] ++
prometheus_children()
Supervisor.init(children, strategy: :one_for_one) Supervisor.init(children, strategy: :one_for_one)
end end
defp prometheus_children do
config = Config.get([:instance, :export_prometheus_metrics], true)
if config do
[
{TelemetryMetricsPrometheus.Core, metrics: prometheus_metrics()},
Pleroma.PrometheusExporter
]
else
[]
end
end
# A seperate set of metrics for distributions because phoenix dashboard does NOT handle them well # A seperate set of metrics for distributions because phoenix dashboard does NOT handle them well
defp distribution_metrics do defp distribution_metrics do
[ [

View file

@ -5,6 +5,8 @@ defmodule Pleroma.Web.AkkomaAPI.MetricsControllerTest do
test "should return metrics when the user has admin:metrics" do test "should return metrics when the user has admin:metrics" do
%{conn: conn} = oauth_access(["admin:metrics"]) %{conn: conn} = oauth_access(["admin:metrics"])
Pleroma.PrometheusExporter.gather()
resp = resp =
conn conn
|> get("/api/v1/akkoma/metrics") |> get("/api/v1/akkoma/metrics")