1%%% 2%%% Copyright 2011, Boundary 3%%% Copyright 2011, Opscode 4%%% 5%%% Licensed under the Apache License, Version 2.0 (the "License"); 6%%% you may not use this file except in compliance with the License. 7%%% You may obtain a copy of the License at 8%%% 9%%% http://www.apache.org/licenses/LICENSE-2.0 10%%% 11%%% Unless required by applicable law or agreed to in writing, software 12%%% distributed under the License is distributed on an "AS IS" BASIS, 13%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14%%% See the License for the specific language governing permissions and 15%%% limitations under the License. 16%%% 17 18 19%%%------------------------------------------------------------------- 20%%% File: folsom_metrics_meter_reader.erl 21%%% @author Seth Falcon <seth@opscode.com> 22%%% @author joe williams <j@boundary.com> 23%%% @doc 24%%% @end 25%%%------------------------------------------------------------------ 26 27-module(folsom_metrics_meter_reader). 28 29-export([new/1, 30 tick/1, 31 mark/1, 32 mark/2, 33 get_values/1, 34 get_acceleration/1 35 ]). 36 37 38-record(meter_reader, { 39 one, 40 five, 41 fifteen, 42 count = 0, 43 start_time, 44 last_count = unset 45 }). 46 47-include("folsom.hrl"). 48 49new(Name) -> 50 OneMin = folsom_ewma:one_minute_ewma(), 51 FiveMin = folsom_ewma:five_minute_ewma(), 52 FifteenMin = folsom_ewma:fifteen_minute_ewma(), 53 54 ets:insert(?METER_READER_TABLE, 55 {Name, #meter_reader{one = OneMin, 56 five = FiveMin, 57 fifteen = FifteenMin, 58 start_time = folsom_utils:now_epoch_micro()}}). 59 60tick(Name) -> 61 #meter_reader{one = OneMin, 62 five = FiveMin, 63 fifteen = FifteenMin} = Meter = get_value(Name), 64 65 OneMin1 = folsom_ewma:tick(OneMin), 66 FiveMin1 = folsom_ewma:tick(FiveMin), 67 FifteenMin1 = folsom_ewma:tick(FifteenMin), 68 69 ets:insert(?METER_READER_TABLE, 70 {Name, Meter#meter_reader{one = OneMin1, 71 five = FiveMin1, 72 fifteen = FifteenMin1}}). 73 74mark(Name) -> 75 mark(Name, 1). 76 77mark(Name, Value) -> 78 % skip first reading to bootstrap last value 79 #meter_reader{count = Count, 80 last_count = LastCount, 81 one = OneMin, 82 five = FiveMin, 83 fifteen = FifteenMin} = Meter = get_value(Name), 84 85 NewMeter = case LastCount of 86 unset -> 87 Meter#meter_reader{last_count = Value}; 88 _ -> 89 Delta = Value - LastCount, 90 OneMin1 = folsom_ewma:update(OneMin, Delta), 91 FiveMin1 = folsom_ewma:update(FiveMin, Delta), 92 FifteenMin1 = folsom_ewma:update(FifteenMin, Delta), 93 Meter#meter_reader{count = Count + Delta, 94 last_count = Value, 95 one = OneMin1, 96 five = FiveMin1, 97 fifteen = FifteenMin1} 98 end, 99 100 ets:insert(?METER_READER_TABLE, {Name, NewMeter}). 101 102get_values(Name) -> 103 #meter_reader{one = OneMin, 104 five = FiveMin, 105 fifteen = FifteenMin} = Meter = get_value(Name), 106 107 L = [ 108 {one, get_rate(OneMin)}, 109 {five, get_rate(FiveMin)}, 110 {fifteen, get_rate(FifteenMin)}, 111 {mean, get_mean_rate(Meter)}, 112 {acceleration, get_acceleration(Name)} 113 ], 114 115 [ {K,V} || {K,V} <- L, V /= undefined ]. 116 117get_acceleration(Name) -> 118 #meter_reader{one = OneMin, 119 five = FiveMin, 120 fifteen = FifteenMin} = get_value(Name), 121 122 [ 123 {one_to_five, calc_acceleration(get_rate(OneMin), get_rate(FiveMin), 300)}, 124 {five_to_fifteen, calc_acceleration(get_rate(FiveMin), get_rate(FifteenMin), 600)}, 125 {one_to_fifteen, calc_acceleration(get_rate(OneMin), get_rate(FifteenMin), 900)} 126 ]. 127 128% internal functions 129 130get_rate(EWMA) -> 131 folsom_ewma:rate(EWMA). 132 133get_mean_rate(#meter_reader{count = Count, start_time = Start}) -> 134 calc_mean_rate(Start, Count). 135 136get_value(Name) -> 137 [{_, Value}] = ets:lookup(?METER_READER_TABLE, Name), 138 Value. 139 140calc_mean_rate(_, 0) -> 141 0.0; 142calc_mean_rate(Start, Count) -> 143 Elapsed = folsom_utils:now_epoch_micro() - Start, 144 Count / Elapsed. 145 146calc_acceleration(Rate1, Rate2, Interval) -> 147 % most current velocity minus previous velocity 148 get_rate(Rate1, Rate2, Interval). 149 150get_rate(Value1, Value2, Interval) -> 151 Delta = Value1 - Value2, 152 Delta / Interval. 153