Initial attempt at a trace API, and a status() command
diff --git a/include/lager.hrl b/include/lager.hrl
index 1c42a93..bb42f7b 100644
--- a/include/lager.hrl
+++ b/include/lager.hrl
@@ -15,7 +15,7 @@
 %% under the License.
 
 -define(LEVELS,
-    [debug, info, notice, warning, error, critical, alert, emergency]).
+    [debug, info, notice, warning, error, critical, alert, emergency, none]).
 
 -define(DEBUG, 7).
 -define(INFO, 6).
diff --git a/src/lager.erl b/src/lager.erl
index 49d2bea..a0d1355 100644
--- a/src/lager.erl
+++ b/src/lager.erl
@@ -23,6 +23,8 @@
 %% API
 -export([start/0,
         log/8, log_dest/9, log/3, log/4,
+        trace_file/2, trace_file/3, trace_console/1, trace_console/2,
+        status/0,
         get_loglevel/1, set_loglevel/2, set_loglevel/3, get_loglevels/0,
         minimum_loglevel/1, posix_error/1,
         safe_format/3, safe_format_chop/3]).
@@ -88,6 +90,63 @@
            safe_format_chop(Format, Args, 4096)],
     safe_notify({log, lager_util:level_to_num(Level), Timestamp, Msg}).
 
+trace_file(File, Filter) ->
+    trace_file(File, Filter, debug).
+
+trace_file(File, Filter, Level) ->
+    Trace0 = {Filter, Level, {lager_file_backend, File}},
+    case lager_util:validate_trace(Trace0) of
+        {ok, Trace} ->
+            Handlers = gen_event:which_handlers(lager_event),
+            %% check if this file backend is already installed
+            case lists:member({lager_file_backend, File}, Handlers) of
+                false ->
+                    %% install the handler
+                    supervisor:start_child(lager_handler_watcher_sup,
+                        [lager_event, {lager_file_backend, File}, {File, none}]);
+                _ ->
+                    ok
+            end,
+            %% install the trace.
+            {MinLevel, Traces} = lager_mochiglobal:get(loglevel),
+            lager_mochiglobal:put(loglevel, {MinLevel, [Trace|Traces]});
+        Error ->
+            Error
+    end.
+
+trace_console(Filter) ->
+    trace_file(Filter, debug).
+
+trace_console(Filter, Level) ->
+    Trace0 = {Filter, Level, lager_console_backend},
+    case lager_util:validate_trace(Trace0) of
+        {ok, Trace} ->
+            {Level, Traces} = lager_mochiglobal:get(loglevel),
+            lager_mochiglobal:put(loglevel, {Level, [Trace|Traces]});
+        Error ->
+            Error
+    end.
+
+status() ->
+    Handlers = gen_event:which_handlers(lager_event),
+    Status = ["Lager status:\n",
+        [begin
+                    Level = get_loglevel(Handler),
+                    case Handler of
+                        {lager_file_backend, File} ->
+                            io_lib:format("File ~s at level ~p\n", [File, Level]);
+                        lager_console_backend ->
+                            io_lib:format("Console at level ~p\n", [Level]);
+                        _ ->
+                            []
+                    end
+            end || Handler <- Handlers],
+        "Active Traces:\n",
+        [begin
+                    io_lib:format("Tracing messages matching ~p at level ~p to ~p\n", [Filter, lager_util:num_to_level(Level), Destination])
+            end || {Filter, Level, Destination} <- element(2, lager_mochiglobal:get(loglevel))]],
+    io:put_chars(Status).
+
 %% @doc Set the loglevel for a particular backend.
 set_loglevel(Handler, Level) when is_atom(Level) ->
     Reply = gen_event:call(lager_event, Handler, {set_loglevel, Level}, infinity),
diff --git a/src/lager_util.erl b/src/lager_util.erl
index 5339636..c32df8c 100644
--- a/src/lager_util.erl
+++ b/src/lager_util.erl
@@ -21,7 +21,7 @@
 -export([levels/0, level_to_num/1, num_to_level/1, open_logfile/2,
         ensure_logfile/4, rotate_logfile/2, format_time/0, format_time/1,
         localtime_ms/0, maybe_utc/1, parse_rotation_date_spec/1,
-        calculate_next_rotation/1, check_traces/4]).
+        calculate_next_rotation/1, validate_trace/1, check_traces/4]).
 
 -ifdef(TEST).
 -include_lib("eunit/include/eunit.hrl").
@@ -37,7 +37,8 @@
 level_to_num(error)     -> 3;
 level_to_num(critical)  -> 2;
 level_to_num(alert)     -> 1;
-level_to_num(emergency) -> 0.
+level_to_num(emergency) -> 0;
+level_to_num(none)      -> -1.
 
 num_to_level(7) -> debug;
 num_to_level(6) -> info;
@@ -46,7 +47,8 @@
 num_to_level(3) -> error;
 num_to_level(2) -> critical;
 num_to_level(1) -> alert;
-num_to_level(0) -> emergency.
+num_to_level(0) -> emergency;
+num_to_level(-1) -> none.
 
 open_logfile(Name, Buffer) ->
     case filelib:ensure_dir(Name) of
@@ -269,6 +271,31 @@
     NewNow = calendar:gregorian_seconds_to_datetime(Seconds),
     calculate_next_rotation(T, NewNow).
 
+validate_trace({Filter, Level, {Destination, ID}}) when is_list(Filter), is_atom(Level), is_atom(Destination) ->
+    case validate_trace({Filter, Level, Destination}) of
+        {ok, {F, L, D}} ->
+            {ok, {F, L, {D, ID}}};
+        Error ->
+            Error
+    end;
+validate_trace({Filter, Level, Destination}) when is_list(Filter), is_atom(Level), is_atom(Destination) ->
+    try level_to_num(Level) of
+        L ->
+            case lists:all(fun({Key, _Value}) when is_atom(Key) -> true; (_) ->
+                            false end, Filter) of
+                true ->
+                    {ok, {Filter, L, Destination}};
+                _ ->
+                    {error, invalid_filter}
+            end
+    catch
+        _:_ ->
+            {error, invalid_level}
+    end;
+validate_trace(_) ->
+    {error, invalid_trace}.
+
+
 check_traces(_, _,  [], Acc) ->
     lists:flatten(Acc);
 check_traces(Attrs, Level, [{_, FilterLevel, _}|Flows], Acc) when Level > FilterLevel ->