Permalink
Browse files

meter reader initial merge

  • Loading branch information...
1 parent a579c05 commit dc4bae7e300e947cb3f1a1233bd8dde1ebbdae06 @joewilliams joewilliams committed Apr 16, 2012
View
@@ -3,6 +3,7 @@
-define(GAUGE_TABLE, folsom_gauges).
-define(HISTOGRAM_TABLE, folsom_histograms).
-define(METER_TABLE, folsom_meters).
+-define(METER_READER_TABLE, folsom_meter_readers).
-define(HISTORY_TABLE, folsom_histories).
-define(DEFAULT_LIMIT, 5).
View
@@ -136,6 +136,8 @@ get_values(Name, history) ->
folsom_metrics_history:get_events(Name);
get_values(Name, meter) ->
folsom_metrics_meter:get_values(Name);
+get_values(Name, meter_reader) ->
+ folsom_metrics_meter_reader:get_values(Name);
get_values(_, Type) ->
{error, Type, unsupported_metric_type}.
@@ -163,10 +165,15 @@ maybe_add_handler(history, Name, false) ->
true = ets:insert(?FOLSOM_TABLE, {Name, #metric{type = history, history_size = ?DEFAULT_SIZE}}),
ok;
maybe_add_handler(meter, Name, false) ->
- ok = folsom_meter_timer_server:register(Name),
+ ok = folsom_meter_timer_server:register(Name, folsom_metrics_meter),
true = folsom_metrics_meter:new(Name),
true = ets:insert(?FOLSOM_TABLE, {Name, #metric{type = meter}}),
ok;
+maybe_add_handler(meter_reader, Name, false) ->
+ ok = folsom_meter_timer_server:register(Name, folsom_metrics_meter_reader),
+ true = folsom_metrics_meter_reader:new(Name),
+ true = ets:insert(?FOLSOM_TABLE, {Name, #metric{type = meter_reader}}),
+ ok;
maybe_add_handler(Type, _, false) ->
{error, Type, unsupported_metric_type};
maybe_add_handler(_, Name, true) ->
@@ -226,6 +233,10 @@ delete_metric(Name, gauge) ->
delete_metric(Name, meter) ->
true = ets:delete(?METER_TABLE, Name),
true = ets:delete(?FOLSOM_TABLE, Name),
+ ok;
+delete_metric(Name, meter_reader) ->
+ true = ets:delete(?METER_READER_TABLE, Name),
+ true = ets:delete(?FOLSOM_TABLE, Name),
ok.
delete_histogram(Name, #histogram{type = uniform, sample = #uniform{reservoir = Reservoir}}) ->
@@ -287,6 +298,13 @@ notify(Name, Value, meter, false) ->
add_handler(meter, Name),
folsom_metrics_meter:mark(Name, Value),
ok;
+notify(Name, Value, meter_reader, true) ->
+ folsom_metrics_meter_reader:mark(Name, Value),
+ ok;
+notify(Name, Value, meter_reader, false) ->
+ add_handler(meter, Name),
+ folsom_metrics_meter_reader:mark(Name, Value),
+ ok;
notify(_, _, Type, _) ->
{error, Type, unsupported_metric_type}.
@@ -28,7 +28,7 @@
-behaviour(gen_server).
%% API
--export([start_link/0, register/1, dump/0]).
+-export([start_link/0, register/2, dump/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -88,12 +88,12 @@ init([]) ->
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
-handle_call({register, Name}, _From, State) ->
+handle_call({register, Name, Module}, _From, State) ->
NewState = case proplists:is_defined(Name, State#state.registered_timers) of
true ->
State;
false ->
- {ok, Ref} = timer:apply_interval(?DEFAULT_INTERVAL, folsom_metrics_meter, tick, [Name]),
+ {ok, Ref} = timer:apply_interval(?DEFAULT_INTERVAL, Module, tick, [Name]),
NewList = [{Name, Ref} | State#state.registered_timers],
#state{registered_timers = NewList}
end,
@@ -156,8 +156,9 @@ code_change(_OldVsn, State, _Extra) ->
%%% Internal functions
%%%===================================================================
-register(Name) ->
- gen_server:call(?SERVER, {register, Name}).
+%% Name of the metric and name of the module used to tick said metric
+register(Name, Module) ->
+ gen_server:call(?SERVER, {register, Name, Module}).
dump() ->
gen_server:call(?SERVER, dump).
@@ -34,6 +34,7 @@
new_history/1,
new_history/2,
new_meter/1,
+ new_meter_reader/1,
delete_metric/1,
notify/1,
notify/2,
@@ -83,6 +84,9 @@ new_history(Name, SampleSize) ->
new_meter(Name) ->
folsom_ets:add_handler(meter, Name).
+new_meter_reader(Name) ->
+ folsom_ets:add_handler(meter_reader, Name).
+
delete_metric(Name) ->
folsom_ets:delete_handler(Name).
@@ -47,27 +47,51 @@ new(Name) ->
OneMin = folsom_ewma:one_minute_ewma(),
FiveMin = folsom_ewma:five_minute_ewma(),
FifteenMin = folsom_ewma:fifteen_minute_ewma(),
- ets:insert(?METER_TABLE,{Name, #meter{one = OneMin, five = FiveMin, fifteen = FifteenMin, start_time = folsom_utils:now_epoch_micro()}}).
+
+ ets:insert(?METER_TABLE,
+ {Name, #meter{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin,
+ start_time = folsom_utils:now_epoch_micro()}}).
tick(Name) ->
- #meter{one = OneMin, five = FiveMin, fifteen = FifteenMin} = Meter = get_value(Name),
+ #meter{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin} = Meter = get_value(Name),
+
OneMin1 = folsom_ewma:tick(OneMin),
FiveMin1 = folsom_ewma:tick(FiveMin),
FifteenMin1 = folsom_ewma:tick(FifteenMin),
- ets:insert(?METER_TABLE, {Name, Meter#meter{one = OneMin1, five = FiveMin1, fifteen = FifteenMin1}}).
+
+ ets:insert(?METER_TABLE,
+ {Name, Meter#meter{one = OneMin1,
+ five = FiveMin1,
+ fifteen = FifteenMin1}}).
mark(Name) ->
mark(Name, 1).
mark(Name, Value) ->
- #meter{count = Count, one = OneMin, five = FiveMin, fifteen = FifteenMin} = Meter = get_value(Name),
+ #meter{count = Count,
+ one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin} = Meter = get_value(Name),
+
OneMin1 = folsom_ewma:update(OneMin, Value),
FiveMin1 = folsom_ewma:update(FiveMin, Value),
FifteenMin1 = folsom_ewma:update(FifteenMin, Value),
- ets:insert(?METER_TABLE, {Name, Meter#meter{count = Count + Value, one = OneMin1, five = FiveMin1, fifteen = FifteenMin1}}).
+
+ ets:insert(?METER_TABLE, {Name, Meter#meter{count = Count + Value,
+ one = OneMin1,
+ five = FiveMin1,
+ fifteen = FifteenMin1}}).
get_values(Name) ->
- #meter{one = OneMin, five = FiveMin, fifteen = FifteenMin, count = Count} = Meter = get_value(Name),
+ #meter{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin,
+ count = Count} = Meter = get_value(Name),
+
L = [
{count, Count},
{one, get_rate(OneMin)},
@@ -76,10 +100,14 @@ get_values(Name) ->
{mean, get_mean_rate(Meter)},
{acceleration, get_acceleration(Name)}
],
+
[ {K,V} || {K,V} <- L, V /= undefined ].
get_acceleration(Name) ->
- #meter{one = OneMin, five = FiveMin, fifteen = FifteenMin} = get_value(Name),
+ #meter{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin} = get_value(Name),
+
[
{one_to_five, calc_acceleration(get_rate(OneMin), get_rate(FiveMin), 300)},
{five_to_fifteen, calc_acceleration(get_rate(FiveMin), get_rate(FifteenMin), 600)},
@@ -105,7 +133,8 @@ calc_mean_rate(Start, Count) ->
Count / Elapsed.
calc_acceleration(Rate1, Rate2, Interval) ->
- get_rate(Rate1, Rate2, Interval). % most current velocity minus previous velocity
+ % most current velocity minus previous velocity
+ get_rate(Rate1, Rate2, Interval).
get_rate(Value1, Value2, Interval) ->
Delta = Value1 - Value2,
@@ -0,0 +1,152 @@
+%%%
+%%% Copyright 2011, Boundary
+%%% Copyright 2011, Opscode
+%%%
+%%% 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_meter_reader.erl
+%%% @author Seth Falcon <seth@opscode.com>
+%%% @author joe williams <j@boundary.com>
+%%% @doc
+%%% @end
+%%%------------------------------------------------------------------
+
+-module(folsom_metrics_meter_reader).
+
+-export([new/1,
+ tick/1,
+ mark/1,
+ mark/2,
+ get_values/1,
+ get_acceleration/1
+ ]).
+
+
+-record(meter_reader, {
+ one,
+ five,
+ fifteen,
+ count = 0,
+ start_time,
+ last_count = unset
+ }).
+
+-include("folsom.hrl").
+
+new(Name) ->
+ OneMin = folsom_ewma:one_minute_ewma(),
+ FiveMin = folsom_ewma:five_minute_ewma(),
+ FifteenMin = folsom_ewma:fifteen_minute_ewma(),
+
+ ets:insert(?METER_READER_TABLE,
+ {Name, #meter_reader{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin,
+ start_time = folsom_utils:now_epoch_micro()}}).
+
+tick(Name) ->
+ #meter_reader{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin} = Meter = get_value(Name),
+
+ OneMin1 = folsom_ewma:tick(OneMin),
+ FiveMin1 = folsom_ewma:tick(FiveMin),
+ FifteenMin1 = folsom_ewma:tick(FifteenMin),
+
+ ets:insert(?METER_READER_TABLE,
+ {Name, Meter#meter_reader{one = OneMin1,
+ five = FiveMin1,
+ fifteen = FifteenMin1}}).
+
+mark(Name) ->
+ mark(Name, 1).
+
+mark(Name, Value) ->
+ % skip first reading to bootstrap last value
+ #meter_reader{count = Count,
+ last_count = LastCount,
+ one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin} = Meter = get_value(Name),
+
+ NewMeter = case LastCount of
+ unset ->
+ Meter#meter_reader{last_count = Value};
+ _ ->
+ Delta = Value - LastCount,
+ OneMin1 = folsom_ewma:update(OneMin, Delta),
+ FiveMin1 = folsom_ewma:update(FiveMin, Delta),
+ FifteenMin1 = folsom_ewma:update(FifteenMin, Delta),
+ Meter#meter_reader{count = Count + Delta,
+ last_count = Value,
+ one = OneMin1,
+ five = FiveMin1,
+ fifteen = FifteenMin1}
+ end,
+
+ ets:insert(?METER_READER_TABLE, {Name, NewMeter}).
+
+get_values(Name) ->
+ #meter_reader{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin} = Meter = get_value(Name),
+
+ L = [
+ {one, get_rate(OneMin)},
+ {five, get_rate(FiveMin)},
+ {fifteen, get_rate(FifteenMin)},
+ {mean, get_mean_rate(Meter)},
+ {acceleration, get_acceleration(Name)}
+ ],
+
+ [ {K,V} || {K,V} <- L, V /= undefined ].
+
+get_acceleration(Name) ->
+ #meter_reader{one = OneMin,
+ five = FiveMin,
+ fifteen = FifteenMin} = get_value(Name),
+
+ [
+ {one_to_five, calc_acceleration(get_rate(OneMin), get_rate(FiveMin), 300)},
+ {five_to_fifteen, calc_acceleration(get_rate(FiveMin), get_rate(FifteenMin), 600)},
+ {one_to_fifteen, calc_acceleration(get_rate(OneMin), get_rate(FifteenMin), 900)}
+ ].
+
+% internal functions
+
+get_rate(EWMA) ->
+ folsom_ewma:rate(EWMA).
+
+get_mean_rate(#meter_reader{count = Count, start_time = Start}) ->
+ calc_mean_rate(Start, Count).
+
+get_value(Name) ->
+ [{_, Value}] = ets:lookup(?METER_READER_TABLE, Name),
+ Value.
+
+calc_mean_rate(_, 0) ->
+ 0.0;
+calc_mean_rate(Start, Count) ->
+ Elapsed = folsom_utils:now_epoch_micro() - Start,
+ Count / Elapsed.
+
+calc_acceleration(Rate1, Rate2, Interval) ->
+ % most current velocity minus previous velocity
+ get_rate(Rate1, Rate2, Interval).
+
+get_rate(Value1, Value2, Interval) ->
+ Delta = Value1 - Value2,
+ Delta / Interval.
View
@@ -102,6 +102,7 @@ create_tables() ->
{?GAUGE_TABLE, [set, named_table, public, {write_concurrency, true}]},
{?HISTOGRAM_TABLE, [set, named_table, public, {write_concurrency, true}]},
{?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}]}
],
[maybe_create_table(ets:info(Name), Name, Opts) || {Name, Opts} <- Tables],
Oops, something went wrong.

0 comments on commit dc4bae7

Please sign in to comment.