Current section
Files
Jump to
Current section
Files
lib/metrics/workers/couter.ex
defmodule Metrex.Counter do
@moduledoc """
Counter metrics implementation
## Examples
Static counters:
Add list of counters into config.exs file to autostart counters:
config :metrex,
counters: ["pageviews"]
On-demand counters:
To create on-demand counters, you need to call `start_link` function:
# Initialize counter with 0
Metrex.start_counter("special_clicks")
Counter operations:
Counter operations are increment, decrement and count:
# Increment a counter by 1
Metrex.Counter.increment("pageviews")
# Increment a counter by x(number)
Metrex.Counter.increment("pageviews", 5)
# Decrement a counter by 1
Metrex.Counter.decrement("pageviews")
# Decrement a counter by x(number)
Metrex.Counter.decrement("pageviews", 3)
# Get current counter
Metrex.Counter.count("pageviews")
"""
use GenServer
@count "count"
@name "name"
def init(val) do
Process.flag(:trap_exit, true)
hooks = Application.get_env(:metrex, :hooks)
{_, metric} = List.keyfind(val, @name, 0)
{:ok, [{@count, hooks.counter_init(metric)}] ++ val}
end
@doc """
Start a new `Counter` metric
"""
def start_link(metric) do
GenServer.start_link(__MODULE__, [{@name, metric}],
name: process_name(metric))
end
@doc """
Increment metric by given val
"""
def increment(metric, val \\ 1),
do: update(metric, val)
@doc """
Decrement metric by given val
"""
def decrement(metric, val \\ 1),
do: update(metric, -val)
@doc """
Reset counter
"""
def remove(metric, _),
do: reset(metric)
@doc """
Reset counter
"""
def reset(metric),
do: metric |> process_name |> GenServer.cast({:reset})
@doc """
Display current counter at given time
"""
def count(metric),
do: metric |> process_name |> GenServer.call({:count})
## Private
defp update(metric, val),
do: metric |> process_name |> GenServer.cast({:update, val})
defp process_name(metric),
do: String.to_atom("counter." <> metric)
## Private API
@doc false
def handle_call({:count}, _from, state) do
{_, count_val} = List.keyfind(state, @count, 0) || {@count, 0}
{:reply, count_val, state}
end
@doc false
def handle_cast({:update, val}, state) do
{_, count_val} = List.keyfind(state, @count, 0)
{:noreply, List.keyreplace(state, @count, 0, {@count, count_val + val})}
end
@doc false
def handle_cast({:reset}, state),
do: {:noreply, [{@count, 0}, List.keyfind(state, @name, 0)]}
@doc false
def handle_info({:EXIT, _pid, reason}, state) do
{:stop, reason, state}
end
@doc false
def terminate(reason, state) do
{_, metric} = List.keyfind(state, @name, 0)
{_, val} = List.keyfind(state, @count, 0)
hooks = Application.get_env(:metrex, :hooks)
hooks.counter_exit(reason, metric, val)
:ok
end
end