meter reader initial merge
diff --git a/include/folsom.hrl b/include/folsom.hrl
index f1995f8..6715a67 100644
--- a/include/folsom.hrl
+++ b/include/folsom.hrl
@@ -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).
diff --git a/src/folsom_ets.erl b/src/folsom_ets.erl
index c42d93f..7c2e34f 100644
--- a/src/folsom_ets.erl
+++ b/src/folsom_ets.erl
@@ -136,6 +136,8 @@
     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 @@
     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, 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 @@
     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}.
 
diff --git a/src/folsom_meter_timer_server.erl b/src/folsom_meter_timer_server.erl
index 4538b38..5a38c07 100644
--- a/src/folsom_meter_timer_server.erl
+++ b/src/folsom_meter_timer_server.erl
@@ -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 @@
 %%                                   {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 @@
 %%% 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).
diff --git a/src/folsom_metrics.erl b/src/folsom_metrics.erl
index 4a7f238..9e30eae 100644
--- a/src/folsom_metrics.erl
+++ b/src/folsom_metrics.erl
@@ -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_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).
 
diff --git a/src/folsom_metrics_meter.erl b/src/folsom_metrics_meter.erl
index 5aa9ba0..5f8236b 100644
--- a/src/folsom_metrics_meter.erl
+++ b/src/folsom_metrics_meter.erl
@@ -47,27 +47,51 @@
     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 @@
          {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 @@
     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,
diff --git a/src/folsom_metrics_meter_reader.erl b/src/folsom_metrics_meter_reader.erl
new file mode 100644
index 0000000..50b15b9
--- /dev/null
+++ b/src/folsom_metrics_meter_reader.erl
@@ -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.
diff --git a/src/folsom_sup.erl b/src/folsom_sup.erl
index a7c0ba2..cd39d40 100644
--- a/src/folsom_sup.erl
+++ b/src/folsom_sup.erl
@@ -102,6 +102,7 @@
               {?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],
diff --git a/test/folsom_erlang_checks.erl b/test/folsom_erlang_checks.erl
index 55bf25b..352cdb3 100644
--- a/test/folsom_erlang_checks.erl
+++ b/test/folsom_erlang_checks.erl
@@ -57,19 +57,21 @@
     ok = folsom_metrics:new_history(<<"history">>),
     ok = folsom_metrics:new_meter(meter),
 
+    ok = folsom_metrics:new_meter_reader(meter_reader),
+
     ?debugFmt("ensuring meter tick is registered with gen_server~n", []),
-    ok = ensure_meter_tick_exists(meter),
+    ok = ensure_meter_tick_exists(),
 
     ?debugFmt("ensuring multiple timer registrations dont cause issues", []),
-    ok = folsom_meter_timer_server:register(meter),
-    ok = folsom_meter_timer_server:register(meter),
-    ok = folsom_meter_timer_server:register(meter),
+    ok = folsom_meter_timer_server:register(meter, folsom_metrics_meter),
+    ok = folsom_meter_timer_server:register(meter, folsom_metrics_meter),
+    ok = folsom_meter_timer_server:register(meter, folsom_metrics_meter),
 
     ?debugFmt("~p", [folsom_meter_timer_server:dump()]),
     {state, List} = folsom_meter_timer_server:dump(),
-    1 = length(List),
+    2 = length(List),
 
-    9 = length(folsom_metrics:get_metrics()),
+    10 = length(folsom_metrics:get_metrics()),
 
     ?debugFmt("~n~nmetrics: ~p~n", [folsom_metrics:get_metrics()]).
 
@@ -92,13 +94,28 @@
     {error, _, nonexistent_metric} = folsom_metrics:notify({historya, "5"}),
     ok = folsom_metrics:notify(historya, <<"binary">>, history),
 
+
+    ?debugFmt("testing meter ...", []),
+
     % simulate an interval tick
     folsom_metrics_meter:tick(meter),
 
-    [ok,ok,ok,ok,ok] = [ folsom_metrics:notify({meter, Item}) || Item <- [100, 100, 100, 100, 100]],
+    [ok,ok,ok,ok,ok] =
+        [ folsom_metrics:notify({meter, Item}) || Item <- [100, 100, 100, 100, 100]],
 
     % simulate an interval tick
-    folsom_metrics_meter:tick(meter).
+    folsom_metrics_meter:tick(meter),
+
+    ?debugFmt("testing meter reader ...", []),
+
+    % simulate an interval tick
+    folsom_metrics_meter_reader:tick(meter_reader),
+
+    [ok,ok,ok,ok,ok] =
+        [ folsom_metrics:notify({meter_reader, Item}) || Item <- [100, 100, 100, 100, 100]],
+
+    % simulate an interval tick
+    folsom_metrics_meter_reader:tick(meter_reader).
 
 check_metrics() ->
     0 = folsom_metrics:get_metric_value(counter),
@@ -125,14 +142,25 @@
     Meter = folsom_metrics:get_metric_value(meter),
     ?debugFmt("~p", [Meter]),
     ok = case proplists:get_value(one, Meter) of
-        Value when Value > 1 ->
-            ok;
-        _ ->
-            error
-    end.
+             Value when Value > 1 ->
+                 ok;
+             _ ->
+                 error
+         end,
+
+    ?debugFmt("checking meter reader~n", []),
+    MeterReader = folsom_metrics:get_metric_value(meter_reader),
+    ?debugFmt("~p", [MeterReader]),
+    ok = case proplists:get_value(one, MeterReader) of
+             Value1 when Value1 < 1 ->
+                 ok;
+             _ ->
+                 error
+         end.
+
 
 delete_metrics() ->
-    11 = length(ets:tab2list(?FOLSOM_TABLE)),
+    12 = length(ets:tab2list(?FOLSOM_TABLE)),
 
     ok = folsom_metrics:delete_metric(counter),
     ok = folsom_metrics:delete_metric(<<"gauge">>),
@@ -152,6 +180,10 @@
     ok = folsom_metrics:delete_metric(meter),
     0 = length(ets:tab2list(?METER_TABLE)),
 
+    1 = length(ets:tab2list(?METER_READER_TABLE)),
+    ok = folsom_metrics:delete_metric(meter_reader),
+    0 = length(ets:tab2list(?METER_READER_TABLE)),
+
     0 = length(ets:tab2list(?FOLSOM_TABLE)).
 
 vm_metrics() ->
@@ -180,8 +212,9 @@
 
     0 = Result.
 
-ensure_meter_tick_exists(Name) ->
-    {state, [{Name ,{interval, _}} | _]} = folsom_meter_timer_server:dump(),
+ensure_meter_tick_exists() ->
+    {state, State} = folsom_meter_timer_server:dump(),
+    2 = length(State),
     ok.
 
 %% internal function