您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

162 行
6.0 KiB

  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. -ifdef(TEST).
  22. -include_lib("eunit/include/eunit.hrl").
  23. -endif.
  24. %% callbacks
  25. -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
  26. code_change/3]).
  27. -export([start_link/3, start/3]).
  28. -record(state, {
  29. module,
  30. config,
  31. event
  32. }).
  33. start_link(Event, Module, Config) ->
  34. gen_server:start_link(?MODULE, [Event, Module, Config], []).
  35. start(Event, Module, Config) ->
  36. gen_server:start(?MODULE, [Event, Module, Config], []).
  37. init([Event, Module, Config]) ->
  38. install_handler(Event, Module, Config),
  39. {ok, #state{event=Event, module=Module, config=Config}}.
  40. handle_call(_Call, _From, State) ->
  41. {reply, ok, State}.
  42. handle_cast(_Request, State) ->
  43. {noreply, State}.
  44. handle_info({gen_event_EXIT, Module, normal}, #state{module=Module} = State) ->
  45. {stop, normal, State};
  46. handle_info({gen_event_EXIT, Module, shutdown}, #state{module=Module} = State) ->
  47. {stop, normal, State};
  48. handle_info({gen_event_EXIT, Module, Reason}, #state{module=Module,
  49. config=Config, event=Event} = State) ->
  50. case lager:log(error, self(), "Lager event handler ~p exited with reason ~s",
  51. [Module, error_logger_lager_h:format_reason(Reason)]) of
  52. ok ->
  53. install_handler(Event, Module, Config);
  54. {error, _} ->
  55. %% lager is not working, so installing a handler won't work
  56. ok
  57. end,
  58. {noreply, State};
  59. handle_info(reinstall_handler, #state{module=Module, config=Config, event=Event} = State) ->
  60. install_handler(Event, Module, Config),
  61. {noreply, State};
  62. handle_info(_Info, State) ->
  63. {noreply, State}.
  64. terminate(_Reason, _State) ->
  65. ok.
  66. code_change(_OldVsn, State, _Extra) ->
  67. {ok, State}.
  68. %% internal
  69. install_handler(Event, Module, Config) ->
  70. case gen_event:add_sup_handler(Event, Module, Config) of
  71. ok ->
  72. _ = lager:log(debug, self(), "Lager installed handler ~p into ~p", [Module, Event]),
  73. lager:update_loglevel_config(),
  74. ok;
  75. Error ->
  76. %% try to reinstall it later
  77. _ = lager:log(error, self(), "Lager failed to install handler ~p into"
  78. " ~p, retrying later : ~p", [Module, Event, Error]),
  79. erlang:send_after(5000, self(), reinstall_handler),
  80. ok
  81. end.
  82. -ifdef(TEST).
  83. from_now(Seconds) ->
  84. {Mega, Secs, Micro} = os:timestamp(),
  85. {Mega, Secs + Seconds, Micro}.
  86. reinstall_on_initial_failure_test_() ->
  87. {timeout, 60000,
  88. [
  89. fun() ->
  90. error_logger:tty(false),
  91. application:load(lager),
  92. application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [from_now(2), undefined]}]),
  93. application:set_env(lager, error_logger_redirect, false),
  94. application:unset_env(lager, crash_log),
  95. application:start(lager),
  96. try
  97. ?assertEqual(1, lager_test_backend:count()),
  98. {_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
  99. ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Message)),
  100. ?assertEqual(0, lager_test_backend:count()),
  101. timer:sleep(6000),
  102. ?assertEqual(0, lager_test_backend:count()),
  103. ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
  104. after
  105. application:stop(lager),
  106. error_logger:tty(true)
  107. end
  108. end
  109. ]
  110. }.
  111. reinstall_on_runtime_failure_test_() ->
  112. {timeout, 60000,
  113. [
  114. fun() ->
  115. error_logger:tty(false),
  116. application:load(lager),
  117. application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [undefined, from_now(5)]}]),
  118. application:set_env(lager, error_logger_redirect, false),
  119. application:unset_env(lager, crash_log),
  120. application:start(lager),
  121. try
  122. ?assertEqual(0, lager_test_backend:count()),
  123. ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event))),
  124. timer:sleep(6000),
  125. ?assertEqual(2, lager_test_backend:count()),
  126. {_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
  127. ?assertEqual("Lager event handler lager_crash_backend exited with reason crash", lists:flatten(Message)),
  128. {_Level2, _Time2, Message2, _Metadata} = lager_test_backend:pop(),
  129. ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Message2)),
  130. ?assertEqual(false, lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
  131. after
  132. application:stop(lager),
  133. error_logger:tty(true)
  134. end
  135. end
  136. ]
  137. }.
  138. -endif.