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.

198 lines
8.2 KiB

14 years ago
14 years ago
14 years ago
  1. %% Copyright (c) 2011 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. -module(error_logger_lager_h).
  17. -behaviour(gen_event).
  18. -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
  19. code_change/3]).
  20. -export([format_reason/1]).
  21. -define(LOG(Level, Pid, Msg),
  22. case lager_util:level_to_num(Level) >= lager_mochiglobal:get(loglevel, 0) of
  23. true ->
  24. lager:log(Level, Pid, Msg);
  25. _ -> ok
  26. end).
  27. -define(LOG(Level, Pid, Fmt, Args),
  28. case lager_util:level_to_num(Level) >= lager_mochiglobal:get(loglevel, 0) of
  29. true ->
  30. lager:log(Level, Pid, Fmt, Args);
  31. _ -> ok
  32. end).
  33. init(_) ->
  34. {ok, {}}.
  35. handle_call(_Request, State) ->
  36. {ok, ok, State}.
  37. handle_event(Event, State) ->
  38. case Event of
  39. {error, _GL, {Pid, Fmt, Args}} ->
  40. case Fmt of
  41. "** Generic server "++_ ->
  42. %% gen_server terminate
  43. [Name, _Msg, _State, Reason] = Args,
  44. ?LOG(error, Pid, "gen_server ~w terminated with reason: ~s",
  45. [Name, format_reason(Reason)]);
  46. "** State machine "++_ ->
  47. %% gen_fsm terminate
  48. [Name, _Msg, StateName, _StateData, Reason] = Args,
  49. ?LOG(error, Pid, "gen_fsm ~w in state ~w terminated with reason: ~s",
  50. [Name, StateName, format_reason(Reason)]);
  51. "** gen_event handler"++_ ->
  52. %% gen_event handler terminate
  53. [ID, Name, _Msg, _State, Reason] = Args,
  54. ?LOG(error, Pid, "gen_event ~w installed in ~w terminated with reason: ~s",
  55. [ID, Name, format_reason(Reason)]);
  56. _ ->
  57. ?LOG(error, Pid, Fmt, Args)
  58. end;
  59. {error_report, _GL, {Pid, std_error, D}} ->
  60. ?LOG(error, Pid, print_silly_list(D));
  61. {error_report, _GL, {Pid, supervisor_report, D}} ->
  62. case lists:sort(D) of
  63. [{errorContext, Ctx}, {offender, Off}, {reason, Reason}, {supervisor, Name}] ->
  64. Offender = format_offender(Off),
  65. ?LOG(error, Pid, "Supervisor ~w had child ~s exit with reason ~w in context ~w", [element(2, Name), Offender, Reason, Ctx]);
  66. _ ->
  67. ?LOG(error, Pid, ["SUPERVISOR REPORT ", print_silly_list(D)])
  68. end;
  69. {error_report, _GL, {Pid, crash_report, [Self, Neighbours]}} ->
  70. ?LOG(error, Pid, ["CRASH REPORT ", format_crash_report(Self, Neighbours)]);
  71. {warning_msg, _GL, {Pid, Fmt, Args}} ->
  72. ?LOG(warning, Pid, Fmt, Args);
  73. {warning_report, _GL, {Pid, std_warning, Report}} ->
  74. ?LOG(warning, Pid, print_silly_list(Report));
  75. {warning_report, _GL, {_Pid, _Type, _Report}} ->
  76. %% ignore, non standard warning type
  77. ok;
  78. {info_msg, _GL, {Pid, Fmt, Args}} ->
  79. ?LOG(info, Pid, Fmt, Args);
  80. {info_report, _GL, {Pid, std_info, D}} ->
  81. Details = lists:sort(D),
  82. case Details of
  83. [{application, App}, {exited, Reason}, {type, _Type}] ->
  84. ?LOG(info, Pid, "Application ~w exited with reason: ~w", [App, Reason]);
  85. _ ->
  86. ?LOG(info, Pid, print_silly_list(D))
  87. end;
  88. {info_report, _GL, {P, progress, D}} ->
  89. Details = lists:sort(D),
  90. case Details of
  91. [{application, App}, {started_at, Node}] ->
  92. ?LOG(info, P, "Application ~w started on node ~w",
  93. [App, Node]);
  94. [{started, Started}, {supervisor, Name}] ->
  95. MFA = format_mfa(proplists:get_value(mfargs, Started)),
  96. Pid = proplists:get_value(pid, Started),
  97. ?LOG(info, P, "Supervisor ~w started ~s at pid ~w", [element(2, Name), MFA, Pid]);
  98. _ ->
  99. ?LOG(info, P, ["PROGRESS REPORT ", print_silly_list(D)])
  100. end;
  101. _ ->
  102. ?LOG(warning, self(), "Unexpected error_logger event ~w", [Event])
  103. end,
  104. {ok, State}.
  105. handle_info(_Info, State) ->
  106. {ok, State}.
  107. terminate(_Reason, _State) ->
  108. ok.
  109. code_change(_OldVsn, State, _Extra) ->
  110. {ok, State}.
  111. %% internal functions
  112. format_crash_report(Report, Neighbours) ->
  113. Name = proplists:get_value(registered_name, Report, proplists:get_value(pid, Report)),
  114. {_Class, Reason, _Trace} = proplists:get_value(error_info, Report),
  115. io_lib:format("Process ~w with ~w neighbours crashed with reason: ~s", [Name, length(Neighbours), format_reason(Reason)]).
  116. format_offender(Off) ->
  117. case proplists:get_value(name, Off) of
  118. undefined ->
  119. %% supervisor_bridge
  120. io_lib:format("at module ~w at ~w", [proplists:get_value(mod, Off), proplists:get_value(pid, Off)]);
  121. Name ->
  122. %% regular supervisor
  123. MFA = format_mfa(proplists:get_value(mfargs, Off)),
  124. io_lib:format("~w started with ~s at ~w", [Name, MFA, proplists:get_value(pid, Off)])
  125. end.
  126. format_reason({'function not exported', [{M, F, A},MFA|_]}) ->
  127. ["call to undefined function ", format_mfa({M, F, length(A)}), " from ", format_mfa(MFA)];
  128. format_reason({undef, [MFA|_]}) ->
  129. ["call to undefined function ", format_mfa(MFA)];
  130. format_reason({bad_return_value, Val}) ->
  131. io_lib:format("bad return value: ~w", [Val]);
  132. format_reason({{case_clause, Val}, [MFA|_]}) ->
  133. [io_lib:format("no case clause matching ~w in ", [Val]), format_mfa(MFA)];
  134. format_reason({function_clause, [MFA|_]}) ->
  135. ["no function clause matching ", format_mfa(MFA)];
  136. format_reason({if_clause, [MFA|_]}) ->
  137. ["no true branch found while evaluating if expression in ", format_mfa(MFA)];
  138. format_reason({{try_clause, Val}, [MFA|_]}) ->
  139. [io_lib:format("no try clause matching ~w in ", [Val]), format_mfa(MFA)];
  140. format_reason({badarith, [MFA|_]}) ->
  141. ["bad arithmetic expression in ", format_mfa(MFA)];
  142. format_reason({{badmatch, Val}, [MFA|_]}) ->
  143. [io_lib:format("no match of right hand value ~w in ", [Val]), format_mfa(MFA)];
  144. %format_reason({system_limit,
  145. format_reason({badarg, [MFA,MFA2|_]}) ->
  146. case MFA of
  147. {_M, _F, A} when is_list(A) ->
  148. ["bad argument in call to ", format_mfa(MFA), " in ", format_mfa(MFA2)];
  149. _ ->
  150. %% seems to be generated by a bad call to a BIF
  151. ["bad argument in ", format_mfa(MFA)]
  152. end;
  153. format_reason({{badarity, {Fun, Args}}, [MFA|_]}) ->
  154. {arity, Arity} = lists:keyfind(arity, 1, erlang:fun_info(Fun)),
  155. [io_lib:format("fun called with wrong arity of ~w instead of ~w in ", [length(Args), Arity]), format_mfa(MFA)];
  156. format_reason({noproc, MFA}) ->
  157. ["no such process or port in call to ", format_mfa(MFA)];
  158. format_reason({{badfun, Term}, [MFA|_]}) ->
  159. [io_lib:format("bad function ~w in ", [Term]), format_mfa(MFA)];
  160. format_reason(Reason) ->
  161. {Str, _} = trunc_io:print(Reason, 500),
  162. Str.
  163. format_mfa({M, F, A}) when is_list(A) ->
  164. io_lib:format("~w:~w("++string:join(lists:duplicate(length(A), "~w"), ", ")++")", [M, F | A]);
  165. format_mfa({M, F, A}) when is_integer(A) ->
  166. io_lib:format("~w:~w/~w", [M, F, A]);
  167. format_mfa(Other) ->
  168. io_lib:format("~w", [Other]).
  169. print_silly_list(L) ->
  170. case lager_stdlib:string_p(L) of
  171. true -> L;
  172. _ -> print_silly_list(L, [], [])
  173. end.
  174. print_silly_list([], Fmt, Acc) ->
  175. io_lib:format(string:join(lists:reverse(Fmt), ", "), lists:reverse(Acc));
  176. print_silly_list([{K,V}|T], Fmt, Acc) ->
  177. print_silly_list(T, ["~w: ~w" | Fmt], [V, K | Acc]);
  178. print_silly_list([H|T], Fmt, Acc) ->
  179. print_silly_list(T, ["~w" | Fmt], [H | Acc]).