cowboy_error_h.erl 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. %% Copyright (c) 2014, Loïc Hoguin <essen@ninenines.eu>
  2. %%
  3. %% Permission to use, copy, modify, and/or distribute this software for any
  4. %% purpose with or without fee is hereby granted, provided that the above
  5. %% copyright notice and this permission notice appear in all copies.
  6. %%
  7. %% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. %% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. %% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. %% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. %% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. -module(cowboy_error_h).
  15. -behaviour(gen_event).
  16. %% Public interface.
  17. -export([ignore/3]).
  18. %% gen_event.
  19. -export([init/1]).
  20. -export([handle_event/2]).
  21. -export([handle_call/2]).
  22. -export([handle_info/2]).
  23. -export([terminate/2]).
  24. -export([code_change/3]).
  25. %% Public interface.
  26. %% Ignore crashes from Pid occuring in M:F/A.
  27. ignore(M, F, A) ->
  28. gen_event:call(error_logger, ?MODULE, {expect, {self(), M, F, A}}).
  29. %% gen_event.
  30. init(_) ->
  31. spawn(fun() -> error_logger:tty(false) end),
  32. {ok, []}.
  33. %% Ignore supervisor and progress reports.
  34. handle_event({info_report, _, {_, progress, _}}, State) ->
  35. {ok, State};
  36. handle_event({info_report, _, {_, std_info, _}}, State) ->
  37. {ok, State};
  38. handle_event({error_report, _, {_, supervisor_report, _}}, State) ->
  39. {ok, State};
  40. %% Ignore gun retry failures.
  41. handle_event({error_report, _, {_, crash_report,
  42. [[{initial_call, {gun, init, _}}, _, _,
  43. {error_info, {error, gone, _}}|_]|_]}},
  44. State) ->
  45. {ok, State};
  46. %% Ignore emulator reports that are a duplicate of what Ranch gives us.
  47. %%
  48. %% The emulator always sends strings for errors, which makes it very
  49. %% difficult to extract the information we need, hence the regexps.
  50. handle_event(Event = {error, GL, {emulator, _, Msg}}, State)
  51. when node(GL) =:= node() ->
  52. Result = re:run(Msg,
  53. "Error in process ([^\s]+).+? with exit value: "
  54. ".+?{stacktrace,\\[{([^,]+),([^,]+),(.+)",
  55. [{capture, all_but_first, list}]),
  56. case Result of
  57. nomatch ->
  58. write_event(Event),
  59. {ok, State};
  60. {match, [PidStr, MStr, FStr, Rest]} ->
  61. A = case Rest of
  62. "[]" ++ _ ->
  63. 0;
  64. "[" ++ Rest2 ->
  65. count_args(Rest2, 1, 0);
  66. _ ->
  67. {match, [AStr]} = re:run(Rest, "([^,]+).+",
  68. [{capture, all_but_first, list}]),
  69. list_to_integer(AStr)
  70. end,
  71. Crash = {list_to_pid(PidStr), list_to_existing_atom(MStr),
  72. list_to_existing_atom(FStr), A},
  73. case lists:member(Crash, State) of
  74. true ->
  75. {ok, lists:delete(Crash, State)};
  76. false ->
  77. write_event(Event),
  78. {ok, State}
  79. end
  80. end;
  81. handle_event(Event = {error, GL,
  82. {_, "Ranch listener" ++ _, [_, _, Pid, {[_, _,
  83. {stacktrace, [{M, F, A, _}|_]}|_], _}]}},
  84. State) when node(GL) =:= node() ->
  85. A2 = if is_list(A) -> length(A); true -> A end,
  86. Crash = {Pid, M, F, A2},
  87. case lists:member(Crash, State) of
  88. true ->
  89. {ok, lists:delete(Crash, State)};
  90. false ->
  91. write_event(Event),
  92. {ok, State}
  93. end;
  94. handle_event(Event = {_, GL, _}, State) when node(GL) =:= node() ->
  95. write_event(Event),
  96. {ok, State};
  97. handle_event(_, State) ->
  98. {ok, State}.
  99. handle_call({expect, Crash}, State) ->
  100. {ok, ok, [Crash, Crash|State]};
  101. handle_call(_, State) ->
  102. {ok, {error, bad_query}, State}.
  103. handle_info(_, State) ->
  104. {ok, State}.
  105. terminate(_, _) ->
  106. spawn(fun() -> error_logger:tty(true) end),
  107. ok.
  108. code_change(_, State, _) ->
  109. {ok, State}.
  110. %% Internal.
  111. write_event(Event) ->
  112. error_logger_tty_h:write_event(
  113. {erlang:universaltime(), Event},
  114. io).
  115. count_args("]" ++ _, N, 0) ->
  116. N;
  117. count_args("]" ++ Tail, N, Levels) ->
  118. count_args(Tail, N, Levels - 1);
  119. count_args("[" ++ Tail, N, Levels) ->
  120. count_args(Tail, N, Levels + 1);
  121. count_args("}" ++ Tail, N, Levels) ->
  122. count_args(Tail, N, Levels - 1);
  123. count_args("{" ++ Tail, N, Levels) ->
  124. count_args(Tail, N, Levels + 1);
  125. count_args("," ++ Tail, N, Levels = 0) ->
  126. count_args(Tail, N + 1, Levels);
  127. count_args("," ++ Tail, N, Levels) ->
  128. count_args(Tail, N, Levels);
  129. count_args([_|Tail], N, Levels) ->
  130. count_args(Tail, N, Levels).