1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2002-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21%% 22%%----------------------------------------------------------------- 23%% Purpose: Functions for handling statistic counters 24%%----------------------------------------------------------------- 25-module(megaco_stats). 26 27 28%%----------------------------------------------------------------- 29%% Application internal exports 30%%----------------------------------------------------------------- 31 32-export([init/1, init/2]). 33 34-export([inc/2, inc/3, inc/4]). 35 36-export([get_stats/1, get_stats/2, get_stats/3, 37 reset_stats/1, reset_stats/2]). 38 39%% -include_lib("megaco/include/megaco.hrl"). 40 41 42%%----------------------------------------------------------------- 43%% Func: init/1, init/2 44%% Description: Initiate the statistics. Creates the stats table 45%% and the global counters. 46%%----------------------------------------------------------------- 47init(Name) -> 48 init(Name, []). 49 50init(Name, GlobalCounters) -> 51 ets:new(Name, [public, named_table, {keypos, 1}]), 52 ets:insert(Name, {global_counters, GlobalCounters}), 53 create_global_snmp_counters(Name, GlobalCounters). 54 55 56create_global_snmp_counters(_Name, []) -> 57 ok; 58create_global_snmp_counters(Name, [Counter|Counters]) -> 59 ets:insert(Name, {Counter, 0}), 60 create_global_snmp_counters(Name, Counters). 61 62 63%%----------------------------------------------------------------- 64%% Func: inc/2, inc/3, inc/4 65%% Description: Increment counter value. Default increment is one 66%% (1). 67%%----------------------------------------------------------------- 68inc(Tab, GlobalCnt) when is_atom(GlobalCnt) -> 69 inc(Tab, GlobalCnt, 1). 70 71inc(Tab, GlobalCnt, Incr) 72 when is_atom(GlobalCnt) andalso (is_integer(Incr) andalso (Incr > 0)) -> 73 do_inc(Tab, GlobalCnt, Incr); 74inc(Tab, Handle, Cnt) 75 when is_atom(Cnt) -> 76 inc(Tab, Handle, Cnt, 1). 77 78inc(Tab, Handle, Cnt, Incr) 79 when is_atom(Cnt) andalso (is_integer(Incr) andalso (Incr > 0)) -> 80 Key = {Handle, Cnt}, 81 do_inc(Tab, Key, Incr). 82 83do_inc(Tab, Key, Incr) -> 84 case (catch ets:update_counter(Tab, Key, Incr)) of 85 {'EXIT', {badarg, _Reason}} -> 86 ets:insert(Tab, {Key, Incr}), 87 Incr; 88 Val -> 89 Val 90 end. 91 92 93%%----------------------------------------------------------------- 94%% Func: get_stats/1, get_stats/2, get_stats/3 95%% Description: Get statistics 96%%----------------------------------------------------------------- 97get_stats(Ets) -> 98 Handles = get_handles_and_global_counters(Ets), 99 (catch do_get_stats(Ets, Handles, [])). 100 101do_get_stats(_Ets, [], Acc) -> 102 {ok, lists:reverse(Acc)}; 103do_get_stats(Ets, [Handle|Handles], Acc) -> 104 case get_stats(Ets, Handle) of 105 {ok, Stats} -> 106 do_get_stats(Ets, Handles, [{Handle, Stats}|Acc]); 107 {error, Reason} -> 108 throw({error, Reason}) 109 end. 110 111get_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) -> 112 case (catch ets:lookup(Ets, GlobalCounter)) of 113 [{GlobalCounter, Val}] -> 114 {ok, Val}; 115 [] -> 116 {error, {no_such_counter, GlobalCounter}} 117 end; 118 119get_stats(Ets, Handle) -> 120 case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of 121 CounterVals when is_list(CounterVals) -> 122 {ok, [{Counter, Val} || [Counter, Val] <- CounterVals]}; 123 Other -> 124 {error, {unexpected_result, Other}} 125 end. 126 127 128get_stats(Ets, Handle, Counter) when is_atom(Counter) -> 129 Key = {Handle, Counter}, 130 case (catch ets:lookup(Ets, Key)) of 131 [{Key, Val}] -> 132 {ok, Val}; 133 _ -> 134 {error, {undefined_counter, Counter}} 135 end. 136 137 138%%----------------------------------------------------------------- 139%% Funcs: reset_stats/1, reset_stats/2 140%% Description: Reset statistics 141%%----------------------------------------------------------------- 142reset_stats(Ets) -> 143 Handles = get_handles_and_global_counters(Ets), 144 (catch do_reset_stats(Ets, Handles, [])). 145 146do_reset_stats(_Ets, [], Acc) -> 147 {ok, lists:reverse(Acc)}; 148do_reset_stats(Ets, [Handle|Handles], Acc) -> 149 case reset_stats(Ets, Handle) of 150 {ok, OldStats} -> 151 do_reset_stats(Ets, Handles, [{Handle, OldStats}|Acc]); 152 {error, Reason} -> 153 throw({error, Reason}) 154 end. 155 156reset_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) -> 157 %% First get the current value of the counter 158 case (catch ets:lookup(Ets, GlobalCounter)) of 159 [{GlobalCounter, Val}] -> 160 ets:insert(Ets, {GlobalCounter, 0}), 161 {ok, Val}; 162 [] -> %% Oooups 163 {error, {no_such_counter, GlobalCounter}} 164 end; 165 166reset_stats(Ets, Handle) -> 167 case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of 168 CounterVals when is_list(CounterVals) -> 169 CVs = [{Counter, Val} || [Counter, Val] <- CounterVals], 170 reset_stats(Ets, Handle, CVs), 171 {ok, CVs}; 172 Other -> 173 {error, {unexpected_result, Other}} 174 end. 175 176reset_stats(_Ets, _Handle, []) -> 177 ok; 178reset_stats(Ets, Handle, [{Counter, _}|CVs]) -> 179 ets:insert(Ets, {{Handle, Counter}, 0}), 180 reset_stats(Ets, Handle, CVs). 181 182 183 184%%----------------------------------------------------------------- 185%% Internal functions 186%%----------------------------------------------------------------- 187get_handles_and_global_counters(Ets) -> 188 GlobalCounters = 189 case ets:lookup(Ets, global_counters) of 190 [{global_counters, GC}] -> 191 GC; 192 [] -> 193 [] 194 end, 195 L1 = ets:match(Ets, {{'$1', '_'}, '_'}), 196 GlobalCounters ++ 197 lists:sort([Handle || [Handle] <- remove_duplicates(L1, [])]). 198 199remove_duplicates([], L) -> 200 L; 201remove_duplicates([H|T], L) -> 202 case lists:member(H,T) of 203 true -> 204 remove_duplicates(T, L); 205 false -> 206 remove_duplicates(T, [H|L]) 207 end. 208 209