defmodule Ogle.Codegen do @moduledoc false alias Ogle.Options alias Ogle.Persistent def module(ogle_name) do :"Ogle.Codegen.#{ogle_name}" end def create(%Options{} = ogle_options) do %Options{name: name, global_tags: global_tags} = ogle_options module_name = module(name) handle_event_ast = build_handle_event_ast(name) other_funs_ast = other_funs_ast() module_ast = quote do defmodule unquote(module_name) do require Persistent @compile {:inline, global_tags: 0} def global_tags(), do: unquote(Macro.escape(global_tags)) def name(), do: unquote(name) unquote(handle_event_ast) unquote(other_funs_ast) end end [{_module, _bin}] = Code.compile_quoted(module_ast) :ok end def purge(ogle_name) do :code.purge(module(ogle_name)) end defp build_handle_event_ast(ogle_name) do quote do def handle_event(event, measurements, metadata, _) do global_tags = global_tags() %Persistent{ events_to_metrics: %{^event => metrics}, storage: {storage_mod, storage} } = Persistent.fast_fetch(unquote(ogle_name)) :lists.foreach( fn {metric, id} -> %{ measurement: measurement, tag_values: tag_values, tags: tags, keep: keep } = metric if keep?(keep, metadata, measurement) do case fetch_measurement(measurement, measurements, metadata) do value when is_number(value) -> tag_values = tag_values.(metadata) tags = Map.merge(global_tags, Map.take(tag_values, tags)) storage_mod.insert_metric(storage, id, metric, value, tags) _ -> nil end end end, metrics ) end end end # credo:disable-for-next-line Credo.Check.Refactor.CyclomaticComplexity defp other_funs_ast() do quote do defp keep?(keep, metadata, measurement) when is_function(keep, 2), do: keep.(metadata, measurement) defp keep?(keep, metadata, _measurement) when is_function(keep, 1), do: keep.(metadata) defp keep?(_keep, _metadata, _measurement), do: true defp fetch_measurement(%Telemetry.Metrics.Counter{}, _measurements, _metadata) do 1 end defp fetch_measurement(measurement, measurements, metadata) do case measurement do nil -> nil fun when is_function(fun, 1) -> fun.(measurements) fun when is_function(fun, 2) -> fun.(measurements, metadata) key -> case measurements do %{^key => nil} -> 1 %{^key => false} -> 1 %{^key => value} -> value _ -> 1 end end end end end end