Added grouped/tagged metrics feature
diff --git a/README.md b/README.md
index 6d60521..25f2a0b 100644
--- a/README.md
+++ b/README.md
@@ -141,6 +141,23 @@
> folsom_metrics:new_meter_reader(Name).
> folsom_metrics:notify({Name, Value}).
+##### Metrics groups/tags
+
+Certain users might want to group and query metrics monitoring a common task. In order to do so, they can
+tag metrics:
+
+ > folsom_metrics:tag_metric(Name, Tag).
+
+and query a list of tuples `[{Name, Value}]` of all metrics with a given tag:
+
+ > folsom_metrics:get_metrics_value(Tag).
+
+If only a certain type of metrics from a given group is desired, one can specify so:
+
+ > folsom_metrics:get_metrics_value(Tag, Type).
+
+where Type is one of `counter`, `gauge`, `histogram`, `history`, `meter`, `meter_reader`, `duration` or `spiral`.
+
##### Erlang VM
folsom also produces Erlang VM statistics.
diff --git a/src/folsom_ets.erl b/src/folsom_ets.erl
index 2e6eb5e..de3b9e5 100644
--- a/src/folsom_ets.erl
+++ b/src/folsom_ets.erl
@@ -29,6 +29,7 @@
add_handler/3,
add_handler/4,
add_handler/5,
+ tag_handler/2,
delete_handler/1,
handler_exists/1,
notify/1,
@@ -39,11 +40,13 @@
get_handlers_info/0,
get_info/1,
get_values/1,
- get_history_values/2
+ get_history_values/2,
+ get_group_values/1,
+ get_group_values/2
]).
-record(metric, {
- tags = [],
+ tags = sets:new(),
type,
history_size
}).
@@ -66,6 +69,14 @@
add_handler(Type, Name, SampleType, SampleSize, Alpha) ->
maybe_add_handler(Type, Name, SampleType, SampleSize, Alpha, handler_exists(Name)).
+tag_handler(Name, Tag) ->
+ case handler_exists(Name) of
+ true ->
+ add_tag(Name, Tag);
+ false ->
+ {error, Name, nonexistent_metric}
+ end.
+
delete_handler(Name) ->
{_, Info} = get_info(Name),
ok = delete_metric(Name, proplists:get_value(type, Info)).
@@ -148,6 +159,12 @@
get_history_values(Name, Count) ->
folsom_metrics_history:get_events(Name, Count).
+get_group_values(Tag) ->
+ [{Name, get_values(Name)} || Name <- get_handlers(), has_tag(Name, Tag)].
+
+get_group_values(Tag, Type) ->
+ [{Name, get_values(Name)} || Name <- get_handlers(), has_tag(Name, Tag), has_type(Name, Type)].
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
@@ -228,6 +245,22 @@
maybe_add_handler(_, Name, _, _, _, true) ->
{error, Name, metric_already_exists}.
+add_tag(Name, Tag) ->
+ OldMetric = ets:lookup_element(?FOLSOM_TABLE, Name, 2),
+ NewMetric = OldMetric#metric{tags=sets:add_element(Tag, get_tags(Name))},
+ true = ets:update_element(?FOLSOM_TABLE, Name, {2, NewMetric}),
+ ok.
+
+get_tags(Name) ->
+ Metric = ets:lookup_element(?FOLSOM_TABLE, Name, 2),
+ Metric#metric.tags.
+
+has_tag(Name, Tag) ->
+ sets:is_element(Tag, get_tags(Name)).
+
+has_type(Name, Type) ->
+ {Name, [{type, Type}]} =:= get_info(Name).
+
delete_metric(Name, history) ->
History = folsom_metrics_history:get_value(Name),
ok = delete_history(Name, History),
diff --git a/src/folsom_metrics.erl b/src/folsom_metrics.erl
index 7ab858f..73565cb 100644
--- a/src/folsom_metrics.erl
+++ b/src/folsom_metrics.erl
@@ -41,6 +41,7 @@
new_duration/4,
new_spiral/1,
delete_metric/1,
+ tag_metric/2,
notify/1,
notify/2,
notify/3,
@@ -51,6 +52,8 @@
get_metrics/0,
metric_exists/1,
get_metrics_info/0,
+ get_metrics_value/1,
+ get_metrics_value/2,
get_metric_info/1,
get_metric_value/1,
get_histogram_statistics/1,
@@ -112,6 +115,9 @@
new_spiral(Name) ->
folsom_ets:add_handler(spiral, Name).
+tag_metric(Name, Tag) ->
+ folsom_ets:tag_handler(Name, Tag).
+
delete_metric(Name) ->
folsom_ets:delete_handler(Name).
@@ -145,6 +151,12 @@
get_metrics_info() ->
folsom_ets:get_handlers_info().
+get_metrics_value(Tag) ->
+ folsom_ets:get_group_values(Tag).
+
+get_metrics_value(Tag, Type) ->
+ folsom_ets:get_group_values(Tag, Type).
+
get_metric_info(Name) ->
[folsom_ets:get_info(Name)].
diff --git a/test/folsom_erlang_checks.erl b/test/folsom_erlang_checks.erl
index 6eab9bc..e0c0cfd 100644
--- a/test/folsom_erlang_checks.erl
+++ b/test/folsom_erlang_checks.erl
@@ -29,7 +29,9 @@
-export([
create_metrics/0,
populate_metrics/0,
+ tag_metrics/0,
check_metrics/0,
+ check_group_metrics/0,
delete_metrics/0,
vm_metrics/0,
counter_metric/2,
@@ -87,6 +89,15 @@
?debugFmt("~n~nmetrics: ~p~n", [folsom_metrics:get_metrics()]).
+tag_metrics() ->
+ Group = "mygroup",
+ ok = folsom_metrics:tag_metric(counter, Group),
+ ok = folsom_metrics:tag_metric(counter2, Group),
+ ok = folsom_metrics:tag_metric(<<"gauge">>, Group),
+ ok = folsom_metrics:tag_metric(meter, Group),
+ ok = folsom_metrics:tag_metric(spiral, Group),
+ ?debugFmt("~n~ntagged metrics: ~p, ~p, ~p, ~p and ~p in group ~p~n", [counter,counter2,<<"gauge">>,meter,spiral,Group]).
+
populate_metrics() ->
ok = folsom_metrics:notify({counter, {inc, 1}}),
ok = folsom_metrics:notify({counter, {dec, 1}}),
@@ -229,6 +240,32 @@
%% check spiral
[{count, 100}, {one, 100}] = folsom_metrics:get_metric_value(spiral).
+check_group_metrics() ->
+ Metrics = get_metrics_value("mygroup"),
+ 5 = length(Metrics),
+ {counter, 0} = lists:keyfind(counter,1,Metrics),
+ {counter2, 0} = lists:keyfind(counter2,1,Metrics),
+ {<<"gauge">>, 2} = lists:keyfind(<<"gauge">>,1,Metrics),
+
+ {meter, Meter} = lists:keyfind(meter,1,Metrics),
+ ok = case proplists:get_value(one, Meter) of
+ Value when Value > 1 ->
+ ok;
+ _ ->
+ error
+ end,
+ ok = case proplists:get_value(day, Meter) of
+ Value1 when Value1 > 0.005 ->
+ ok;
+ _ ->
+ error
+ end,
+
+ {spiral, [{count, 100}, {one, 100}]} = lists:keyfind(spiral,1,Metrics),
+
+ Counters = get_metrics_value("mygroup",counter),
+ {counter, 0} = lists:keyfind(counter,1,Counters),
+ {counter2, 0} = lists:keyfind(counter2,1,Counters).
delete_metrics() ->
17 = length(ets:tab2list(?FOLSOM_TABLE)),
diff --git a/test/folsom_tests.erl b/test/folsom_tests.erl
index 04f2d94..389c3f9 100644
--- a/test/folsom_tests.erl
+++ b/test/folsom_tests.erl
@@ -32,6 +32,8 @@
fun (_) -> folsom:stop() end,
[{"creating metrics",
fun folsom_erlang_checks:create_metrics/0},
+ {"tagging metrics",
+ fun folsom_erlang_checks:tag_metrics/0},
{"populating metrics",
{timeout, 30, fun folsom_erlang_checks:populate_metrics/0}},
{"checking metrics",
@@ -40,6 +42,8 @@
fun () ->
folsom_erlang_checks:counter_metric(10000, testcounter)
end},
+ {"checking group metrics",
+ fun folsom_erlang_checks:check_group_metrics/0},
{"checking erlang vm metrics",
fun folsom_erlang_checks:vm_metrics/0},
{"deleting metrics",