Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

242 wiersze
9.2 KiB

14 lat temu
  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. sink :: pid() | atom()
  33. }).
  34. start_link(Sink, Module, Config) ->
  35. gen_server:start_link(?MODULE, [Sink, Module, Config], []).
  36. start(Sink, Module, Config) ->
  37. gen_server:start(?MODULE, [Sink, Module, Config], []).
  38. init([Sink, Module, Config]) ->
  39. process_flag(trap_exit, true),
  40. install_handler(Sink, Module, Config),
  41. {ok, #state{sink=Sink, module=Module, config=Config}}.
  42. handle_call(_Call, _From, State) ->
  43. {reply, ok, State}.
  44. handle_cast(_Request, State) ->
  45. {noreply, State}.
  46. handle_info({gen_event_EXIT, Module, normal}, #state{module=Module} = State) ->
  47. {stop, normal, State};
  48. handle_info({gen_event_EXIT, Module, shutdown}, #state{module=Module} = State) ->
  49. {stop, normal, State};
  50. handle_info({gen_event_EXIT, Module, {'EXIT', {kill_me, [_KillerHWM, KillerReinstallAfter]}}},
  51. #state{module=Module, sink=Sink, config = Config} = State) ->
  52. %% Brutally kill the manager but stay alive to restore settings.
  53. %%
  54. %% SinkPid here means the gen_event process. Handlers *all* live inside the
  55. %% same gen_event process space, so when the Pid is killed, *all* of the
  56. %% pending log messages in its mailbox will die too.
  57. SinkPid = whereis(Sink),
  58. unlink(SinkPid),
  59. {message_queue_len, Len} = process_info(SinkPid, message_queue_len),
  60. error_logger:error_msg("Killing sink ~p, current message_queue_len:~p~n", [Sink, Len]),
  61. exit(SinkPid, kill),
  62. timer:apply_after(KillerReinstallAfter, lager_app, start_handler, [Sink, Module, Config]),
  63. {stop, normal, State};
  64. handle_info({gen_event_EXIT, Module, Reason}, #state{module=Module,
  65. config=Config, sink=Sink} = State) ->
  66. case lager:log(error, self(), "Lager event handler ~p exited with reason ~s",
  67. [Module, error_logger_lager_h:format_reason(Reason)]) of
  68. ok ->
  69. install_handler(Sink, Module, Config);
  70. {error, _} ->
  71. %% lager is not working, so installing a handler won't work
  72. ok
  73. end,
  74. {noreply, State};
  75. handle_info(reinstall_handler, #state{module=Module, config=Config, sink=Sink} = State) ->
  76. install_handler(Sink, Module, Config),
  77. {noreply, State};
  78. handle_info({reboot, Sink}, State) ->
  79. _ = lager_app:boot(Sink),
  80. {noreply, State};
  81. handle_info(stop, State) ->
  82. {stop, normal, State};
  83. handle_info({'EXIT', _Pid, killed}, #state{module=Module, config=Config, sink=Sink} = State) ->
  84. Tmr = application:get_env(lager, killer_reinstall_after, 5000),
  85. timer:apply_after(Tmr, lager_app, start_handler, [Sink, Module, Config]),
  86. {stop, normal, State};
  87. handle_info(_Info, State) ->
  88. {noreply, State}.
  89. terminate(_Reason, _State) ->
  90. ok.
  91. code_change(_OldVsn, State, _Extra) ->
  92. {ok, State}.
  93. %% internal
  94. install_handler(Sink, lager_backend_throttle, Config) ->
  95. %% The lager_backend_throttle needs to know to which sink it is
  96. %% attached, hence this admittedly ugly workaround. Handlers are
  97. %% sensitive to the structure of the configuration sent to `init',
  98. %% sadly, so it's not trivial to add a configuration item to be
  99. %% ignored to backends without breaking 3rd party handlers.
  100. install_handler2(Sink, lager_backend_throttle, [{sink, Sink}|Config]);
  101. install_handler(Sink, Module, Config) ->
  102. install_handler2(Sink, Module, Config).
  103. %% private
  104. install_handler2(Sink, Module, Config) ->
  105. case gen_event:add_sup_handler(Sink, Module, Config) of
  106. ok ->
  107. ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Sink]),
  108. lager:update_loglevel_config(Sink),
  109. ok;
  110. {error, {fatal, Reason}} ->
  111. ?INT_LOG(error, "Lager fatally failed to install handler ~p into"
  112. " ~p, NOT retrying: ~p", [Module, Sink, Reason]),
  113. %% tell ourselves to stop
  114. self() ! stop,
  115. ok;
  116. Error ->
  117. %% try to reinstall it later
  118. ?INT_LOG(error, "Lager failed to install handler ~p into"
  119. " ~p, retrying later : ~p", [Module, Sink, Error]),
  120. erlang:send_after(5000, self(), reinstall_handler),
  121. ok
  122. end.
  123. -ifdef(TEST).
  124. from_now(Seconds) ->
  125. {Mega, Secs, Micro} = os:timestamp(),
  126. {Mega, Secs + Seconds, Micro}.
  127. reinstall_on_initial_failure_test_() ->
  128. {timeout, 60000,
  129. [
  130. fun() ->
  131. error_logger:tty(false),
  132. application:load(lager),
  133. application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [from_now(2), undefined]}]),
  134. application:set_env(lager, error_logger_redirect, false),
  135. application:unset_env(lager, crash_log),
  136. lager:start(),
  137. try
  138. {_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
  139. ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Message)),
  140. timer:sleep(6000),
  141. lager_test_backend:flush(),
  142. ?assertEqual(0, lager_test_backend:count()),
  143. ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
  144. after
  145. application:stop(lager),
  146. application:stop(goldrush),
  147. error_logger:tty(true)
  148. end
  149. end
  150. ]
  151. }.
  152. reinstall_on_runtime_failure_test_() ->
  153. {timeout, 60000,
  154. [
  155. fun() ->
  156. error_logger:tty(false),
  157. application:load(lager),
  158. application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [undefined, from_now(5)]}]),
  159. application:set_env(lager, error_logger_redirect, false),
  160. application:unset_env(lager, crash_log),
  161. lager:start(),
  162. try
  163. ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event))),
  164. timer:sleep(6000),
  165. pop_until("Lager event handler lager_crash_backend exited with reason crash", fun lists:flatten/1),
  166. pop_until("Lager failed to install handler lager_crash_backend into lager_event, retrying later",
  167. fun(Msg) -> string:substr(lists:flatten(Msg), 1, 84) end),
  168. ?assertEqual(false, lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
  169. after
  170. application:stop(lager),
  171. application:stop(goldrush),
  172. error_logger:tty(true)
  173. end
  174. end
  175. ]
  176. }.
  177. reinstall_handlers_after_killer_hwm_test_() ->
  178. {timeout, 60000,
  179. [
  180. fun() ->
  181. error_logger:tty(false),
  182. application:load(lager),
  183. application:set_env(lager, handlers, [{lager_manager_killer, [1000, 5000]}]),
  184. application:set_env(lager, error_logger_redirect, false),
  185. application:set_env(lager, killer_reinstall_after, 5000),
  186. application:unset_env(lager, crash_log),
  187. lager:start(),
  188. lager:trace_file("foo", [{foo, "bar"}], error),
  189. L = length(gen_event:which_handlers(lager_event)),
  190. try
  191. lager_manager_killer:kill_me(),
  192. timer:sleep(6000),
  193. ?assertEqual(L, length(gen_event:which_handlers(lager_event))),
  194. file:delete("foo")
  195. after
  196. application:stop(lager),
  197. application:stop(goldrush),
  198. error_logger:tty(true)
  199. end
  200. end
  201. ]
  202. }.
  203. pop_until(String, Fun) ->
  204. try_backend_pop(lager_test_backend:pop(), String, Fun).
  205. try_backend_pop(undefined, String, _Fun) ->
  206. throw("Not found: " ++ String);
  207. try_backend_pop({_Severity, _Date, Msg, _Metadata}, String, Fun) ->
  208. case Fun(Msg) of
  209. String ->
  210. ok;
  211. _ ->
  212. try_backend_pop(lager_test_backend:pop(), String, Fun)
  213. end.
  214. -endif.