|
|
- %% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
- %%
- %% This file is provided to you under the Apache License,
- %% Version 2.0 (the "License"); you may not use this file
- %% except in compliance with the License. You may obtain
- %% a copy of the License at
- %%
- %% http://www.apache.org/licenses/LICENSE-2.0
- %%
- %% Unless required by applicable law or agreed to in writing,
- %% software distributed under the License is distributed on an
- %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- %% KIND, either express or implied. See the License for the
- %% specific language governing permissions and limitations
- %% under the License.
-
- %% @doc A process that does a gen_event:add_sup_handler and attempts to re-add
- %% event handlers when they exit.
-
- %% @private
-
- -module(lager_handler_watcher).
-
- -behaviour(gen_server).
-
- -include("lager.hrl").
-
- -ifdef(TEST).
- -include_lib("eunit/include/eunit.hrl").
- -endif.
-
- %% callbacks
- -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
- code_change/3]).
-
- -export([start_link/3, start/3]).
-
- -record(state, {
- module :: atom(),
- config :: any(),
- event :: pid() | atom()
- }).
-
- start_link(Event, Module, Config) ->
- gen_server:start_link(?MODULE, [Event, Module, Config], []).
-
- start(Event, Module, Config) ->
- gen_server:start(?MODULE, [Event, Module, Config], []).
-
- init([Event, Module, Config]) ->
- install_handler(Event, Module, Config),
- {ok, #state{event=Event, module=Module, config=Config}}.
-
- handle_call(_Call, _From, State) ->
- {reply, ok, State}.
-
- handle_cast(_Request, State) ->
- {noreply, State}.
-
- handle_info({gen_event_EXIT, Module, normal}, #state{module=Module} = State) ->
- {stop, normal, State};
- handle_info({gen_event_EXIT, Module, shutdown}, #state{module=Module} = State) ->
- {stop, normal, State};
- handle_info({gen_event_EXIT, Module, Reason}, #state{module=Module,
- config=Config, event=Event} = State) ->
- case lager:log(error, self(), "Lager event handler ~p exited with reason ~s",
- [Module, error_logger_lager_h:format_reason(Reason)]) of
- ok ->
- install_handler(Event, Module, Config);
- {error, _} ->
- %% lager is not working, so installing a handler won't work
- ok
- end,
- {noreply, State};
- handle_info(reinstall_handler, #state{module=Module, config=Config, event=Event} = State) ->
- install_handler(Event, Module, Config),
- {noreply, State};
- handle_info(stop, State) ->
- {stop, normal, State};
- handle_info(_Info, State) ->
- {noreply, State}.
-
- terminate(_Reason, _State) ->
- ok.
-
- code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
- %% internal
-
- install_handler(Event, Module, Config) ->
- case gen_event:add_sup_handler(Event, Module, Config) of
- ok ->
- ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Event]),
- lager:update_loglevel_config(),
- ok;
- {error, {fatal, Reason}} ->
- ?INT_LOG(error, "Lager fatally failed to install handler ~p into"
- " ~p, NOT retrying: ~p", [Module, Event, Reason]),
- %% tell ourselves to stop
- self() ! stop,
- ok;
- Error ->
- %% try to reinstall it later
- ?INT_LOG(error, "Lager failed to install handler ~p into"
- " ~p, retrying later : ~p", [Module, Event, Error]),
- erlang:send_after(5000, self(), reinstall_handler),
- ok
- end.
-
- -ifdef(TEST).
-
- from_now(Seconds) ->
- {Mega, Secs, Micro} = os:timestamp(),
- {Mega, Secs + Seconds, Micro}.
-
- reinstall_on_initial_failure_test_() ->
- {timeout, 60000,
- [
- fun() ->
- error_logger:tty(false),
- application:load(lager),
- application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [from_now(2), undefined]}]),
- application:set_env(lager, error_logger_redirect, false),
- application:unset_env(lager, crash_log),
- lager:start(),
- try
- ?assertEqual(1, lager_test_backend:count()),
- {_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
- ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Message)),
- ?assertEqual(0, lager_test_backend:count()),
- timer:sleep(6000),
- ?assertEqual(0, lager_test_backend:count()),
- ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
- after
- application:stop(lager),
- application:stop(goldrush),
- error_logger:tty(true)
- end
- end
- ]
- }.
-
- reinstall_on_runtime_failure_test_() ->
- {timeout, 60000,
- [
- fun() ->
- error_logger:tty(false),
- application:load(lager),
- application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [undefined, from_now(5)]}]),
- application:set_env(lager, error_logger_redirect, false),
- application:unset_env(lager, crash_log),
- lager:start(),
- try
- ?assertEqual(0, lager_test_backend:count()),
- ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event))),
- timer:sleep(6000),
- ?assertEqual(2, lager_test_backend:count()),
- {_Severity, _Date, Msg, _Metadata} = lager_test_backend:pop(),
- ?assertEqual("Lager event handler lager_crash_backend exited with reason crash", lists:flatten(Msg)),
- {_Severity2, _Date2, Msg2, _Metadata2} = lager_test_backend:pop(),
- ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Msg2)),
- ?assertEqual(false, lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
- after
- application:stop(lager),
- application:stop(goldrush),
- error_logger:tty(true)
- end
- end
- ]
- }.
-
-
- -endif.
|