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.

242 lines
9.2 KiB

преди 12 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 9 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 14 години
преди 11 години
преди 13 години
преди 11 години
  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.