@ -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}. |