Merge pull request #51 from AlexandreBeaulne/groupedmetrics
Added grouped metrics feature
diff --git a/README.md b/README.md
index 6d60521..93a522c 100644
--- a/README.md
+++ b/README.md
@@ -141,6 +141,27 @@
> 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 untag metrics:
+
+ > folsom_metrics:untag_metric(Name, Tag).
+
+Users can 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..edd2f36 100644
--- a/src/folsom_ets.erl
+++ b/src/folsom_ets.erl
@@ -29,6 +29,8 @@
add_handler/3,
add_handler/4,
add_handler/5,
+ tag_handler/2,
+ untag_handler/2,
delete_handler/1,
handler_exists/1,
notify/1,
@@ -39,11 +41,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 +70,22 @@
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.
+
+untag_handler(Name, Tag) ->
+ case handler_exists(Name) of
+ true ->
+ rm_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 +168,13 @@
get_history_values(Name, Count) ->
folsom_metrics_history:get_events(Name, Count).
+get_group_values(Tag) ->
+ folsom_ets:get_group_values(Tag, '_').
+
+get_group_values(Tag, Type) ->
+ Metrics = ets:match(?FOLSOM_TABLE, {'$1', {metric, '$2', Type, '_'}}),
+ [{Name, get_values(Name)} || [Name, Tags] <- Metrics, sets:is_element(Tag, Tags)].
+
%%%===================================================================
%%% Internal functions
%%%===================================================================
@@ -228,6 +255,16 @@
maybe_add_handler(_, Name, _, _, _, true) ->
{error, Name, metric_already_exists}.
+add_tag(Name, Tag) ->
+ M = #metric{tags=Tags} = ets:lookup_element(?FOLSOM_TABLE, Name, 2),
+ true = ets:update_element(?FOLSOM_TABLE, Name, {2, M#metric{tags=sets:add_element(Tag, Tags)}}),
+ ok.
+
+rm_tag(Name, Tag) ->
+ M = #metric{tags=Tags} = ets:lookup_element(?FOLSOM_TABLE, Name, 2),
+ true = ets:update_element(?FOLSOM_TABLE, Name, {2, M#metric{tags=sets:del_element(Tag, Tags)}}),
+ ok.
+
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..a6245c0 100644
--- a/src/folsom_metrics.erl
+++ b/src/folsom_metrics.erl
@@ -41,6 +41,8 @@
new_duration/4,
new_spiral/1,
delete_metric/1,
+ tag_metric/2,
+ untag_metric/2,
notify/1,
notify/2,
notify/3,
@@ -51,6 +53,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 +116,12 @@
new_spiral(Name) ->
folsom_ets:add_handler(spiral, Name).
+tag_metric(Name, Tag) ->
+ folsom_ets:tag_handler(Name, Tag).
+
+untag_metric(Name, Tag) ->
+ folsom_ets:untag_handler(Name, Tag).
+
delete_metric(Name) ->
folsom_ets:delete_handler(Name).
@@ -145,6 +155,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..abfe913 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,42 @@
%% check spiral
[{count, 100}, {one, 100}] = folsom_metrics:get_metric_value(spiral).
+check_group_metrics() ->
+ Group = "mygroup",
+ Metrics = folsom_metrics:get_metrics_value(Group),
+ 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 = folsom_metrics:get_metrics_value(Group,counter),
+ {counter, 0} = lists:keyfind(counter,1,Counters),
+ {counter2, 0} = lists:keyfind(counter2,1,Counters),
+
+ ok = folsom_metrics:untag_metric(counter2, Group),
+ ok = folsom_metrics:untag_metric(<<"gauge">>, Group),
+ ok = folsom_metrics:untag_metric(meter, Group),
+ ok = folsom_metrics:untag_metric(spiral, Group),
+ ?debugFmt("~n~nuntagged metrics: ~p, ~p, ~p and ~p in group ~p~n", [counter2,<<"gauge">>,meter,spiral,Group]),
+ RemainingMetrics = folsom_metrics:get_metrics_value(Group),
+ 1 = length(RemainingMetrics),
+ {counter, 0} = lists:keyfind(counter,1,Metrics).
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",