blob: e9963c0263fc2e6b0951f2241d66afa01801ad52 [file] [log] [blame]
Christopher Piro5b3a8f72007-08-01 22:27:37 +00001%%% Copyright (c) 2007- Facebook
2%%% Distributed under the Thrift Software License
Christopher Piroc2e37c72007-11-15 06:26:30 +00003%%%
Christopher Piro5b3a8f72007-08-01 22:27:37 +00004%%% See accompanying file LICENSE or visit the Thrift site at:
5%%% http://developers.facebook.com/thrift/
6
7-module(thrift_logger).
8
9-behaviour(gen_event).
10
Christopher Pirofa0c8572007-08-11 01:15:57 +000011-include("thrift.hrl").
12-include("oop.hrl").
Christopher Pirofa0c8572007-08-11 01:15:57 +000013
Christopher Piro5b3a8f72007-08-01 22:27:37 +000014%% gen_event callbacks
Christopher Piroc2e37c72007-11-15 06:26:30 +000015-export([init/1, handle_event/2, handle_call/2,
Christopher Piro5b3a8f72007-08-01 22:27:37 +000016 handle_info/2, terminate/2, code_change/3]).
17
eletuchy6f3507c2008-02-27 23:50:21 +000018-export([install/0, bin_trim/1]).
Christopher Piro6c46f1a2007-10-23 09:47:15 +000019
Christopher Piroc2e37c72007-11-15 06:26:30 +000020%%
21
eletuchy57fd32c2008-02-27 17:43:40 +000022-record(state, {omit_formats=gb_sets:empty()}).
Christopher Piro5b3a8f72007-08-01 22:27:37 +000023
Christopher Piroc2e37c72007-11-15 06:26:30 +000024-define(GS_TERM_FORMAT, "** Generic server ~p terminating \n** Last message in was ~p~n** When Server state == ~p~n** Reason for termination == ~n** ~p~n").
25
Christopher Pirode11d852007-11-18 02:10:20 +000026%%%
27%%% ensure the regular logger is out and ours is in
28%%%
Christopher Piroc2e37c72007-11-15 06:26:30 +000029
Christopher Piro5b3a8f72007-08-01 22:27:37 +000030install() ->
Christopher Piro5b3a8f72007-08-01 22:27:37 +000031 %% remove loggers
Christopher Piro68940292007-10-02 00:35:12 +000032 io:format("starting logger~n"),
Christopher Piro5b3a8f72007-08-01 22:27:37 +000033 lists:foreach(fun(Logger) ->
34 case Logger of
35 _ -> gen_event:delete_handler(error_logger, Logger, normal)
36 end end,
37 gen_event:which_handlers(error_logger)),
38
39 %% TODO(cpiro): sasl someday?
40 %% gen_event:add_handler(error_logger, sasl_report_file_h, {LogFile, all}),
Christopher Piro5b3a8f72007-08-01 22:27:37 +000041
Christopher Piro68940292007-10-02 00:35:12 +000042 gen_event:add_handler(error_logger, ?MODULE, []),
Christopher Piro5b3a8f72007-08-01 22:27:37 +000043
Christopher Piro68940292007-10-02 00:35:12 +000044 ok.
45
Christopher Pirode11d852007-11-18 02:10:20 +000046%%%
47%%% init
48%%%
49
Christopher Piro5b3a8f72007-08-01 22:27:37 +000050init([]) ->
eletuchy57fd32c2008-02-27 17:43:40 +000051 OmitFormats = gb_sets:from_list(config(omit_fmt)),
52 State = #state{omit_formats = OmitFormats},
Christopher Piro5b3a8f72007-08-01 22:27:37 +000053 {ok, State}.
54
Christopher Pirode11d852007-11-18 02:10:20 +000055%%%
56%%% handle_event
57%%%
58
Christopher Piro5b3a8f72007-08-01 22:27:37 +000059handle_event2(Symbol, Pid, Type, Message, State) -> % Message must be a string
60 {ok, MessageSafe, NL} = regexp:gsub(Message, "[\n]+", " "), % collapse whitespace to one space
61
62 Type1 =
Christopher Piroc2e37c72007-11-15 06:26:30 +000063 case Type of
64 "" -> "";
65 _ -> sformat("~p ", [Type])
66 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +000067
Christopher Piro3b63fe42007-10-19 21:34:31 +000068 Banner =
Christopher Piro6c46f1a2007-10-23 09:47:15 +000069 case config(show_pid) of
Christopher Piro3b63fe42007-10-19 21:34:31 +000070 true ->
Christopher Piro21db52d2008-01-14 05:54:50 +000071 sformat("~s ~p ~s", [Symbol, Pid, Type1]);
Christopher Piro3b63fe42007-10-19 21:34:31 +000072 false ->
73 sformat("~s~i ~s", [Symbol, Pid, Type1])
74 end,
75 BannerLen = length(Banner),
76
77 %% there's no way to see if Message is a string? just try
78 Output = sformat("~s", [Message]),
79 OutputSafe = sformat("~s", [MessageSafe]),
Christopher Piro5b3a8f72007-08-01 22:27:37 +000080
81 Length =
Christopher Piroc2e37c72007-11-15 06:26:30 +000082 case (length(OutputSafe) + BannerLen) < config(term_width) of
83 true -> short;
84 false -> long
85 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +000086
87 OneLine =
Christopher Piroc2e37c72007-11-15 06:26:30 +000088 case NL == 0 of
89 true -> oneliner;
90 false -> multiline
91 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +000092
Christopher Piro6c46f1a2007-10-23 09:47:15 +000093 case { config(force_one_line), Length, OneLine } of
Christopher Piroc2e37c72007-11-15 06:26:30 +000094 %% one line and short ... print as is
95 {_, short, oneliner} ->
96 format("~s~s~n", [Banner, OutputSafe]);
Christopher Piro5b3a8f72007-08-01 22:27:37 +000097
Christopher Piroc2e37c72007-11-15 06:26:30 +000098 %% too long ... squash to one
99 {true, long, _} ->
100 O = Banner ++ OutputSafe,
101 Format = sformat("~~~ps >~n", [config(term_width)-2]), % e.g. "~80s >~n"
102 format(Format, [O]);
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000103
Christopher Piroc2e37c72007-11-15 06:26:30 +0000104 %% short but multiline... collapse to one
105 {true, short, multiline} ->
106 format("~s~s~n", [Banner, OutputSafe]);
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000107
Christopher Piroc2e37c72007-11-15 06:26:30 +0000108 %% just print it
109 _ ->
110 format("~s~n~s~n~n", [Banner, Output])
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000111 end.
112
113%%
Christopher Piro524c3ec2007-10-13 05:15:33 +0000114
eletuchy6f3507c2008-02-27 23:50:21 +0000115bin_trim([]) ->
116 [];
117bin_trim([H|T]) ->
118 [bin_trim(H) | bin_trim(T)];
119bin_trim({}) ->
120 {};
eletuchyefe64a62008-02-27 16:31:01 +0000121bin_trim(T) when is_tuple(T) ->
122 list_to_tuple(bin_trim(tuple_to_list(T)));
123bin_trim(Bin) when is_binary(Bin), size(Bin) > 100 ->
124 {Bin1,Rest} = split_binary(Bin, 100),
125 Bin1;
126bin_trim(Term) ->
127 Term.
128
eletuchy57fd32c2008-02-27 17:43:40 +0000129handle_event1({What, _Gleader, {Ref, Format, Data}}, State = #state{omit_formats=OmitFormats})
130 when is_list(Format) ->
Christopher Piro10522a72007-11-15 06:26:31 +0000131 Symbol =
132 case What of
133 error -> "!!";
134 warning_msg -> "**";
135 info_msg -> "..";
136 _Else -> "??"
137 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000138
Christopher Piro524c3ec2007-10-13 05:15:33 +0000139 case {Format, Data} of
Christopher Pirode11d852007-11-18 02:10:20 +0000140 {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, {Kind, E}]} when Kind == timeout; Kind == thrift_exception ->
141 ok;
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000142
Christopher Pirode11d852007-11-18 02:10:20 +0000143 {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, Reason]} ->
144 Format1 = "** gen_server terminating in message ~p~n** State = ~s~n** Reason = ~p~n",
eletuchyefe64a62008-02-27 16:31:01 +0000145 Message = sformat(Format1, [LastMessage, bin_trim(oop:inspect(Obj)), Reason]),
Christopher Pirode11d852007-11-18 02:10:20 +0000146 handle_event2(Symbol, Ref, "", Message, State);
147
Christopher Piroc2e37c72007-11-15 06:26:30 +0000148 {?GS_TERM_FORMAT, _Dta} ->
eletuchyefe64a62008-02-27 16:31:01 +0000149 TrimData = bin_trim(Data),
150 Message = sformat("DATA DIDN'T MATCH: ~p~n", [TrimData]) ++ sformat(Format, TrimData),
Christopher Piroc2e37c72007-11-15 06:26:30 +0000151 handle_event2(Symbol, Ref, "", Message, State);
152 {_, _} ->
eletuchy57fd32c2008-02-27 17:43:40 +0000153 case gb_sets:is_member(Format, OmitFormats) of
154 true ->
155 ok;
Christopher Piroc2e37c72007-11-15 06:26:30 +0000156 false ->
eletuchyefe64a62008-02-27 16:31:01 +0000157 Message = sformat(Format, bin_trim(Data)),
eletuchy57fd32c2008-02-27 17:43:40 +0000158 handle_event2(Symbol, Ref, "", Message, State)
Christopher Piroc2e37c72007-11-15 06:26:30 +0000159 end
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000160 end,
161 {ok, State};
162
163handle_event1({What, _Gleader, {Pid, Type, Report}}, State) ->
Christopher Piro10522a72007-11-15 06:26:31 +0000164 Symbol =
165 case What of
166 error_report -> "!!";
167 warning_report -> "**";
168 info_report -> "..";
169 _Else -> "??"
170 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000171
172 case Type of
Christopher Piro3b63fe42007-10-19 21:34:31 +0000173 crash_report ->
Christopher Piroc2e37c72007-11-15 06:26:30 +0000174 print_crash_report(Report);
Christopher Piro3b63fe42007-10-19 21:34:31 +0000175 progress ->
Christopher Piroc2e37c72007-11-15 06:26:30 +0000176 ok;
177 _ ->
178 Message = sformat("|| ~s", [oop:inspect(Report)]),
179 handle_event2(Symbol, Pid, Type, Message, State)
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000180 end,
181 {ok, State};
182
183handle_event1(_Event, State) ->
184 handle_event2("??", "<?.?.?>", "", _Event, State),
185 {ok, State}.
186
187handle_event(Event, State) ->
188 try
Christopher Piroc2e37c72007-11-15 06:26:30 +0000189 handle_event1(Event, State)
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000190 catch
Christopher Piroc2e37c72007-11-15 06:26:30 +0000191 _:E ->
192 format("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n error logger error:~n ~p~n Event = ~p~n State = ~p~n ~p~n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n",
193 [E, Event, State, erlang:get_stacktrace()]),
194 {ok, State}
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000195 end.
196
Christopher Pirode11d852007-11-18 02:10:20 +0000197%%%
198%%% call, info, terminate, code_change
199%%%
200
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000201handle_call(_Request, State) ->
202 Reply = ok,
203 {ok, Reply, State}.
204
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000205handle_info(_Info, State) ->
206 {ok, State}.
207
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000208terminate(normal, _State) ->
209 ok;
210terminate(Reason, _State) ->
211 format("*****************~n~n frick, error logger terminating: ~p~n~n*****************~n~n", [Reason]),
212 ok.
213
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000214code_change(_OldVsn, State, _Extra) ->
215 {ok, State}.
216
217%%====================================================================
218%%% Internal functions
219%%====================================================================
Christopher Piro68940292007-10-02 00:35:12 +0000220
221%% how to output
222format(Format, Data) ->
223 io:format(Format, Data).
224
225%% convenience
226sformat(Format, Data) ->
227 thrift_utils:sformat(Format, Data).
228
Christopher Piro6c46f1a2007-10-23 09:47:15 +0000229config(Item) ->
230 thrift:config(Item).
Christopher Piro3b63fe42007-10-19 21:34:31 +0000231
Christopher Piroc2e37c72007-11-15 06:26:30 +0000232print_crash_report(Report) ->
Christopher Piro3b63fe42007-10-19 21:34:31 +0000233 case Report of
Christopher Piroa89cd7b2007-12-19 00:00:39 +0000234 %% for R12B0
235 [[_, _, {error_info, {exit, {thrift_exception, _}, _}} | _] | _] ->
236 ok;
237 [[_, _, {error_info, {exit, {timeout, _}, _}} | _] | _] ->
238 ok;
239
240 %% for R11B5
Christopher Pirode11d852007-11-18 02:10:20 +0000241 [[_,_,{error_info, {thrift_exception, _}}|_] | _] ->
242 ok;
243 [[_,_,{error_info, {timeout, _}}|_] | _] ->
244 ok;
Christopher Piroa89cd7b2007-12-19 00:00:39 +0000245
246 %% else
Christopher Piro3b63fe42007-10-19 21:34:31 +0000247 _ ->
Christopher Pirode11d852007-11-18 02:10:20 +0000248 io:format("~~~~ crash report: ~w~n", [Report])
Christopher Piro3b63fe42007-10-19 21:34:31 +0000249 end.