blob: bf1f54b76aac15a8a36c0e28cf25a3ffe8e565cd [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
Christopher Piro6c46f1a2007-10-23 09:47:15 +000018-export([install/0]).
19
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
eletuchyefe64a62008-02-27 16:31:01 +0000115bin_trim(L) when is_list(L) ->
116 lists:map(fun bin_trim/1, L);
117bin_trim(T) when is_tuple(T) ->
118 list_to_tuple(bin_trim(tuple_to_list(T)));
119bin_trim(Bin) when is_binary(Bin), size(Bin) > 100 ->
120 {Bin1,Rest} = split_binary(Bin, 100),
121 Bin1;
122bin_trim(Term) ->
123 Term.
124
eletuchy57fd32c2008-02-27 17:43:40 +0000125handle_event1({What, _Gleader, {Ref, Format, Data}}, State = #state{omit_formats=OmitFormats})
126 when is_list(Format) ->
Christopher Piro10522a72007-11-15 06:26:31 +0000127 Symbol =
128 case What of
129 error -> "!!";
130 warning_msg -> "**";
131 info_msg -> "..";
132 _Else -> "??"
133 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000134
Christopher Piro524c3ec2007-10-13 05:15:33 +0000135 case {Format, Data} of
Christopher Pirode11d852007-11-18 02:10:20 +0000136 {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, {Kind, E}]} when Kind == timeout; Kind == thrift_exception ->
137 ok;
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000138
Christopher Pirode11d852007-11-18 02:10:20 +0000139 {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, Reason]} ->
140 Format1 = "** gen_server terminating in message ~p~n** State = ~s~n** Reason = ~p~n",
eletuchyefe64a62008-02-27 16:31:01 +0000141 Message = sformat(Format1, [LastMessage, bin_trim(oop:inspect(Obj)), Reason]),
Christopher Pirode11d852007-11-18 02:10:20 +0000142 handle_event2(Symbol, Ref, "", Message, State);
143
Christopher Piroc2e37c72007-11-15 06:26:30 +0000144 {?GS_TERM_FORMAT, _Dta} ->
eletuchyefe64a62008-02-27 16:31:01 +0000145 TrimData = bin_trim(Data),
146 Message = sformat("DATA DIDN'T MATCH: ~p~n", [TrimData]) ++ sformat(Format, TrimData),
Christopher Piroc2e37c72007-11-15 06:26:30 +0000147 handle_event2(Symbol, Ref, "", Message, State);
148 {_, _} ->
eletuchy57fd32c2008-02-27 17:43:40 +0000149 case gb_sets:is_member(Format, OmitFormats) of
150 true ->
151 ok;
Christopher Piroc2e37c72007-11-15 06:26:30 +0000152 false ->
eletuchyefe64a62008-02-27 16:31:01 +0000153 Message = sformat(Format, bin_trim(Data)),
eletuchy57fd32c2008-02-27 17:43:40 +0000154 handle_event2(Symbol, Ref, "", Message, State)
Christopher Piroc2e37c72007-11-15 06:26:30 +0000155 end
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000156 end,
157 {ok, State};
158
159handle_event1({What, _Gleader, {Pid, Type, Report}}, State) ->
Christopher Piro10522a72007-11-15 06:26:31 +0000160 Symbol =
161 case What of
162 error_report -> "!!";
163 warning_report -> "**";
164 info_report -> "..";
165 _Else -> "??"
166 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000167
168 case Type of
Christopher Piro3b63fe42007-10-19 21:34:31 +0000169 crash_report ->
Christopher Piroc2e37c72007-11-15 06:26:30 +0000170 print_crash_report(Report);
Christopher Piro3b63fe42007-10-19 21:34:31 +0000171 progress ->
Christopher Piroc2e37c72007-11-15 06:26:30 +0000172 ok;
173 _ ->
174 Message = sformat("|| ~s", [oop:inspect(Report)]),
175 handle_event2(Symbol, Pid, Type, Message, State)
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000176 end,
177 {ok, State};
178
179handle_event1(_Event, State) ->
180 handle_event2("??", "<?.?.?>", "", _Event, State),
181 {ok, State}.
182
183handle_event(Event, State) ->
184 try
Christopher Piroc2e37c72007-11-15 06:26:30 +0000185 handle_event1(Event, State)
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000186 catch
Christopher Piroc2e37c72007-11-15 06:26:30 +0000187 _:E ->
188 format("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n error logger error:~n ~p~n Event = ~p~n State = ~p~n ~p~n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n",
189 [E, Event, State, erlang:get_stacktrace()]),
190 {ok, State}
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000191 end.
192
Christopher Pirode11d852007-11-18 02:10:20 +0000193%%%
194%%% call, info, terminate, code_change
195%%%
196
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000197handle_call(_Request, State) ->
198 Reply = ok,
199 {ok, Reply, State}.
200
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000201handle_info(_Info, State) ->
202 {ok, State}.
203
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000204terminate(normal, _State) ->
205 ok;
206terminate(Reason, _State) ->
207 format("*****************~n~n frick, error logger terminating: ~p~n~n*****************~n~n", [Reason]),
208 ok.
209
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000210code_change(_OldVsn, State, _Extra) ->
211 {ok, State}.
212
213%%====================================================================
214%%% Internal functions
215%%====================================================================
Christopher Piro68940292007-10-02 00:35:12 +0000216
217%% how to output
218format(Format, Data) ->
219 io:format(Format, Data).
220
221%% convenience
222sformat(Format, Data) ->
223 thrift_utils:sformat(Format, Data).
224
Christopher Piro6c46f1a2007-10-23 09:47:15 +0000225config(Item) ->
226 thrift:config(Item).
Christopher Piro3b63fe42007-10-19 21:34:31 +0000227
Christopher Piroc2e37c72007-11-15 06:26:30 +0000228print_crash_report(Report) ->
Christopher Piro3b63fe42007-10-19 21:34:31 +0000229 case Report of
Christopher Piroa89cd7b2007-12-19 00:00:39 +0000230 %% for R12B0
231 [[_, _, {error_info, {exit, {thrift_exception, _}, _}} | _] | _] ->
232 ok;
233 [[_, _, {error_info, {exit, {timeout, _}, _}} | _] | _] ->
234 ok;
235
236 %% for R11B5
Christopher Pirode11d852007-11-18 02:10:20 +0000237 [[_,_,{error_info, {thrift_exception, _}}|_] | _] ->
238 ok;
239 [[_,_,{error_info, {timeout, _}}|_] | _] ->
240 ok;
Christopher Piroa89cd7b2007-12-19 00:00:39 +0000241
242 %% else
Christopher Piro3b63fe42007-10-19 21:34:31 +0000243 _ ->
Christopher Pirode11d852007-11-18 02:10:20 +0000244 io:format("~~~~ crash report: ~w~n", [Report])
Christopher Piro3b63fe42007-10-19 21:34:31 +0000245 end.