Permalink
Browse files

Add a 'spiral' one minute sliding window count/meter

Sorry about the name.
  • Loading branch information...
1 parent 3027584 commit 270dfb2817daf19b81672c0c4df1bfa0ef505864 @russelldb russelldb committed Jul 5, 2012
Showing with 125 additions and 5 deletions.
  1. +9 −0 include/folsom.hrl
  2. +20 −0 src/folsom_ets.erl
  3. +4 −0 src/folsom_metrics.erl
  4. +74 −0 src/folsom_metrics_spiral.erl
  5. +2 −1 src/folsom_sup.erl
  6. +16 −4 test/folsom_erlang_checks.erl
View
@@ -6,6 +6,7 @@
-define(METER_READER_TABLE, folsom_meter_readers).
-define(HISTORY_TABLE, folsom_histories).
-define(DURATION_TABLE, folsom_durations).
+-define(SPIRAL_TABLE, folsom_spirals).
-define(DEFAULT_LIMIT, 5).
-define(DEFAULT_SIZE, 1028). % mimic codahale's metrics
@@ -14,6 +15,14 @@
-define(DEFAULT_INTERVAL, 5000).
-define(DEFAULT_SAMPLE_TYPE, uniform).
+-record(spiral, {
+ tid = folsom_metrics_histogram_ets:new(folsom_spiral,
+ [ordered_set,
+ {write_concurrency, true},
+ public]),
+ server
+ }).
+
-record(slide, {
window = ?DEFAULT_SLIDING_WINDOW,
reservoir = folsom_metrics_histogram_ets:new(folsom_slide,
View
@@ -140,6 +140,8 @@ get_values(Name, meter_reader) ->
folsom_metrics_meter_reader:get_values(Name);
get_values(Name, duration) ->
folsom_metrics_duration:get_values(Name);
+get_values(Name, spiral) ->
+ folsom_metrics_spiral:get_values(Name);
get_values(_, Type) ->
{error, Type, unsupported_metric_type}.
@@ -181,6 +183,10 @@ maybe_add_handler(meter_reader, Name, false) ->
true = folsom_metrics_meter_reader:new(Name),
true = ets:insert(?FOLSOM_TABLE, {Name, #metric{type = meter_reader}}),
ok;
+maybe_add_handler(spiral, Name, false) ->
+ true = folsom_metrics_spiral:new(Name),
+ true = ets:insert(?FOLSOM_TABLE, {Name, #metric{type = spiral}}),
+ ok;
maybe_add_handler(Type, _, false) ->
{error, Type, unsupported_metric_type};
maybe_add_handler(_, Name, true) ->
@@ -251,6 +257,13 @@ delete_metric(Name, meter) ->
delete_metric(Name, meter_reader) ->
true = ets:delete(?METER_READER_TABLE, Name),
true = ets:delete(?FOLSOM_TABLE, Name),
+ ok;
+delete_metric(Name, spiral) ->
+ #spiral{tid=Tid, server=Pid} = folsom_metrics_spiral:get_value(Name),
+ folsom_sample_slide_server:stop(Pid),
+ true = ets:delete(Tid),
+ ets:delete(?SPIRAL_TABLE, Name),
+ ets:delete(?FOLSOM_TABLE, Name),
ok.
delete_histogram(Name, #histogram{type = uniform, sample = #uniform{reservoir = Reservoir}}) ->
@@ -344,6 +357,13 @@ notify(Name, Value, duration, false) ->
add_handler(duration, Name),
folsom_metrics_duration:update(Name, Value),
ok;
+notify(Name, Value, spiral, true) ->
+ folsom_metrics_spiral:update(Name, Value),
+ ok;
+notify(Name, Value, spiral, false) ->
+ add_handler(spiral, Name),
+ folsom_metrics_spiral:update(Name, Value),
+ ok;
notify(_, _, Type, _) ->
{error, Type, unsupported_metric_type}.
View
@@ -39,6 +39,7 @@
new_duration/2,
new_duration/3,
new_duration/4,
+ new_spiral/1,
delete_metric/1,
notify/1,
notify/2,
@@ -103,6 +104,9 @@ new_duration(Name, SampleType, SampleSize) ->
new_duration(Name, SampleType, SampleSize, Alpha) ->
folsom_ets:add_handler(duration, Name, SampleType, SampleSize, Alpha).
+new_spiral(Name) ->
+ folsom_ets:add_handler(spiral, Name).
+
delete_metric(Name) ->
folsom_ets:delete_handler(Name).
@@ -0,0 +1,74 @@
+%%%
+%%% Copyright 2012, Basho Technologies, Inc. All Rights Reserved.
+%%%
+%%% Licensed under the Apache License, Version 2.0 (the "License");
+%%% you may not use this file except in compliance with the License.
+%%% You may obtain a copy of the License at
+%%%
+%%% http://www.apache.org/licenses/LICENSE-2.0
+%%%
+%%% Unless required by applicable law or agreed to in writing, software
+%%% distributed under the License is distributed on an "AS IS" BASIS,
+%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%%% See the License for the specific language governing permissions and
+%%% limitations under the License.
+%%%
+
+
+%%%-------------------------------------------------------------------
+%%% File: folsom_metrics_spiral.erl
+%%% @author Russell Brown <russelldb@basho.com>
+%%% @doc A total count, and sliding window count of events over the last
+%%% minute.
+%%% @end
+%%%------------------------------------------------------------------
+
+-module(folsom_metrics_spiral).
+
+-export([new/1,
+ update/2,
+ trim/2,
+ get_value/1,
+ get_values/1
+ ]).
+
+%% size of the window in seconds
+-define(WINDOW, 60).
+
+-include("folsom.hrl").
+
+new(Name) ->
+ Spiral = #spiral{},
+ Pid = folsom_sample_slide_sup:start_slide_server(?MODULE,
+ Spiral#spiral.tid,
+ ?WINDOW),
+ ets:insert_new(Spiral#spiral.tid, {count, 0}),
+ ets:insert(?SPIRAL_TABLE, {Name, Spiral#spiral{server=Pid}}).
+
+update(Name, Value) ->
+ #spiral{tid=Tid} = get_value(Name),
+ Moment = folsom_utils:now_epoch(),
+ ets:insert_new(Tid, {Moment, 0}),
+ ets:update_counter(Tid, Moment, Value),
+ ets:update_counter(Tid, count, Value).
+
+get_value(Name) ->
+ [{Name, Spiral}] = ets:lookup(?SPIRAL_TABLE, Name),
+ Spiral.
+
+trim(Tid, _Window) ->
+ Oldest = oldest(),
+ ets:select_delete(Tid, [{{'$1','_'}, [{is_integer, '$1'}, {'<', '$1', Oldest}], ['true']}]).
+
+get_values(Name) ->
+ Oldest = oldest(),
+ #spiral{tid=Tid} = get_value(Name),
+ [{count, Count}] = ets:lookup(Tid, count),
+ One =lists:sum(ets:select(Tid, [{{'$1','$2'},[{is_integer, '$1'}, {'>=', '$1', Oldest}],['$2']}])),
+
+ [{count, Count}, {one, One}].
+
+oldest() ->
+ folsom_utils:now_epoch() - ?WINDOW.
+
+
View
@@ -107,7 +107,8 @@ create_tables() ->
{?METER_TABLE, [set, named_table, public, {write_concurrency, true}]},
{?METER_READER_TABLE, [set, named_table, public, {write_concurrency, true}]},
{?HISTORY_TABLE, [set, named_table, public, {write_concurrency, true}]},
- {?DURATION_TABLE, [ordered_set, named_table, public, {write_concurrency, true}]}
+ {?DURATION_TABLE, [ordered_set, named_table, public, {write_concurrency, true}]},
+ {?SPIRAL_TABLE, [set, named_table, public, {write_concurrency, true}]}
],
[maybe_create_table(ets:info(Name), Name, Opts) || {Name, Opts} <- Tables],
ok.
@@ -63,6 +63,8 @@ create_metrics() ->
ok = folsom_metrics:new_duration(duration),
+ ok = folsom_metrics:new_spiral(spiral),
+
?debugFmt("ensuring meter tick is registered with gen_server~n", []),
ok = ensure_meter_tick_exists(),
@@ -75,7 +77,10 @@ create_metrics() ->
{state, List} = folsom_meter_timer_server:dump(),
2 = length(List),
- 12 = length(folsom_metrics:get_metrics()),
+ %% check a server got started for the spiral metric
+ 1 = length(supervisor:which_children(folsom_sample_slide_sup)),
+
+ 13 = length(folsom_metrics:get_metrics()),
?debugFmt("~n~nmetrics: ~p~n", [folsom_metrics:get_metrics()]).
@@ -129,7 +134,9 @@ populate_metrics() ->
[ folsom_metrics:notify({meter_reader, Item}) || Item <- [1, 10, 100, 1000, 10000]],
% simulate an interval tick
- folsom_metrics_meter_reader:tick(meter_reader).
+ folsom_metrics_meter_reader:tick(meter_reader),
+
+ folsom_metrics:notify_existing_metric(spiral, 100, spiral).
check_metrics() ->
0 = folsom_metrics:get_metric_value(counter),
@@ -188,10 +195,14 @@ check_metrics() ->
%% check duration
Dur = folsom_metrics:get_metric_value(duration),
- duration_check(Dur).
+ duration_check(Dur),
+
+ %% check spiral
+ [{count, 100}, {one, 100}] = folsom_metrics:get_metric_value(spiral).
+
delete_metrics() ->
- 14= length(ets:tab2list(?FOLSOM_TABLE)),
+ 15 = length(ets:tab2list(?FOLSOM_TABLE)),
ok = folsom_metrics:delete_metric(counter),
ok = folsom_metrics:delete_metric(<<"gauge">>),
@@ -217,6 +228,7 @@ delete_metrics() ->
0 = length(ets:tab2list(?METER_READER_TABLE)),
ok = folsom_metrics:delete_metric(duration),
+ ok = folsom_metrics:delete_metric(spiral),
0 = length(ets:tab2list(?FOLSOM_TABLE)).

0 comments on commit 270dfb2

Please sign in to comment.