You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
6.4 KiB

14 years ago
  1. %% Copyright (c) 2011-2012 Basho Technologies, Inc. All Rights Reserved.
  2. %%
  3. %% This file is provided to you under the Apache License,
  4. %% Version 2.0 (the "License"); you may not use this file
  5. %% except in compliance with the License. You may obtain
  6. %% a copy of the License at
  7. %%
  8. %% http://www.apache.org/licenses/LICENSE-2.0
  9. %%
  10. %% Unless required by applicable law or agreed to in writing,
  11. %% software distributed under the License is distributed on an
  12. %% "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  13. %% KIND, either express or implied. See the License for the
  14. %% specific language governing permissions and limitations
  15. %% under the License.
  16. %% @doc A process that does a gen_event:add_sup_handler and attempts to re-add
  17. %% event handlers when they exit.
  18. %% @private
  19. -module(lager_handler_watcher).
  20. -behaviour(gen_server).
  21. -include("lager.hrl").
  22. -ifdef(TEST).
  23. -include_lib("eunit/include/eunit.hrl").
  24. -endif.
  25. %% callbacks
  26. -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
  27. code_change/3]).
  28. -export([start_link/3, start/3]).
  29. -record(state, {
  30. module :: atom(),
  31. config :: any(),
  32. event :: pid() | atom()
  33. }).
  34. start_link(Event, Module, Config) ->
  35. gen_server:start_link(?MODULE, [Event, Module, Config], []).
  36. start(Event, Module, Config) ->
  37. gen_server:start(?MODULE, [Event, Module, Config], []).
  38. init([Event, Module, Config]) ->
  39. install_handler(Event, Module, Config),
  40. {ok, #state{event=Event, module=Module, config=Config}}.
  41. handle_call(_Call, _From, State) ->
  42. {reply, ok, State}.
  43. handle_cast(_Request, State) ->
  44. {noreply, State}.
  45. handle_info({gen_event_EXIT, Module, normal}, #state{module=Module} = State) ->
  46. {stop, normal, State};
  47. handle_info({gen_event_EXIT, Module, shutdown}, #state{module=Module} = State) ->
  48. {stop, normal, State};
  49. handle_info({gen_event_EXIT, Module, Reason}, #state{module=Module,
  50. config=Config, event=Event} = State) ->
  51. case lager:log(error, self(), "Lager event handler ~p exited with reason ~s",
  52. [Module, error_logger_lager_h:format_reason(Reason)]) of
  53. ok ->
  54. install_handler(Event, Module, Config);
  55. {error, _} ->
  56. %% lager is not working, so installing a handler won't work
  57. ok
  58. end,
  59. {noreply, State};
  60. handle_info(reinstall_handler, #state{module=Module, config=Config, event=Event} = State) ->
  61. install_handler(Event, Module, Config),
  62. {noreply, State};
  63. handle_info(stop, State) ->
  64. {stop, normal, State};
  65. handle_info(_Info, State) ->
  66. {noreply, State}.
  67. terminate(_Reason, _State) ->
  68. ok.
  69. code_change(_OldVsn, State, _Extra) ->
  70. {ok, State}.
  71. %% internal
  72. install_handler(Event, Module, Config) ->
  73. case gen_event:add_sup_handler(Event, Module, Config) of
  74. ok ->
  75. ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Event]),
  76. lager:update_loglevel_config(),
  77. ok;
  78. {error, {fatal, Reason}} ->
  79. ?INT_LOG(error, "Lager fatally failed to install handler ~p into"
  80. " ~p, NOT retrying: ~p", [Module, Event, Reason]),
  81. %% tell ourselves to stop
  82. self() ! stop,
  83. ok;
  84. Error ->
  85. %% try to reinstall it later
  86. ?INT_LOG(error, "Lager failed to install handler ~p into"
  87. " ~p, retrying later : ~p", [Module, Event, Error]),
  88. erlang:send_after(5000, self(), reinstall_handler),
  89. ok
  90. end.
  91. -ifdef(TEST).
  92. from_now(Seconds) ->
  93. {Mega, Secs, Micro} = os:timestamp(),
  94. {Mega, Secs + Seconds, Micro}.
  95. reinstall_on_initial_failure_test_() ->
  96. {timeout, 60000,
  97. [
  98. fun() ->
  99. error_logger:tty(false),
  100. application:load(lager),
  101. application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [from_now(2), undefined]}]),
  102. application:set_env(lager, error_logger_redirect, false),
  103. application:unset_env(lager, crash_log),
  104. lager:start(),
  105. try
  106. ?assertEqual(1, lager_test_backend:count()),
  107. {_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
  108. ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Message)),
  109. ?assertEqual(0, lager_test_backend:count()),
  110. timer:sleep(6000),
  111. ?assertEqual(0, lager_test_backend:count()),
  112. ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
  113. after
  114. application:stop(lager),
  115. application:stop(goldrush),
  116. error_logger:tty(true)
  117. end
  118. end
  119. ]
  120. }.
  121. reinstall_on_runtime_failure_test_() ->
  122. {timeout, 60000,
  123. [
  124. fun() ->
  125. error_logger:tty(false),
  126. application:load(lager),
  127. application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [undefined, from_now(5)]}]),
  128. application:set_env(lager, error_logger_redirect, false),
  129. application:unset_env(lager, crash_log),
  130. lager:start(),
  131. try
  132. ?assertEqual(0, lager_test_backend:count()),
  133. ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event))),
  134. timer:sleep(6000),
  135. ?assertEqual(2, lager_test_backend:count()),
  136. {_Severity, _Date, Msg, _Metadata} = lager_test_backend:pop(),
  137. ?assertEqual("Lager event handler lager_crash_backend exited with reason crash", lists:flatten(Msg)),
  138. {_Severity2, _Date2, Msg2, _Metadata2} = lager_test_backend:pop(),
  139. ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Msg2)),
  140. ?assertEqual(false, lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
  141. after
  142. application:stop(lager),
  143. application:stop(goldrush),
  144. error_logger:tty(true)
  145. end
  146. end
  147. ]
  148. }.
  149. -endif.