Merge pull request #139 from basho/adt-avoid-console-io-hang

Disable console backend if oldshell is used
diff --git a/include/lager.hrl b/include/lager.hrl
index ac84d98..ade93e1 100644
--- a/include/lager.hrl
+++ b/include/lager.hrl
@@ -84,7 +84,7 @@
     %% from a gen_event handler
     spawn(fun() ->
             case catch(gen_event:which_handlers(lager_event)) of
-                X when X == []; X == {'EXIT', noproc} ->
+                X when X == []; X == {'EXIT', noproc}; X == [lager_backend_throttle] ->
                     %% there's no handlers yet or lager isn't running, try again
                     %% in half a second.
                     timer:sleep(500),
diff --git a/src/lager_console_backend.erl b/src/lager_console_backend.erl
index 8f968e0..c64fe9c 100644
--- a/src/lager_console_backend.erl
+++ b/src/lager_console_backend.erl
@@ -47,15 +47,27 @@
         _ -> []
     end,
 
-    try lager_util:config_to_mask(Level) of
-        Levels ->
+    try {is_new_style_console_available(), lager_util:config_to_mask(Level)} of
+        {false, _} ->
+            Msg = "Lager's console backend is incompatible with the 'old' shell, not enabling it",
+            %% be as noisy as possible, log to every possible place
+            try
+                alarm_handler:set_alarm({?MODULE, "WARNING: " ++ Msg})
+            catch
+                _:_ ->
+                    error_logger:warning_msg(Msg ++ "~n")
+            end,
+            io:format("WARNING: " ++ Msg ++ "~n"),
+            ?INT_LOG(warning, Msg, []),
+            {error, {fatal, old_shell}};
+        {true, Levels} ->
             {ok, #state{level=Levels,
                     formatter=Formatter, 
                     format_config=FormatterConfig,
                     colors=Colors}}
     catch
         _:_ ->
-            {error, bad_log_level}
+            {error, {fatal, bad_log_level}}
     end;
 init(Level) ->
     init([Level,{lager_default_formatter,?TERSE_FORMAT ++ [eol()]}]).
@@ -109,6 +121,23 @@
     end.
 
 -ifdef(TEST).
+is_new_style_console_available() ->
+    true.
+-else.
+is_new_style_console_available() ->
+    %% Criteria:
+    %% 1. If the user has specified '-noshell' on the command line,
+    %%    then we will pretend that the new-style console is available.
+    %%    If there is no shell at all, then we don't have to worry
+    %%    about log events being blocked by the old-style shell.
+    %% 2. If the user_drv process iss registered, all is OK.
+    %%    'user_drv' is a registered proc name used by the "new"
+    %%    console driver.
+    init:get_argument(noshell) /= error orelse
+        is_pid(whereis(user_drv)).
+-endif.
+
+-ifdef(TEST).
 console_log_test_() ->
     %% tiny recursive fun that pretends to be a group leader
     F = fun(Self) ->
diff --git a/src/lager_file_backend.erl b/src/lager_file_backend.erl
index b8a3411..6e1d2ef 100644
--- a/src/lager_file_backend.erl
+++ b/src/lager_file_backend.erl
@@ -99,7 +99,7 @@
     case validate_logfile_proplist(LogFileConfig) of
         false ->
             %% falied to validate config
-            {error, bad_config};
+            {error, {fatal, bad_config}};
         Config ->
             %% probabably a better way to do this, but whatever
             [Name, Level, Date, Size, Count, SyncInterval, SyncSize, SyncOn, CheckInterval, Formatter, FormatterConfig] =
diff --git a/src/lager_handler_watcher.erl b/src/lager_handler_watcher.erl
index 2086346..ac34119 100644
--- a/src/lager_handler_watcher.erl
+++ b/src/lager_handler_watcher.erl
@@ -23,6 +23,8 @@
 
 -behaviour(gen_server).
 
+-include("lager.hrl").
+
 -ifdef(TEST).
 -include_lib("eunit/include/eunit.hrl").
 -endif.
@@ -73,6 +75,8 @@
 handle_info(reinstall_handler, #state{module=Module, config=Config, event=Event} = State) ->
     install_handler(Event, Module, Config),
     {noreply, State};
+handle_info(stop, State) ->
+    {stop, normal, State};
 handle_info(_Info, State) ->
     {noreply, State}.
 
@@ -87,12 +91,18 @@
 install_handler(Event, Module, Config) ->
     case gen_event:add_sup_handler(Event, Module, Config) of
         ok ->
-            _ = lager:log(debug, self(), "Lager installed handler ~p into ~p", [Module, Event]),
+            ?INT_LOG(debug, "Lager installed handler ~p into ~p", [Module, Event]),
             lager:update_loglevel_config(),
             ok;
+        {error, {fatal, Reason}} ->
+            ?INT_LOG(error, "Lager fatally failed to install handler ~p into"
+                " ~p, NOT retrying: ~p", [Module, Event, Reason]),
+            %% tell ourselves to stop
+            self() ! stop,
+            ok;
         Error ->
             %% try to reinstall it later
-            _ = lager:log(error, self(), "Lager failed to install handler ~p into"
+            ?INT_LOG(error, "Lager failed to install handler ~p into"
                " ~p, retrying later : ~p", [Module, Event, Error]),
             erlang:send_after(5000, self(), reinstall_handler),
             ok
@@ -145,10 +155,10 @@
                         ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event))),
                         timer:sleep(6000),
                         ?assertEqual(2, lager_test_backend:count()),
-                        {_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
-                        ?assertEqual("Lager event handler lager_crash_backend exited with reason crash", lists:flatten(Message)),
-                        {_Level2, _Time2, Message2, _Metadata} = lager_test_backend:pop(),
-                        ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Message2)),
+                        {_Severity, _Date, Msg, _Metadata} = lager_test_backend:pop(),
+                        ?assertEqual("Lager event handler lager_crash_backend exited with reason crash", lists:flatten(Msg)),
+                        {_Severity2, _Date2, Msg2, _Metadata2} = lager_test_backend:pop(),
+                        ?assertMatch("Lager failed to install handler lager_crash_backend into lager_event, retrying later :"++_, lists:flatten(Msg2)),
                         ?assertEqual(false, lists:member(lager_crash_backend, gen_event:which_handlers(lager_event)))
                     after
                        application:stop(lager),
diff --git a/src/lager_handler_watcher_sup.erl b/src/lager_handler_watcher_sup.erl
index b3161ae..f3763aa 100644
--- a/src/lager_handler_watcher_sup.erl
+++ b/src/lager_handler_watcher_sup.erl
@@ -35,5 +35,5 @@
     {ok, {{simple_one_for_one, 10, 60},
             [
                 {lager_handler_watcher, {lager_handler_watcher, start_link, []},
-                        transient, 5000, worker, [lager_handler_watcher]}
+                        temporary, 5000, worker, [lager_handler_watcher]}
                 ]}}.