Монитор памяти ETS Изменение конфигурации
Как я могу изменить valid_exchanges
в записи конфигурации во время работы? Мы получаем использование памяти от подчиненных узлов, и если оно превышает пороговое значение, мы отключаем обмены. Однако конфигурация по умолчанию не меняется даже после развертывания. Можем ли мы точно настроить пороги памяти во время выполнения, изменив конфигурацию? Я также хочу изменить список действительных бирж.
-module(ebid_mon).
-behaviour(gen_server).
-export([start_link/1]).
-export([
enable_exchanges/1,
disable_exchanges/1,
check_memory/0,
get_monitoring_config/0,
set_config/1
]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]).
-include("logger.hrl").
-record(state, {
length_timer = undefined,
config = undefined
}).
-record(ebid_settings, {name, value}).
-record(config,{
master_name = ['ebid@rtb0','ebid@dev6'],
count_threshold = 2,
time_threshold = 20000, % in Miliseconds
memory_threshold = 0.95,
disable_memory_threshold = 0.95,
enable_memory_threshold = 0.88,
inbetween_count_threshold = 4,
strategy = exchange,
emailto = "adx@adx.com",
emailfrom = "adx@adx.com",
valid_exchanges = [adx]
}).
-define(TIME_INTERVAL,timer:seconds(20)).
-define(LOG_INITIALS,"ebid_mon :").
get_monitoring_config() ->
get_default_config().
get_default_config() ->
[{count_threshold,2},{time_threshold,20000},{memory_threshold,0.95},{disable_memory_threshold,0.95},{enable_memory_threshold,0.88},{strategy,exchange},{valid_exchanges,[adx]},{to,"adx@adx.com"},{from,"adx@adx.com"},{master_name,['ebid@rtb0','ebid@dev6']},{inbetween_count_threshold,4}].
set_config(Config) ->
gen_server:call(?MODULE,{set_config,Config}).
start_link(Config) ->
gen_server:start_link({local,?MODULE},?MODULE,[Config],[]).
init([Data]) ->
Config = get_config(Data),
init_process(Config).
init_process(Config) ->
process_flag(trap_exit, true),
try
?log_error("~p Process table to store temporary data ~p",[?LOG_INITIALS, ets:new(?MODULE,[set,public,named_table])])
catch
Exception:Reason ->
?log_error("~p Failed to create the ets table ~p~p",[?LOG_INITIALS,Exception,Reason])
end,
LengthRef = erlang:start_timer(Config#config.time_threshold, self(), check_load),
{ok, #state{length_timer = LengthRef, config = Config}}.
handle_call({set_config,Data},_From,State) ->
case erlang:is_list(Data) of
true ->
%ebid_settings:set(<<"default_ebid_mon_config">>,Data),
Config = get_config(Data),
{reply,success,State#state{config = Config}};
false ->
?log_error("~p Bad configuration passed. Make sure its is a list of tuples",[?LOG_INITIALS]),
{reply,bad_config,State}
end;
handle_call(_Call, _From, State) ->
{reply, undefined, State}.
handle_cast(_Cast, State) ->
{noreply, State}.
handle_info({timeout,_Tref,check_load},State = #state{config = Config}) ->
?log_error("~p Config is ~p",[?LOG_INITIALS,Config]),
case lists:member(erlang:node(),Config#config.master_name) of
true ->
collect_slaves_memory_stats(Config);
false ->
?log_error("~p This node is not part of master node list. Which is ~p",[?LOG_INITIALS,Config#config.master_name])
end,
Tref = erlang:start_timer(Config#config.time_threshold,self(),check_load),
{noreply,State#state{length_timer = Tref}};
handle_info(_Info,State) ->
{noreply,State}.
code_change(_OldVsn,State,_Extra) ->
{ok,State}.
terminate(Reason,State) ->
error_logger:error_msg("~p Process terminating : ~p \t ~p",[?LOG_INITIALS,Reason,State]).
disable_exchanges(Valid_Exchanges) ->
?log_error("~p Disabling Exchanges",[?LOG_INITIALS]),
not lists:any(fun(Exchange) -> disable_exchange(Exchange) end,Valid_Exchanges).
disable_exchange(Exchange) ->
case mnesia:dirty_read(ebid_settings,to_binary(to_list(Exchange) ++ "_enabled")) of
[] ->
true;
[Record] ->
case Record#ebid_settings.value of
false ->
?log_error("~p Exchange ~p is already disabled",[?LOG_INITIALS,Exchange]),
true;
true ->
ebid_utils:set_exchange_enabled(Exchange,false),
false
end
end.
enable_exchanges(Valid_Exchanges) ->
?log_error("~p Enabling Exchanges ~p",[?LOG_INITIALS,Valid_Exchanges]),
not lists:any(fun(Exchange) -> enable_exchange(Exchange) end,Valid_Exchanges).
enable_exchange(Exchange) ->
?log_error("~p checking mnesia ebid_settings",[?LOG_INITIALS]),
case mnesia:dirty_read(ebid_settings,to_binary(to_list(Exchange) ++ "_enabled")) of
[] ->
true;
[Record] ->
case Record#ebid_settings.value of
true ->
?log_error("~p Exchange ~p is already enabled",[?LOG_INITIALS,Exchange]),
true;
false ->
ebid_utils:set_exchange_enabled(Exchange,true),
false
end
end.
%%%%%%%%%Private methods to module goes below this point and public goes above this point%%%%%%%%%%%%%%%%
collect_slaves_memory_stats(Config) ->
Alarm = check(ebid_master_alarm_for_exchanges),
?log_error("~p Alarm Status = ~p~n~n~n",[?LOG_INITIALS,Alarm]),
case Alarm of
undefined ->
?log_error("~p Taking No Alarm Action",[?LOG_INITIALS]),
take_action(no_alarm,Config);
_Alarm ->
%If alarm is set then insert in to ets and if N continous checks are set then
?log_error("~p Taking Alarm action",[?LOG_INITIALS]),
take_action(alarm,Config)
end.
take_action(alarm,Config) ->
?log_error("~p Active Alarm",[?LOG_INITIALS]),
?log_error("~p Node Details are:",[?LOG_INITIALS]),
MemoryUsageAlarmOnAllNodes = lists:any(fun(Node) ->
Memory = rpc:call(Node,ebid_mon,check_memory,[]),
?log_error("~p ~p \t ~p",[?LOG_INITIALS,Node,Memory]),
case Memory of
{badrpc,_} -> false;
_ -> Memory >= Config#config.disable_memory_threshold
end
end,
mnesia:system_info(running_db_nodes) -- [ebid@rtb0]),
case decision_for_exchange(ebid_master_key_to_disable_exchanges,Config#config.count_threshold) of
true ->
case MemoryUsageAlarmOnAllNodes of
true ->
?log_error("~p Disabling Exchanges ~p",[?LOG_INITIALS,Config#config.valid_exchanges]),
case disable_exchanges(Config#config.valid_exchanges) of
true ->
Data = create_email_data(),
send_email(disable,Data,Config);
false ->
?log_error("~p Exchanges are already disabled thus not sending and email",[?LOG_INITIALS])
end,
clear_ets_entry(ebid_master_key_to_enable_exchanges_for_middle),
clear_ets_entry(ebid_master_key_to_disable_exchanges);
false ->
clear_alarm(ebid_master_alarm_for_exchanges),
clear_ets_entry(ebid_master_key_to_disable_exchanges)
end;
false ->
?log_error("~p setting ets entry = ~p",[?LOG_INITIALS,make_ets_entry(ebid_master_key_to_disable_exchanges)])
end;
take_action(no_alarm,Config) ->
?log_error("~p No active Alarm",[?LOG_INITIALS]),
?log_error("~p Node Details are:",[?LOG_INITIALS]),
MemoryUsageAlarmOnAllNodes = lists:foldl(fun(Node,Acc) ->
Memory = rpc:call(Node,ebid_mon,check_memory,[]),
?log_error("~p ~p \t ~p",[?LOG_INITIALS,Node,Memory]),
Result = case Memory of
{badrpc,_} -> false;
_ -> if
Memory < Config#config.enable_memory_threshold ->
false;
Memory >= Config#config.disable_memory_threshold ->
true;
true ->
undefined
end
end,
Acc ++ [Result]
end,
[],
mnesia:system_info(running_db_nodes) -- [ebid@rtb0]),
case lists:member(undefined,MemoryUsageAlarmOnAllNodes) or lists:member(true,MemoryUsageAlarmOnAllNodes) of
true ->
case lists:member(undefined,MemoryUsageAlarmOnAllNodes) and not lists:member(true,MemoryUsageAlarmOnAllNodes) of
false ->
?log_error("~p One of the node is loaded. Thus setting the alarm",[?LOG_INITIALS]),
set_alarm(ebid_master_alarm_for_exchanges),
make_ets_entry(ebid_master_key_to_disable_exchanges);
true ->
?log_error("~p In middle of both threshold. Thus enable after 5 count",[?LOG_INITIALS]),
key_based_enable_decision(ebid_master_key_to_enable_exchanges_for_middle,Config#config.inbetween_count_threshold,Config)
end;
false ->
key_based_enable_decision(ebid_master_key_to_enable_exchanges,Config#config.count_threshold,Config)
end.
key_based_enable_decision(Key,Count,Config) ->
case decision_for_exchange(Key,Count) of
true ->
?log_error("~p None of the node is loaded. Thus enable exchanges",[?LOG_INITIALS]),
clear_alarm(ebid_master_alarm_for_exchanges),
clear_ets_entry(Key),
clear_ets_entry(ebid_master_key_to_enable_exchanges_for_middle),
case enable_exchanges(Config#config.valid_exchanges) of
true ->
Data = create_email_data(),
send_email(enable,Data,Config);
false ->
?log_error("~p Exchanges are already enabled thus not sending and email",[?LOG_INITIALS])
end;
false ->
?log_error("~p setting ets entry for key ~p = ~p",[?LOG_INITIALS,Key,make_ets_entry(Key)])
end.
create_email_data() ->
Data = lists:foldl(fun(Node,A) -> Memory = rpc:call(Node,ebid_mon,check_memory,[]), Result = case Memory of {badrpc,_} -> 0.0; _ -> Memory end, A ++ ["<tr><td>",erlang:atom_to_list(Node),"</td><td>",erlang:float_to_list(Result*100,[{decimals,5}])," %</td></tr>"] end,[], mnesia:system_info(running_db_nodes) -- [ebid@rtb0]),
?log_error("~p Email Data is : ~p",[?LOG_INITIALS,Data]),
lists:flatten(io_lib:format("<html><body><table> ~s </table></body></html>",[Data])).
clear_ets_entry(Key) ->
ets:delete(?MODULE,Key).
make_ets_entry(Key) ->
ets:update_counter(?MODULE,Key,1,{Key,0}).
decision_for_exchange(Key,ThresholdCount) ->
?log_error("~p checking the decision for ~p",[?LOG_INITIALS,Key]),
Decision = case ets:lookup(?MODULE,Key) of
[] ->
false;
DataObject ->
[{Key,Value}] = DataObject,
?log_error("~p Counter Value for key = ~p is ~p",[?LOG_INITIALS,Key,Value]),
Value >= ThresholdCount
end,
Decision.
check_memory() ->
SystemMemory = memsup:get_system_memory_data(),
((get_value(total_memory,SystemMemory) - (get_value(free_memory,SystemMemory) + get_value(cached_memory,SystemMemory) + get_value(buffered_memory,SystemMemory)))/get_value(total_memory,SystemMemory)).
check_alarm(Alarm) ->
case check(Alarm) of
undefined ->
false;
_Value ->
true
end.
check(Alarm) ->
proplists:get_value(Alarm,alarm_handler:get_alarms()).
set_alarm(Alarm) ->
case check_alarm(Alarm) of
true ->
already_set;
false ->
alarm_handler:set_alarm({Alarm,[]})
end.
clear_alarm(Alarm) ->
alarm_handler:clear_alarm(Alarm).
get_config(Data) ->
#config{
master_name = get_value(master_name,Data),
count_threshold = get_value(count_threshold,Data),
time_threshold = get_value(time_threshold,Data),
memory_threshold = get_value(memory_threshold,Data),
disable_memory_threshold = get_value(disable_memory_threshold,Data),
enable_memory_threshold = get_value(enable_memory_threshold,Data),
valid_exchanges = get_value(valid_exchanges,Data),
emailto = get_value(to,Data),
emailfrom = get_value(from,Data),
strategy = get_value(strategy,Data),
inbetween_count_threshold = get_value(inbetween_count_threshold,Data)
}.
get_value(Key,Data) ->
case proplists:get_value(Key,Data) of
undefined ->
get_value(Key);
V ->
V
end.
get_value(master_name) ->
#config.master_name;
get_value(count_threshold) ->
#config.count_threshold;
get_value(time_threshold) ->
#config.time_threshold;
get_value(memory_threshold) ->
#config.memory_threshold;
get_value(disable_memory_threshold) ->
#config.disable_memory_threshold;
get_value(enable_memory_threshold) ->
#config.enable_memory_threshold;
get_value(valid_exchanges) ->
#config.valid_exchanges;
get_value(to) ->
#config.emailto;
get_value(from) ->
#config.emailfrom;
get_value(inbetween_count_threshold) ->
#config.inbetween_count_threshold;
get_value(strategy) ->
#config.strategy.
to_binary(Value) when is_binary(Value) ->
Value;
to_binary(Value) when is_list(Value) ->
erlang:list_to_binary(Value);
to_binary(Value) when is_atom(Value) ->
erlang:atom_to_binary(Value,utf8).
%to_atom(Value) when is_atom(Value) ->
% Value;
%to_atom(Value) when is_list(Value) ->
% erlang:list_to_atom(Value);
%to_atom(Value) when is_binary(Value) ->
% erlang:binary_to_atom(Value,utf8).
to_list(Value) when is_list(Value) ->
Value;
to_list(Value) when is_binary(Value) ->
erlang:binary_to_list(Value);
to_list(Value) when is_atom(Value) ->
erlang:atom_to_list(Value).
send_email(enable,Data,Config) ->
send_email("After Enabling",Data,Config);
send_email(disable,Data,Config) ->
send_email("After disabling",Data,Config);
send_email(Type,Data,Config) ->
?log_error("Sending email"),
os:cmd("echo \"From:" ++ Config#config.emailfrom ++"\r\nTo:" ++ Config#config.emailto ++ "\r\nSubject: Memory Status : each node : " ++ Type ++ " \r\nMime-Version: 1.1 \r\nContent-Type: text/html \r\n\r\n" ++ Data ++ "\" | /usr/sbin/sendmail -t").