[thrift] gut Erlang exception handling

Summary: * move type field to tException from subclasses
          * add backtrace to tException
          * add oop:is_a
          * on exit, wrap exceptions in {thrift_exception, E} ... otherwise can't distinguish e.g. exit:{{tBinProtException, {tException, ...}}, Stack} vs. exit:{tBinProtException, {tException, ...} -- I hate erlang
          * all throws/exits to tException:throw which does the wrapping described above

Reviewed By: eletuchy

Test Plan: been using this code on my live server ^_^

Revert: OK


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665350 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/erl/src/thrift_logger.erl b/lib/erl/src/thrift_logger.erl
index 0d0b876..c8fb49a 100644
--- a/lib/erl/src/thrift_logger.erl
+++ b/lib/erl/src/thrift_logger.erl
@@ -8,14 +8,8 @@
 
 -behaviour(gen_event).
 
-%% TODO(cpiro): either
-%% make exceptions know whether they need to be displayed
-%% or not exit with tExecptions for non-errors
-%% or "register" tExceptions with the logger (I LIKE!)
-%% ... we shouldn't need to build any specifics in here
 -include("thrift.hrl").
 -include("oop.hrl").
--include("transport/tTransportException.hrl").
 
 %% gen_event callbacks
 -export([init/1, handle_event/2, handle_call/2,
@@ -29,9 +23,10 @@
 
 -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").
 
-%%
+%%%
+%%% ensure the regular logger is out and ours is in
+%%%
 
-%% ensure the regular logger is out and ours is in
 install() ->
     %% remove loggers
     io:format("starting logger~n"),
@@ -48,32 +43,18 @@
 
     ok.
 
-%%====================================================================
-%% gen_event callbacks
-%%====================================================================
-%%--------------------------------------------------------------------
-%% @spec init(Args) -> {ok, State}.
-%%
-%% @doc
-%% Whenever a new event handler is added to an event manager,
-%% this function is called to initialize the event handler.
-%% @end
-%%--------------------------------------------------------------------
+%%%
+%%% init
+%%%
+
 init([]) ->
     State = #state{},
     {ok, State}.
 
-%%--------------------------------------------------------------------
-%% @spec  handle_event(Event, State) -> {ok, State} |
-%%                               {swap_handler, Args1, State1, Mod2, Args2} |
-%%                               remove_handler.
-%%
-%% @doc
-%% Whenever an event manager receives an event sent using
-%% gen_event:notify/2 or gen_event:sync_notify/2, this function is called for
-%% each installed event handler to handle the event.
-%% @end
-%%--------------------------------------------------------------------
+%%%
+%%% handle_event
+%%%
+
 handle_event2(Symbol, Pid, Type, Message, State) -> % Message must be a string
     {ok, MessageSafe, NL} = regexp:gsub(Message, "[\n]+", " "), % collapse whitespace to one space
 
@@ -140,31 +121,14 @@
         end,
 
     case {Format, Data} of
-        {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, Reason]} ->
-            %% TODO: move as much logic as possible out of thrift_logger
-            Ignore =
-                begin
-                    is_tuple(Reason) andalso
-                        size(Reason) >= 1 andalso element(1, Reason) == timeout
-                end
-                orelse
-                begin
-                    case thrift_utils:unnest_record(Reason, tTransportException) of
-                        error -> false;
-                        {ok, TTE} ->
-                            oop:get(TTE, type) == ?tTransportException_NOT_OPEN andalso
-                                oop:get(TTE, message) == "in tSocket:read/2: gen_tcp:recv"
-                    end
-                end,
+        {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, {Kind, E}]} when Kind == timeout; Kind == thrift_exception ->
+            ok;
 
-            case Ignore of
-                true ->
-                    ok;
-                false ->
-                    Format1 = "** gen_server terminating in message ~p~n** State  = ~s~n** Reason = ~s~n",
-                    Message = sformat(Format1, [LastMessage, oop:inspect(Obj), oop:inspect(Reason)]), %% TODO(cpiro): hope Reason is an object?
-                    handle_event2(Symbol, Ref, "", Message, State)
-            end;
+        {?GS_TERM_FORMAT, [Ref, LastMessage, Obj, Reason]} ->
+            Format1 = "** gen_server terminating in message ~p~n** State  = ~s~n** Reason = ~p~n",
+            Message = sformat(Format1, [LastMessage, oop:inspect(Obj), Reason]),
+            handle_event2(Symbol, Ref, "", Message, State);
+
         {?GS_TERM_FORMAT, _Dta} ->
             Message = sformat("DATA DIDN'T MATCH: ~p~n", [Data]) ++ sformat(Format, Data),
             handle_event2(Symbol, Ref, "", Message, State);
@@ -213,58 +177,23 @@
             {ok, State}
     end.
 
-%%--------------------------------------------------------------------
-%% @spec handle_call(Request, State) -> {ok, Reply, State} |
-%%                                {swap_handler, Reply, Args1, State1,
-%%                                  Mod2, Args2} |
-%%                                {remove_handler, Reply}.
-%%
-%% @doc
-%% Whenever an event manager receives a request sent using
-%% gen_event:call/3,4, this function is called for the specified event
-%% handler to handle the request.
-%% @end
-%%--------------------------------------------------------------------
+%%%
+%%% call, info, terminate, code_change
+%%%
+
 handle_call(_Request, State) ->
     Reply = ok,
     {ok, Reply, State}.
 
-%%--------------------------------------------------------------------
-%% @spec handle_info(Info, State) -> {ok, State} |
-%%                             {swap_handler, Args1, State1, Mod2, Args2} |
-%%                              remove_handler.
-%%
-%% @doc
-%% This function is called for each installed event handler when
-%% an event manager receives any other message than an event or a synchronous
-%% request (or a system message).
-%% @end
-%%--------------------------------------------------------------------
 handle_info(_Info, State) ->
     {ok, State}.
 
-%%--------------------------------------------------------------------
-%% @spec terminate(Reason, State) -> void().
-%%
-%% @doc
-%% Whenever an event handler is deleted from an event manager,
-%% this function is called. It should be the opposite of Module:init/1 and
-%% do any necessary cleaning up.
-%% @end
-%%--------------------------------------------------------------------
 terminate(normal, _State) ->
     ok;
 terminate(Reason, _State) ->
     format("*****************~n~n  frick, error logger terminating: ~p~n~n*****************~n~n", [Reason]),
     ok.
 
-%%--------------------------------------------------------------------
-%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}.
-%%
-%% @doc
-%% Convert process state when code is changed
-%% @end
-%%--------------------------------------------------------------------
 code_change(_OldVsn, State, _Extra) ->
     {ok, State}.
 
@@ -285,13 +214,10 @@
 
 print_crash_report(Report) ->
     case Report of
-        [[_,_,{error_info, XX}|_] | _]  ->
-            case thrift_utils:first_item(XX) of
-                tTransportException ->
-                    ok;
-                _ ->
-                    io:format("~~~~ crash report: ~P~n", [XX, 3])
-            end;
+        [[_,_,{error_info, {thrift_exception, _}}|_] | _]  ->
+            ok;
+        [[_,_,{error_info, {timeout, _}}|_] | _]  ->
+            ok;
         _ ->
-            io:format("~~~~ crash report (?): ~p~n", [Report])
+            io:format("~~~~ crash report: ~w~n", [Report])
     end.