diff options
Diffstat (limited to 'lib/megaco/src/engine/megaco_stats.erl')
-rw-r--r-- | lib/megaco/src/engine/megaco_stats.erl | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/lib/megaco/src/engine/megaco_stats.erl b/lib/megaco/src/engine/megaco_stats.erl new file mode 100644 index 0000000000..af180fb9d6 --- /dev/null +++ b/lib/megaco/src/engine/megaco_stats.erl @@ -0,0 +1,207 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2002-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%----------------------------------------------------------------- +%% Purpose: Functions for handling statistic counters +%%----------------------------------------------------------------- +-module(megaco_stats). + + +%%----------------------------------------------------------------- +%% Application internal exports +%%----------------------------------------------------------------- + +-export([init/1, init/2]). + +-export([inc/2, inc/3, inc/4]). + +-export([get_stats/1, get_stats/2, get_stats/3, + reset_stats/1, reset_stats/2]). + +%% -include_lib("megaco/include/megaco.hrl"). + + +%%----------------------------------------------------------------- +%% Func: init/1, init/2 +%% Description: Initiate the statistics. Creates the stats table +%% and the global counters. +%%----------------------------------------------------------------- +init(Name) -> + init(Name, []). + +init(Name, GlobalCounters) -> + ets:new(Name, [public, named_table, {keypos, 1}]), + ets:insert(Name, {global_counters, GlobalCounters}), + create_global_snmp_counters(Name, GlobalCounters). + + +create_global_snmp_counters(_Name, []) -> + ok; +create_global_snmp_counters(Name, [Counter|Counters]) -> + ets:insert(Name, {Counter, 0}), + create_global_snmp_counters(Name, Counters). + + +%%----------------------------------------------------------------- +%% Func: inc/2, inc/3, inc/4 +%% Description: Increment counter value. Default increment is one +%% (1). +%%----------------------------------------------------------------- +inc(Tab, GlobalCnt) when is_atom(GlobalCnt) -> + inc(Tab, GlobalCnt, 1). + +inc(Tab, GlobalCnt, Incr) + when is_atom(GlobalCnt) andalso (is_integer(Incr) andalso (Incr > 0)) -> + do_inc(Tab, GlobalCnt, Incr); +inc(Tab, Handle, Cnt) + when is_atom(Cnt) -> + inc(Tab, Handle, Cnt, 1). + +inc(Tab, Handle, Cnt, Incr) + when is_atom(Cnt) andalso (is_integer(Incr) andalso (Incr > 0)) -> + Key = {Handle, Cnt}, + do_inc(Tab, Key, Incr). + +do_inc(Tab, Key, Incr) -> + case (catch ets:update_counter(Tab, Key, Incr)) of + {'EXIT', {badarg, _Reason}} -> + ets:insert(Tab, {Key, Incr}), + Incr; + Val -> + Val + end. + + +%%----------------------------------------------------------------- +%% Func: get_stats/1, get_stats/2, get_stats/3 +%% Description: Get statistics +%%----------------------------------------------------------------- +get_stats(Ets) -> + Handles = get_handles_and_global_counters(Ets), + (catch do_get_stats(Ets, Handles, [])). + +do_get_stats(_Ets, [], Acc) -> + {ok, lists:reverse(Acc)}; +do_get_stats(Ets, [Handle|Handles], Acc) -> + case get_stats(Ets, Handle) of + {ok, Stats} -> + do_get_stats(Ets, Handles, [{Handle, Stats}|Acc]); + {error, Reason} -> + throw({error, Reason}) + end. + +get_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) -> + case (catch ets:lookup(Ets, GlobalCounter)) of + [{GlobalCounter, Val}] -> + {ok, Val}; + [] -> + {error, {no_such_counter, GlobalCounter}} + end; + +get_stats(Ets, Handle) -> + case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of + CounterVals when is_list(CounterVals) -> + {ok, [{Counter, Val} || [Counter, Val] <- CounterVals]}; + Other -> + {error, {unexpected_result, Other}} + end. + + +get_stats(Ets, Handle, Counter) when is_atom(Counter) -> + Key = {Handle, Counter}, + case (catch ets:lookup(Ets, Key)) of + [{Key, Val}] -> + {ok, Val}; + _ -> + {error, {undefined_counter, Counter}} + end. + + +%%----------------------------------------------------------------- +%% Funcs: reset_stats/1, reset_stats/2 +%% Description: Reset statistics +%%----------------------------------------------------------------- +reset_stats(Ets) -> + Handles = get_handles_and_global_counters(Ets), + (catch do_reset_stats(Ets, Handles, [])). + +do_reset_stats(_Ets, [], Acc) -> + {ok, lists:reverse(Acc)}; +do_reset_stats(Ets, [Handle|Handles], Acc) -> + case reset_stats(Ets, Handle) of + {ok, OldStats} -> + do_reset_stats(Ets, Handles, [{Handle, OldStats}|Acc]); + {error, Reason} -> + throw({error, Reason}) + end. + +reset_stats(Ets, GlobalCounter) when is_atom(GlobalCounter) -> + %% First get the current value of the counter + case (catch ets:lookup(Ets, GlobalCounter)) of + [{GlobalCounter, Val}] -> + ets:insert(Ets, {GlobalCounter, 0}), + {ok, Val}; + [] -> %% Oooups + {error, {no_such_counter, GlobalCounter}} + end; + +reset_stats(Ets, Handle) -> + case (catch ets:match(Ets, {{Handle, '$1'},'$2'})) of + CounterVals when is_list(CounterVals) -> + CVs = [{Counter, Val} || [Counter, Val] <- CounterVals], + reset_stats(Ets, Handle, CVs), + {ok, CVs}; + Other -> + {error, {unexpected_result, Other}} + end. + +reset_stats(_Ets, _Handle, []) -> + ok; +reset_stats(Ets, Handle, [{Counter, _}|CVs]) -> + ets:insert(Ets, {{Handle, Counter}, 0}), + reset_stats(Ets, Handle, CVs). + + + +%%----------------------------------------------------------------- +%% Internal functions +%%----------------------------------------------------------------- +get_handles_and_global_counters(Ets) -> + GlobalCounters = + case ets:lookup(Ets, global_counters) of + [{global_counters, GC}] -> + GC; + [] -> + [] + end, + L1 = ets:match(Ets, {{'$1', '_'}, '_'}), + GlobalCounters ++ + lists:sort([Handle || [Handle] <- remove_duplicates(L1, [])]). + +remove_duplicates([], L) -> + L; +remove_duplicates([H|T], L) -> + case lists:member(H,T) of + true -> + remove_duplicates(T, L); + false -> + remove_duplicates(T, [H|L]) + end. + |