blob: c6d7074f198b3fe405cfd2e82e8df81d158be3f0 [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
Christopher Piro6c46f1a2007-10-23 09:47:15 +000022-record(state, {}).
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([]) ->
Christopher Piro6c46f1a2007-10-23 09:47:15 +000051 State = #state{},
Christopher Piro5b3a8f72007-08-01 22:27:37 +000052 {ok, State}.
53
Christopher Pirode11d852007-11-18 02:10:20 +000054%%%
55%%% handle_event
56%%%
57
Christopher Piro5b3a8f72007-08-01 22:27:37 +000058handle_event2(Symbol, Pid, Type, Message, State) -> % Message must be a string
59 {ok, MessageSafe, NL} = regexp:gsub(Message, "[\n]+", " "), % collapse whitespace to one space
60
61 Type1 =
Christopher Piroc2e37c72007-11-15 06:26:30 +000062 case Type of
63 "" -> "";
64 _ -> sformat("~p ", [Type])
65 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +000066
Christopher Piro3b63fe42007-10-19 21:34:31 +000067 Banner =
Christopher Piro6c46f1a2007-10-23 09:47:15 +000068 case config(show_pid) of
Christopher Piro3b63fe42007-10-19 21:34:31 +000069 true ->
70 sformat("~s ~s ~s", [Symbol, Pid, Type1]);
71 false ->
72 sformat("~s~i ~s", [Symbol, Pid, Type1])
73 end,
74 BannerLen = length(Banner),
75
76 %% there's no way to see if Message is a string? just try
77 Output = sformat("~s", [Message]),
78 OutputSafe = sformat("~s", [MessageSafe]),
Christopher Piro5b3a8f72007-08-01 22:27:37 +000079
80 Length =
Christopher Piroc2e37c72007-11-15 06:26:30 +000081 case (length(OutputSafe) + BannerLen) < config(term_width) of
82 true -> short;
83 false -> long
84 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +000085
86 OneLine =
Christopher Piroc2e37c72007-11-15 06:26:30 +000087 case NL == 0 of
88 true -> oneliner;
89 false -> multiline
90 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +000091
Christopher Piro6c46f1a2007-10-23 09:47:15 +000092 case { config(force_one_line), Length, OneLine } of
Christopher Piroc2e37c72007-11-15 06:26:30 +000093 %% one line and short ... print as is
94 {_, short, oneliner} ->
95 format("~s~s~n", [Banner, OutputSafe]);
Christopher Piro5b3a8f72007-08-01 22:27:37 +000096
Christopher Piroc2e37c72007-11-15 06:26:30 +000097 %% too long ... squash to one
98 {true, long, _} ->
99 O = Banner ++ OutputSafe,
100 Format = sformat("~~~ps >~n", [config(term_width)-2]), % e.g. "~80s >~n"
101 format(Format, [O]);
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000102
Christopher Piroc2e37c72007-11-15 06:26:30 +0000103 %% short but multiline... collapse to one
104 {true, short, multiline} ->
105 format("~s~s~n", [Banner, OutputSafe]);
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000106
Christopher Piroc2e37c72007-11-15 06:26:30 +0000107 %% just print it
108 _ ->
109 format("~s~n~s~n~n", [Banner, Output])
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000110 end.
111
112%%
Christopher Piro524c3ec2007-10-13 05:15:33 +0000113
Christopher Piroefd5eec2007-10-02 01:33:37 +0000114handle_event1({What, _Gleader, {Ref, Format, Data}}, State) when is_list(Format) ->
Christopher Piro10522a72007-11-15 06:26:31 +0000115 Symbol =
116 case What of
117 error -> "!!";
118 warning_msg -> "**";
119 info_msg -> "..";
120 _Else -> "??"
121 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000122
Christopher Piro524c3ec2007-10-13 05:15:33 +0000123 case {Format, Data} of
Christopher Pirode11d852007-11-18 02:10:20 +0000124 {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, {Kind, E}]} when Kind == timeout; Kind == thrift_exception ->
125 ok;
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000126
Christopher Pirode11d852007-11-18 02:10:20 +0000127 {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, Reason]} ->
128 Format1 = "** gen_server terminating in message ~p~n** State = ~s~n** Reason = ~p~n",
129 Message = sformat(Format1, [LastMessage, oop:inspect(Obj), Reason]),
130 handle_event2(Symbol, Ref, "", Message, State);
131
Christopher Piroc2e37c72007-11-15 06:26:30 +0000132 {?GS_TERM_FORMAT, _Dta} ->
133 Message = sformat("DATA DIDN'T MATCH: ~p~n", [Data]) ++ sformat(Format, Data),
134 handle_event2(Symbol, Ref, "", Message, State);
135 {_, _} ->
136 case lists:member(Format, config(omit_fmt)) of
137 false ->
138 Message = sformat(Format, Data),
139 handle_event2(Symbol, Ref, "", Message, State);
140 true ->
141 ok
142 end
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000143 end,
144 {ok, State};
145
146handle_event1({What, _Gleader, {Pid, Type, Report}}, State) ->
Christopher Piro10522a72007-11-15 06:26:31 +0000147 Symbol =
148 case What of
149 error_report -> "!!";
150 warning_report -> "**";
151 info_report -> "..";
152 _Else -> "??"
153 end,
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000154
155 case Type of
Christopher Piro3b63fe42007-10-19 21:34:31 +0000156 crash_report ->
Christopher Piroc2e37c72007-11-15 06:26:30 +0000157 print_crash_report(Report);
Christopher Piro3b63fe42007-10-19 21:34:31 +0000158 progress ->
Christopher Piroc2e37c72007-11-15 06:26:30 +0000159 ok;
160 _ ->
161 Message = sformat("|| ~s", [oop:inspect(Report)]),
162 handle_event2(Symbol, Pid, Type, Message, State)
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000163 end,
164 {ok, State};
165
166handle_event1(_Event, State) ->
167 handle_event2("??", "<?.?.?>", "", _Event, State),
168 {ok, State}.
169
170handle_event(Event, State) ->
171 try
Christopher Piroc2e37c72007-11-15 06:26:30 +0000172 handle_event1(Event, State)
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000173 catch
Christopher Piroc2e37c72007-11-15 06:26:30 +0000174 _:E ->
175 format("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n error logger error:~n ~p~n Event = ~p~n State = ~p~n ~p~n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n",
176 [E, Event, State, erlang:get_stacktrace()]),
177 {ok, State}
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000178 end.
179
Christopher Pirode11d852007-11-18 02:10:20 +0000180%%%
181%%% call, info, terminate, code_change
182%%%
183
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000184handle_call(_Request, State) ->
185 Reply = ok,
186 {ok, Reply, State}.
187
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000188handle_info(_Info, State) ->
189 {ok, State}.
190
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000191terminate(normal, _State) ->
192 ok;
193terminate(Reason, _State) ->
194 format("*****************~n~n frick, error logger terminating: ~p~n~n*****************~n~n", [Reason]),
195 ok.
196
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000197code_change(_OldVsn, State, _Extra) ->
198 {ok, State}.
199
200%%====================================================================
201%%% Internal functions
202%%====================================================================
Christopher Piro68940292007-10-02 00:35:12 +0000203
204%% how to output
205format(Format, Data) ->
206 io:format(Format, Data).
207
208%% convenience
209sformat(Format, Data) ->
210 thrift_utils:sformat(Format, Data).
211
Christopher Piro6c46f1a2007-10-23 09:47:15 +0000212config(Item) ->
213 thrift:config(Item).
Christopher Piro3b63fe42007-10-19 21:34:31 +0000214
Christopher Piroc2e37c72007-11-15 06:26:30 +0000215print_crash_report(Report) ->
Christopher Piro3b63fe42007-10-19 21:34:31 +0000216 case Report of
Christopher Piroa89cd7b2007-12-19 00:00:39 +0000217 %% for R12B0
218 [[_, _, {error_info, {exit, {thrift_exception, _}, _}} | _] | _] ->
219 ok;
220 [[_, _, {error_info, {exit, {timeout, _}, _}} | _] | _] ->
221 ok;
222
223 %% for R11B5
Christopher Pirode11d852007-11-18 02:10:20 +0000224 [[_,_,{error_info, {thrift_exception, _}}|_] | _] ->
225 ok;
226 [[_,_,{error_info, {timeout, _}}|_] | _] ->
227 ok;
Christopher Piroa89cd7b2007-12-19 00:00:39 +0000228
229 %% else
Christopher Piro3b63fe42007-10-19 21:34:31 +0000230 _ ->
Christopher Pirode11d852007-11-18 02:10:20 +0000231 io:format("~~~~ crash report: ~w~n", [Report])
Christopher Piro3b63fe42007-10-19 21:34:31 +0000232 end.