@ -0,0 +1,44 @@ | |||||
-module(lager_manager_killer). | |||||
-author("Sungjin Park <jinni.park@gmail.com>"). | |||||
-behavior(gen_event). | |||||
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]). | |||||
-include("lager.hrl"). | |||||
-record(state, { | |||||
killer_hwm :: non_neg_integer(), | |||||
killer_reinstall_after :: non_neg_integer() | |||||
}). | |||||
init([KillerHWM, KillerReinstallAfter]) -> | |||||
{ok, #state{killer_hwm=KillerHWM, killer_reinstall_after=KillerReinstallAfter}}. | |||||
handle_call(get_loglevel, State) -> | |||||
{ok, {mask, ?LOG_NONE}, State}; | |||||
handle_call({set_loglevel, _Level}, State) -> | |||||
{ok, ok, State}; | |||||
handle_call(get_settings, State = #state{killer_hwm=KillerHWM, killer_reinstall_after=KillerReinstallAfter}) -> | |||||
{ok, [KillerHWM, KillerReinstallAfter], State}; | |||||
handle_call(_Request, State) -> | |||||
{ok, ok, State}. | |||||
handle_event({log, _Message}, State = #state{killer_hwm=KillerHWM, killer_reinstall_after=KillerReinstallAfter}) -> | |||||
{message_queue_len, Len} = process_info(self(), message_queue_len), | |||||
case Len > KillerHWM of | |||||
true -> | |||||
exit({kill_me, [KillerHWM, KillerReinstallAfter]}); | |||||
_ -> | |||||
{ok, State} | |||||
end; | |||||
handle_event(_Event, State) -> | |||||
{ok, State}. | |||||
handle_info(_Info, State) -> | |||||
{ok, State}. | |||||
terminate(_Reason, _State) -> | |||||
ok. | |||||
code_change(_OldVsn, State, _Extra) -> | |||||
{ok, State}. |
@ -0,0 +1,55 @@ | |||||
-module(lager_manager_killer_test). | |||||
-author("Sungjin Park <jinni.park@gmail.com>"). | |||||
-compile([{parse_transform, lager_transform}]). | |||||
-ifdef(TEST). | |||||
-include_lib("eunit/include/eunit.hrl"). | |||||
overload_test() -> | |||||
application:stop(lager), | |||||
application:load(lager), | |||||
Delay = 1000, % sleep 1 sec on every log | |||||
KillerHWM = 10, % kill the manager if there are more than 10 pending logs | |||||
KillerReinstallAfter = 1000, % reinstall killer after 1 sec | |||||
application:set_env(lager, handlers, [{lager_slow_backend, Delay}]), | |||||
application:set_env(lager, async_threshold, undefined), | |||||
application:set_env(lager, killer_hwm, KillerHWM), | |||||
application:set_env(lager, killer_reinstall_after, KillerReinstallAfter), | |||||
ensure_started(lager), | |||||
lager_config:set(async, true), | |||||
Manager = whereis(lager_event), | |||||
erlang:trace(all, true, [procs]), | |||||
[lager:info("~p'th message", [N]) || N <- lists:seq(1,KillerHWM+2)], | |||||
Margin = 100, | |||||
receive | |||||
{trace, Manager, exit, killed} -> | |||||
?debugFmt("Manager ~p killed", [Manager]) | |||||
after Delay+Margin -> | |||||
?assert(false) | |||||
end, | |||||
receive | |||||
{trace, _Sup, spawn, Pid, Fun} -> | |||||
?assert(process_info(Pid, registered_name) =:= {registered_name, lager_event}), | |||||
?debugFmt("Manager ~p start with ~p", [Pid, Fun]), | |||||
?assertNot(lists:member(lager_manager_killer, gen_event:which_handlers(lager_event))) | |||||
after Margin -> | |||||
?assert(false) | |||||
end, | |||||
erlang:trace(all, false, [procs]), | |||||
timer:sleep(KillerReinstallAfter), | |||||
?assert(proplists:get_value(lager_manager_killer, gen_event:which_handlers(lager_event))), | |||||
?assert(gen_event:call(lager_event, lager_manager_killer, get_settings) =:= [KillerHWM, KillerReinstallAfter]), | |||||
?debugFmt("Killer reinstalled with [~p, ~p]", [KillerHWM, KillerReinstallAfter]), | |||||
application:stop(lager). | |||||
ensure_started(App) -> | |||||
case application:start(App) of | |||||
ok -> | |||||
ok; | |||||
{error, {not_started, Dep}} -> | |||||
ensure_started(Dep), | |||||
ensure_started(App) | |||||
end. | |||||
-endif. |
@ -0,0 +1,34 @@ | |||||
-module(lager_slow_backend). | |||||
-author("Sungjin Park <jinni.park@gmail.com>"). | |||||
-behavior(gen_event). | |||||
-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, code_change/3]). | |||||
-include("lager.hrl"). | |||||
-record(state, { | |||||
delay :: non_neg_integer() | |||||
}). | |||||
init(Delay) -> | |||||
{ok, #state{delay=Delay}}. | |||||
handle_call(get_loglevel, State) -> | |||||
{ok, lager_util:config_to_mask(debug), State}; | |||||
handle_call(_Request, State) -> | |||||
{ok, ok, State}. | |||||
handle_event({log, _Message}, State) -> | |||||
timer:sleep(State#state.delay), | |||||
{ok, State}; | |||||
handle_event(_Event, State) -> | |||||
{ok, State}. | |||||
handle_info(_Info, State) -> | |||||
{ok, State}. | |||||
terminate(_Reason, _State) -> | |||||
ok. | |||||
code_change(_OldVsn, State, _Extra) -> | |||||
{ok, State}. |