Skip to content

Instantly share code, notes, and snippets.

@wfgilman
Last active April 19, 2018 18:03
Show Gist options
  • Save wfgilman/1849a111b72ef69f0713520eb8d5920a to your computer and use it in GitHub Desktop.
Save wfgilman/1849a111b72ef69f0713520eb8d5920a to your computer and use it in GitHub Desktop.
GenServer reporting to Appsignal
defmodule Pipeline.Metrics do
defstruct transaction: nil, key: nil, action: nil
use GenServer
require Logger
@namespace :pipeline
def start_link do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def open(keys, pipeline) when is_list(keys) do
keys
|> format()
|> Enum.each(&GenServer.cast(__MODULE__, {:open, &1, pipeline}))
end
def open(key, pipeline) do
GenServer.cast(__MODULE__, {:open, format(key), pipeline})
end
def close(key) do
GenServer.cast(__MODULE__, {:close, format(key)})
end
def start(key) do
GenServer.cast(__MODULE__, {:start, format(key)})
end
def finish(key, metadata) do
GenServer.cast(__MODULE__, {:end, format(key), metadata})
end
@impl true
def init(:ok) do
state = []
{:ok, state}
end
@impl true
def handle_cast({:open, key, pipeline}, state) do
transaction = Appsignal.Transaction.start(
Appsignal.Transaction.generate_id(),
@namespace
)
Logger.info fn -> "Started Transaction: #{inspect(key)}" end
entry = struct(__MODULE__, [transaction: transaction, key: key, action: pipeline])
{:noreply, [entry | state]}
end
def handle_cast({:close, key}, state) do
{metric, state} = Enum.split_with(state, &(&1.key == key))
unless metric == [] do
%{transaction: t, action: action} = Enum.at(metric, 0)
Appsignal.Transaction.set_action(t, action)
Appsignal.Transaction.finish(t)
:ok = Appsignal.Transaction.complete(t)
Logger.info fn -> "Completed Transaction: #{inspect(key)}" end
end
{:noreply, state}
end
def handle_cast({:start, key}, state) do
case find(key, state) do
nil ->
:ok
Logger.info fn -> "Failed to Start Event: #{inspect(key)}" end
metric ->
Appsignal.Transaction.start_event(metric.transaction)
Logger.info fn -> "Started Event: #{inspect(key)}" end
end
{:noreply, state}
end
def handle_cast({:end, key, metadata}, state) do
case find(key, state) do
nil ->
:ok
Logger.info fn -> "Failed to Finish Event: #{inspect(key)}, #{inspect(metadata)}" end
metric ->
Appsignal.Transaction.finish_event(metric.transaction, metadata[:name], metadata[:title], "", 0)
Logger.info fn -> "Finished Event: #{inspect(key)}, #{inspect(metadata)}" end
end
{:noreply, state}
end
defp find(key, state) do
case Enum.split_with(state, &(&1.key == key)) do
{[], _} ->
nil
{[metric], _} ->
metric
end
end
defp format(keys) when is_list(keys) do
Enum.map(keys, &format/1)
end
defp format(%{__struct__: struct, id: id}) do
{struct, id}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment