diff --git a/lib/peep.ex b/lib/peep.ex index 46f6af7..2c44c43 100644 --- a/lib/peep.ex +++ b/lib/peep.ex @@ -68,8 +68,13 @@ defmodule Peep do values are already precomputed, for example presummed socket stats. """ use GenServer + require Logger - alias Peep.{EventHandler, Options, Statsd} + require Peep.Persistent + + alias Peep.EventHandler + alias Peep.Options + alias Peep.Statsd defmodule State do @moduledoc false @@ -98,10 +103,10 @@ defmodule Peep do def insert_metric(name, metric, value, tags) when is_number(value) do case Peep.Persistent.fetch(name) do - %Peep.Persistent{ + Peep.Persistent.persistent( storage: {storage_mod, storage}, metrics_to_ids: %{^metric => id} - } -> + ) -> storage_mod.insert_metric(storage, id, metric, value, tags) _ -> @@ -136,7 +141,7 @@ defmodule Peep do """ def get_all_metrics(name) do case Peep.Persistent.fetch(name) do - %Peep.Persistent{storage: {storage_mod, storage}} = p -> + Peep.Persistent.persistent(storage: {storage_mod, storage}) = p -> storage_mod.get_all_metrics(storage, p) _ -> @@ -153,10 +158,10 @@ defmodule Peep do def get_metric(name, metric, tags) do case Peep.Persistent.fetch(name) do - %Peep.Persistent{ + Peep.Persistent.persistent( storage: {storage_mod, storage}, metrics_to_ids: %{^metric => id} - } -> + ) -> storage_mod.get_metric(storage, id, metric, tags) _ -> diff --git a/lib/peep/codegen.ex b/lib/peep/codegen.ex index d9af558..9151a20 100644 --- a/lib/peep/codegen.ex +++ b/lib/peep/codegen.ex @@ -2,7 +2,6 @@ defmodule Peep.Codegen do @moduledoc false alias Peep.Options - alias Peep.Persistent def module(peep_name) do :"Peep.Codegen.#{peep_name}" @@ -18,7 +17,7 @@ defmodule Peep.Codegen do module_ast = quote do defmodule unquote(module_name) do - require Persistent + import Peep.Persistent, only: [fast_fetch: 1, persistent: 1] @compile {:inline, global_tags: 0} @@ -43,10 +42,10 @@ defmodule Peep.Codegen do def handle_event(event, measurements, metadata, _) do global_tags = global_tags() - %Persistent{ + persistent( events_to_metrics: %{^event => metrics}, storage: {storage_mod, storage} - } = Persistent.fast_fetch(unquote(peep_name)) + ) = fast_fetch(unquote(peep_name)) :lists.foreach( fn {metric, id} -> diff --git a/lib/peep/event_handler.ex b/lib/peep/event_handler.ex index db1add5..e1f3f6f 100644 --- a/lib/peep/event_handler.ex +++ b/lib/peep/event_handler.ex @@ -3,8 +3,10 @@ defmodule Peep.EventHandler do @compile :inline + import Peep.Persistent, only: [persistent: 1] + def attach(name) do - %Peep.Persistent{events_to_metrics: metrics_by_event} = Peep.Persistent.fetch(name) + persistent(events_to_metrics: metrics_by_event) = Peep.Persistent.fetch(name) module = Peep.Codegen.module(name) for {event_name, _metrics} <- metrics_by_event do diff --git a/lib/peep/persistent.ex b/lib/peep/persistent.ex index 52dd5de..862fe44 100644 --- a/lib/peep/persistent.ex +++ b/lib/peep/persistent.ex @@ -1,6 +1,15 @@ defmodule Peep.Persistent do @moduledoc false - defstruct [:name, :storage, :events_to_metrics, :ids_to_metrics, :metrics_to_ids] + + require Record + + Record.defrecord(:persistent, [ + :name, + :storage, + events_to_metrics: %{}, + ids_to_metrics: %{}, + metrics_to_ids: %{} + ]) @compile {:inline, key: 1, fetch: 1} @@ -10,16 +19,17 @@ defmodule Peep.Persistent do @typep events_to_metrics() :: %{ :telemetry.event_name() => [{Telemetry.Metrics.t(), non_neg_integer()}] } - @typep ids_to_metrics :: %{Peep.metric_id() => Telemetry.Metrics.t()} - @typep metrics_to_ids :: %{Telemetry.Metrics.t() => Peep.metric_id()} - - @type t() :: %__MODULE__{ - name: name(), - storage: storage(), - events_to_metrics: events_to_metrics(), - ids_to_metrics: ids_to_metrics(), - metrics_to_ids: metrics_to_ids() - } + @typep metrics_to_ids() :: %{Telemetry.Metrics.t() => Peep.metric_id()} + + @type ids_to_metrics() :: %{Peep.metric_id() => Telemetry.Metrics.t()} + @type t() :: + record(:persistent, + name: name(), + storage: storage(), + events_to_metrics: events_to_metrics(), + ids_to_metrics: ids_to_metrics(), + metrics_to_ids: metrics_to_ids() + ) @spec new(Peep.Options.t()) :: t() def new(%Peep.Options{} = options) do @@ -43,18 +53,18 @@ defmodule Peep.Persistent do metrics_to_ids: metrics_to_ids } = Peep.assign_metric_ids(metrics) - %__MODULE__{ + persistent( name: name, storage: storage, events_to_metrics: events_to_metrics, ids_to_metrics: ids_to_metrics, metrics_to_ids: metrics_to_ids - } + ) end @spec store(t()) :: :ok - def store(%__MODULE__{} = term) do - %__MODULE__{name: name} = term + def store(persistent() = term) do + persistent(name: name) = term :persistent_term.put(key(name), term) end @@ -72,7 +82,7 @@ defmodule Peep.Persistent do @spec storage(name()) :: {module(), term()} | nil def storage(name) when is_atom(name) do case fetch(name) do - %__MODULE__{storage: s} -> + persistent(storage: s) -> s _ -> @@ -80,6 +90,9 @@ defmodule Peep.Persistent do end end + @spec ids_to_metrics(t()) :: ids_to_metrics() + def ids_to_metrics(persistent(ids_to_metrics: itm)), do: itm + defmacro fast_fetch(name) when is_atom(name) do quote do :persistent_term.get(unquote(key(name)), nil) diff --git a/lib/peep/storage/atomics.ex b/lib/peep/storage/atomics.ex index 595fe66..8f1b54d 100644 --- a/lib/peep/storage/atomics.ex +++ b/lib/peep/storage/atomics.ex @@ -1,13 +1,15 @@ defmodule Peep.Storage.Atomics do @moduledoc false - defstruct [ + require Record + + Record.defrecord(:atomic, [ :num_buckets, :buckets, :sum, :above_max, :bucket_calculator - ] + ]) def new(%Telemetry.Metrics.Distribution{} = metric) do {bucket_calculator, config} = Peep.Buckets.config(metric) @@ -16,23 +18,23 @@ defmodule Peep.Storage.Atomics do sum = :atomics.new(1, signed: true) above_max = :atomics.new(1, signed: false) - %__MODULE__{ + atomic( num_buckets: num_buckets, buckets: buckets, sum: sum, above_max: above_max, bucket_calculator: {bucket_calculator, config} - } + ) end def insert( - %__MODULE__{ + atomic( bucket_calculator: {module, config}, buckets: buckets, sum: sum, num_buckets: num_buckets, above_max: above_max - }, + ), value ) do # :atomics indexes are 1-based. @@ -50,13 +52,15 @@ defmodule Peep.Storage.Atomics do :atomics.add(sum, 1, round(value)) end - def values(%__MODULE__{ - bucket_calculator: {module, config}, - buckets: buckets, - sum: sum, - above_max: above_max, - num_buckets: num_buckets - }) do + def values( + atomic( + bucket_calculator: {module, config}, + buckets: buckets, + sum: sum, + above_max: above_max, + num_buckets: num_buckets + ) + ) do map = for idx <- 1..num_buckets, into: %{} do {module.upper_bound(idx - 1, config), :atomics.get(buckets, idx)} diff --git a/lib/peep/storage/ets.ex b/lib/peep/storage/ets.ex index 5a499ab..58bee82 100644 --- a/lib/peep/storage/ets.ex +++ b/lib/peep/storage/ets.ex @@ -7,6 +7,9 @@ defmodule Peep.Storage.ETS do consider switching to `Peep.Storage.Striped`, which reduces lock contention at the cost of higher memory usage. """ + + require Peep.Storage.Atomics + alias Peep.Storage alias Telemetry.Metrics @@ -81,9 +84,9 @@ defmodule Peep.Storage.ETS do end @impl true - def get_all_metrics(tid, %Peep.Persistent{ids_to_metrics: itm}) do + def get_all_metrics(tid, persistent) do :ets.tab2list(tid) - |> group_metrics(itm, %{}) + |> group_metrics(Peep.Persistent.ids_to_metrics(persistent), %{}) end @impl true @@ -153,7 +156,7 @@ defmodule Peep.Storage.ETS do update_in(acc, [Access.key(metric, %{}), Access.key(tags, 0)], &(&1 + value)) end - defp group_metric({{id, tags}, %Storage.Atomics{} = atomics}, itm, acc) do + defp group_metric({{id, tags}, Storage.Atomics.atomic() = atomics}, itm, acc) do %{^id => metric} = itm put_in(acc, [Access.key(metric, %{}), Access.key(tags)], Storage.Atomics.values(atomics)) end diff --git a/lib/peep/storage/striped.ex b/lib/peep/storage/striped.ex index 95d3713..a5013e0 100644 --- a/lib/peep/storage/striped.ex +++ b/lib/peep/storage/striped.ex @@ -5,6 +5,7 @@ defmodule Peep.Storage.Striped do Offers less lock contention than `Peep.Storage.ETS`, at the cost of higher memory usage. Recommended when executing thousands of metrics per second. """ + alias Telemetry.Metrics alias Peep.Storage @@ -187,7 +188,8 @@ defmodule Peep.Storage.Striped do end @impl true - def get_all_metrics(tids, %Peep.Persistent{ids_to_metrics: itm}) do + def get_all_metrics(tids, persistent) do + itm = Peep.Persistent.ids_to_metrics(persistent) acc = get_all_metrics2(Tuple.to_list(tids), itm, %{}) remove_timestamps_from_last_values(acc) end diff --git a/test/support/custom_storage.ex b/test/support/custom_storage.ex index b01ea37..4b30777 100644 --- a/test/support/custom_storage.ex +++ b/test/support/custom_storage.ex @@ -7,9 +7,13 @@ defmodule CustomStorage do """ @behaviour Peep.Storage + require Peep.Persistent + require Peep.Storage.Atomics + alias Telemetry.Metrics alias Peep.Storage + @impl true @spec new(non_neg_integer) :: tuple def new(n_agents) do @@ -85,7 +89,7 @@ defmodule CustomStorage do end @impl true - def get_all_metrics(agents, %Peep.Persistent{ids_to_metrics: itm}) do + def get_all_metrics(agents, Peep.Persistent.persistent(ids_to_metrics: itm)) do agents |> Tuple.to_list() |> Enum.flat_map(fn agent -> @@ -205,7 +209,7 @@ defmodule CustomStorage do group_metrics(rest, itm, acc2) end - defp group_metric({{id, tags}, %Storage.Atomics{} = atomics}, itm, acc) do + defp group_metric({{id, tags}, Storage.Atomics.atomic() = atomics}, itm, acc) do %{^id => metric} = itm put_in(acc, [Access.key(metric, %{}), Access.key(tags)], Storage.Atomics.values(atomics)) end