Merge pull request #170 from MaximMinin/master

pretty printing of nested records
diff --git a/.gitignore b/.gitignore
index 3bde15b..d053947 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@
 .project
 log
 deps
+.local_dialyzer_plt
diff --git a/Makefile b/Makefile
index 2994a71..4c61dd6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
-.PHONY: rel stagedevrel deps test
+.PHONY: all compile deps clean distclean test check_plt build_plt dialyzer \
+	    cleanplt
 
 all: deps compile
 
@@ -14,39 +15,6 @@
 distclean: clean
 	./rebar delete-deps
 
-test:
-	./rebar compile eunit
+DIALYZER_APPS = kernel stdlib erts sasl eunit syntax_tools compiler crypto
 
-##
-## Doc targets
-##
-docs:
-	./rebar doc
-
-APPS = kernel stdlib sasl erts ssl tools os_mon runtime_tools crypto inets \
-	xmerl webtool snmp public_key mnesia eunit
-COMBO_PLT = $(HOME)/.riak_combo_dialyzer_plt
-
-check_plt: compile
-	dialyzer --check_plt --plt $(COMBO_PLT) --apps $(APPS)
-
-build_plt: compile
-	dialyzer --build_plt --output_plt $(COMBO_PLT) --apps $(APPS)
-
-dialyzer: compile
-	@echo
-	@echo Use "'make check_plt'" to check PLT prior to using this target.
-	@echo Use "'make build_plt'" to build PLT prior to using this target.
-	@echo
-	@sleep 1
-	dialyzer -Wunmatched_returns --plt $(COMBO_PLT) ebin | \
-	    fgrep -v -f ./dialyzer.ignore-warnings
-
-cleanplt:
-	@echo 
-	@echo "Are you sure?  It takes about 1/2 hour to re-build."
-	@echo Deleting $(COMBO_PLT) in 5 seconds.
-	@echo 
-	sleep 5
-	rm $(COMBO_PLT)
-
+include tools.mk
diff --git a/README.md b/README.md
index e3475ad..c2f499f 100644
--- a/README.md
+++ b/README.md
@@ -132,7 +132,7 @@
 Lager is also supplied with a error_logger handler module that translates
 traditional erlang error messages into a friendlier format and sends them into
 lager itself to be treated like a regular lager log call. To disable this, set
-the lager application variable `error_logger_redirect' to `false'.
+the lager application variable `error_logger_redirect` to `false`.
 
 The error_logger handler will also log more complete error messages (protected
 with use of trunc_io) to a "crash log" which can be referred to for further
diff --git a/rebar b/rebar
index 7bdb274..cbabc30 100755
--- a/rebar
+++ b/rebar
Binary files differ
diff --git a/rebar.config b/rebar.config
index 6809cbb..6460605 100644
--- a/rebar.config
+++ b/rebar.config
@@ -1,9 +1,12 @@
-{erl_opts, [debug_info]}.
+{erl_opts, [debug_info, warn_untyped_record]}.
 {erl_first_files, ["src/lager_util.erl"]}.
 {deps, [
-        {goldrush, ".*",
-            {git, "git://github.com/DeadZen/goldrush.git", {tag, "879c69874a"}}}
+        {goldrush, "0\.1\.6",
+            {git, "git://github.com/DeadZen/goldrush.git", {tag, "0.1.6"}}}
        ]}.
 
+{xref_checks, []}.
+{xref_queries, [{"(XC - UC) || (XU - X - B - lager_default_tracer : Mod)", []}]}.
+
 {cover_enabled, true}.
 {edoc_opts, [{stylesheet_file, "./priv/edoc.css"}]}.
diff --git a/src/error_logger_lager_h.erl b/src/error_logger_lager_h.erl
index 6acfec4..1c7e092 100644
--- a/src/error_logger_lager_h.erl
+++ b/src/error_logger_lager_h.erl
@@ -414,8 +414,7 @@
 t0() ->
     application:stop(lager),
     application:stop(sasl),
-    application:start(sasl),
-    application:start(lager),
+    lager:start(),
     set_high_water(5),
     [error_logger:warning_msg("Foo ~p!", [X]) || X <- lists:seq(1,10)],
     timer:sleep(1000),
diff --git a/src/lager.app.src b/src/lager.app.src
index 63f35ce..9adfd7c 100644
--- a/src/lager.app.src
+++ b/src/lager.app.src
@@ -3,14 +3,14 @@
 {application, lager,
  [
   {description, "Erlang logging framework"},
-  {vsn, "2.0.0"},
+  {vsn, "2.0.2"},
   {modules, []},
   {applications, [
                   kernel,
-                  stdlib
+                  stdlib,
+                  goldrush
                  ]},
   {registered, [lager_sup, lager_event, lager_crash_log, lager_handler_watcher_sup]},
-  {included_applications, [goldrush]},
   {mod, {lager_app, []}},
   {env, [
             %% What handlers to install with what arguments
diff --git a/src/lager.erl b/src/lager.erl
index bd4757e..c075544 100644
--- a/src/lager.erl
+++ b/src/lager.erl
@@ -191,7 +191,7 @@
 stop_trace({_Filter, _Level, Target} = Trace) ->
     {Level, Traces} = lager_config:get(loglevel),
     NewTraces =  lists:delete(Trace, Traces),
-    lager_util:trace_filter([ element(1, T) || T <- NewTraces ]),
+    _ = lager_util:trace_filter([ element(1, T) || T <- NewTraces ]),
     %MinLevel = minimum_loglevel(get_loglevels() ++ get_trace_levels(NewTraces)),
     lager_config:set(loglevel, {Level, NewTraces}),
     case get_loglevel(Target) of
@@ -210,7 +210,7 @@
 
 clear_all_traces() ->
     {Level, _Traces} = lager_config:get(loglevel),
-    lager_util:trace_filter(none),
+    _ = lager_util:trace_filter(none),
     lager_config:set(loglevel, {Level, []}),
     lists:foreach(fun(Handler) ->
           case get_loglevel(Handler) of
@@ -319,7 +319,7 @@
     case lists:member(Trace, Traces) of
         false ->
             NewTraces = [Trace|Traces],
-            lager_util:trace_filter([ element(1, T) || T <- NewTraces]),
+            _ = lager_util:trace_filter([ element(1, T) || T <- NewTraces]),
             lager_config:set(loglevel, {MinLevel, [Trace|Traces]});
         _ ->
             ok
diff --git a/src/lager_app.erl b/src/lager_app.erl
index d169f80..6052c3a 100644
--- a/src/lager_app.erl
+++ b/src/lager_app.erl
@@ -113,7 +113,7 @@
                 end
         end,
 
-    lager_util:trace_filter(none), 
+    _ = lager_util:trace_filter(none), 
 
     {ok, Pid, SavedHandlers}.
 
diff --git a/src/lager_backend_throttle.erl b/src/lager_backend_throttle.erl
index 14573b0..8b6f3ec 100644
--- a/src/lager_backend_throttle.erl
+++ b/src/lager_backend_throttle.erl
@@ -30,9 +30,9 @@
         code_change/3]).
 
 -record(state, {
-        hwm,
-        window_min,
-        async = true
+        hwm :: non_neg_integer(),
+        window_min :: non_neg_integer(),
+        async = true :: boolean()
     }).
 
 init([Hwm, Window]) ->
diff --git a/src/lager_console_backend.erl b/src/lager_console_backend.erl
index 1c61610..4d9c4e3 100644
--- a/src/lager_console_backend.erl
+++ b/src/lager_console_backend.erl
@@ -1,4 +1,4 @@
-%% Copyright (c) 2011-2012 Basho Technologies, Inc.  All Rights Reserved.
+%% Copyright (c) 2011-2012, 2014 Basho Technologies, Inc.  All Rights Reserved.
 %%
 %% This file is provided to you under the Apache License,
 %% Version 2.0 (the "License"); you may not use this file
@@ -24,7 +24,10 @@
 -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
         code_change/3]).
 
--record(state, {level, formatter,format_config,colors=[]}).
+-record(state, {level :: {'mask', integer()},
+                formatter :: atom(),
+                format_config :: any(),
+                colors=[] :: list()}).
 
 -ifdef(TEST).
 -include_lib("eunit/include/eunit.hrl").
@@ -41,7 +44,7 @@
     init([Level,{lager_default_formatter,?TERSE_FORMAT ++ [eol()]}]);
 init([Level,{Formatter,FormatterConfig}]) when is_atom(Formatter) ->
     Colors = case application:get_env(lager, colored) of
-        {ok, true} -> 
+        {ok, true} ->
             {ok, LagerColors} = application:get_env(lager, colors),
             LagerColors;
         _ -> []
@@ -62,7 +65,7 @@
             {error, {fatal, old_shell}};
         {true, Levels} ->
             {ok, #state{level=Levels,
-                    formatter=Formatter, 
+                    formatter=Formatter,
                     format_config=FormatterConfig,
                     colors=Colors}}
     catch
@@ -116,7 +119,7 @@
     case application:get_env(lager, colored) of
         {ok, true}  ->
             "\e[0m\r\n";
-        _ -> 
+        _ ->
             "\r\n"
     end.
 
@@ -132,11 +135,11 @@
     %%    about log events being blocked by the old-style shell.
     %% 2. Windows doesn't support the new shell, so all windows users
     %%    have is the oldshell.
-    %% 3. If the user_drv process iss registered, all is OK.
+    %% 3. If the user_drv process is registered, all is OK.
     %%    'user_drv' is a registered proc name used by the "new"
     %%    console driver.
     init:get_argument(noshell) /= error orelse
-        element(1, os:type()) == win32 orelse
+        element(1, os:type()) /= win32 orelse
         is_pid(whereis(user_drv)).
 -endif.
 
@@ -165,7 +168,7 @@
                 application:load(lager),
                 application:set_env(lager, handlers, []),
                 application:set_env(lager, error_logger_redirect, false),
-                application:start(lager),
+                lager:start(),
                 whereis(user)
         end,
         fun(User) ->
@@ -221,7 +224,7 @@
                         unregister(user),
                         register(user, Pid),
                         erlang:group_leader(Pid, whereis(lager_event)),
-                        gen_event:add_handler(lager_event, lager_console_backend, 
+                        gen_event:add_handler(lager_event, lager_console_backend,
                           [info, {lager_default_formatter, [date,"#",time,"#",severity,"#",node,"#",pid,"#",
                                                             module,"#",function,"#",file,"#",line,"#",message,"\r\n"]}]),
                         lager_config:set(loglevel, {?INFO, []}),
@@ -232,7 +235,7 @@
                         receive
                             {io_request, _, _, {put_chars, unicode, Msg}} ->
                                 TestMsg = "Test message" ++ eol(),
-                                ?assertMatch([_, _, "info", NodeStr, PidStr, ModuleStr, _, _, _, TestMsg], 
+                                ?assertMatch([_, _, "info", NodeStr, PidStr, ModuleStr, _, _, _, TestMsg],
                                              re:split(Msg, "#", [{return, list}, {parts, 10}]))
                         after
                             500 ->
@@ -381,7 +384,7 @@
                 application:load(lager),
                 application:set_env(lager, handlers, [{lager_console_backend, info}]),
                 application:set_env(lager, error_logger_redirect, false),
-                application:start(lager)
+                lager:start()
         end,
         fun(_) ->
                 application:stop(lager),
diff --git a/src/lager_crash_log.erl b/src/lager_crash_log.erl
index eab2275..089e32a 100644
--- a/src/lager_crash_log.erl
+++ b/src/lager_crash_log.erl
@@ -45,14 +45,14 @@
 -export([start_link/5, start/5]).
 
 -record(state, {
-        name,
-        fd,
-        inode,
-        fmtmaxbytes,
-        size,
-        date,
-        count,
-        flap=false
+        name :: string(),
+        fd :: pid(),
+        inode :: integer(),
+        fmtmaxbytes :: integer(),
+        size :: integer(),
+        date :: undefined | string(),
+        count :: integer(),
+        flap=false :: boolean()
 }).
 
 %% @private
@@ -95,7 +95,7 @@
 
 %% @private
 handle_info(rotate, #state{name=Name, count=Count, date=Date} = State) ->
-    lager_util:rotate_logfile(Name, Count),
+    _ = lager_util:rotate_logfile(Name, Count),
     schedule_rotation(Date),
     {noreply, State};
 handle_info(_Info, State) ->
@@ -199,7 +199,7 @@
         true ->
             case lager_util:ensure_logfile(Name, FD, Inode, false) of
                 {ok, {_, _, Size}} when RotSize /= 0, Size > RotSize ->
-                    lager_util:rotate_logfile(Name, Count),
+                    _ = lager_util:rotate_logfile(Name, Count),
                     handle_cast({log, Event}, State);
                 {ok, {NewFD, NewInode, _Size}} ->
                     {Date, TS} = lager_util:format_time(
diff --git a/src/lager_file_backend.erl b/src/lager_file_backend.erl
index dfed64a..96f41bc 100644
--- a/src/lager_file_backend.erl
+++ b/src/lager_file_backend.erl
@@ -1,3 +1,4 @@
+%% -*- coding: latin-1 -*-
 %% Copyright (c) 2011-2012 Basho Technologies, Inc.  All Rights Reserved.
 %%
 %% This file is provided to you under the Apache License,
@@ -61,15 +62,15 @@
         inode :: integer(),
         flap=false :: boolean(),
         size = 0 :: integer(),
-        date,
-        count = 10,
-        formatter,
-        formatter_config,
-        sync_on,
-        check_interval = ?DEFAULT_CHECK_INTERVAL,
-        sync_interval = ?DEFAULT_SYNC_INTERVAL,
-        sync_size = ?DEFAULT_SYNC_SIZE,
-        last_check = os:timestamp()
+        date :: undefined | string(),
+        count = 10 :: integer(),
+        formatter :: atom(),
+        formatter_config :: any(),
+        sync_on :: {'mask', integer()},
+        check_interval = ?DEFAULT_CHECK_INTERVAL :: non_neg_integer(),
+        sync_interval = ?DEFAULT_SYNC_INTERVAL :: non_neg_integer(),
+        sync_size = ?DEFAULT_SYNC_SIZE :: non_neg_integer(),
+        last_check = os:timestamp() :: erlang:timestamp()
     }).
 
 -type option() :: {file, string()} | {level, lager:log_level()} |
@@ -146,7 +147,7 @@
 
 %% @private
 handle_info({rotate, File}, #state{name=File,count=Count,date=Date} = State) ->
-    lager_util:rotate_logfile(File, Count),
+    _ = lager_util:rotate_logfile(File, Count),
     schedule_rotation(File, Date),
     {ok, State};
 handle_info(_Info, State) ->
@@ -468,7 +469,7 @@
                 application:set_env(lager, handlers, [{lager_test_backend, info}]),
                 application:set_env(lager, error_logger_redirect, false),
                 application:set_env(lager, async_threshold, undefined),
-                application:start(lager)
+                lager:start()
         end,
         fun(_) ->
                 file:delete("test.log"),
@@ -715,7 +716,7 @@
                 application:load(lager),
                 application:set_env(lager, handlers, [{lager_test_backend, info}]),
                 application:set_env(lager, error_logger_redirect, false),
-                application:start(lager)
+                lager:start()
         end,
         fun(_) ->
                 file:delete("test.log"),
diff --git a/src/lager_format.erl b/src/lager_format.erl
index b834f27..d12ce3b 100644
--- a/src/lager_format.erl
+++ b/src/lager_format.erl
@@ -23,7 +23,7 @@
 -export([format/3, format/4]).
 
 -record(options, {
-        chomp = false
+        chomp = false :: boolean()
     }).
 
 format(FmtStr, Args, MaxLen) ->
diff --git a/src/lager_handler_watcher.erl b/src/lager_handler_watcher.erl
index ac34119..1285a24 100644
--- a/src/lager_handler_watcher.erl
+++ b/src/lager_handler_watcher.erl
@@ -36,9 +36,9 @@
 -export([start_link/3, start/3]).
 
 -record(state, {
-        module,
-        config,
-        event
+        module :: atom(),
+        config :: any(),
+        event :: pid() | atom()
     }).
 
 start_link(Event, Module, Config) ->
@@ -123,7 +123,7 @@
                     application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [from_now(2), undefined]}]),
                     application:set_env(lager, error_logger_redirect, false),
                     application:unset_env(lager, crash_log),
-                    application:start(lager),
+                    lager:start(),
                     try
                       ?assertEqual(1, lager_test_backend:count()),
                       {_Level, _Time, Message, _Metadata} = lager_test_backend:pop(),
@@ -149,7 +149,7 @@
                     application:set_env(lager, handlers, [{lager_test_backend, info}, {lager_crash_backend, [undefined, from_now(5)]}]),
                     application:set_env(lager, error_logger_redirect, false),
                     application:unset_env(lager, crash_log),
-                    application:start(lager),
+                    lager:start(),
                     try
                         ?assertEqual(0, lager_test_backend:count()),
                         ?assert(lists:member(lager_crash_backend, gen_event:which_handlers(lager_event))),
diff --git a/src/lager_trunc_io.erl b/src/lager_trunc_io.erl
index 43b3d24..a2f2d6b 100644
--- a/src/lager_trunc_io.erl
+++ b/src/lager_trunc_io.erl
@@ -127,13 +127,10 @@
     end,
     {R, length(R)};
 
-print(Bin, _Max, O = #print_options{depth=1}) when is_binary(Bin) ->
-    case O#print_options.lists_as_strings of
-        true when Bin == <<>>  ->
-            {"<<>>", 4};
-        _ ->
-            {"<<...>>", 7}
-    end;
+print(<<>>, _Max, #print_options{depth=1}) ->
+    {"<<>>", 4};
+print(Bin, _Max, #print_options{depth=1}) when is_binary(Bin) ->
+    {"<<...>>", 7};
 print(<<>>, _Max, Options) ->
     case Options#print_options.force_strings of
         true ->
@@ -766,7 +763,7 @@
 
     %% I don't even know...
     ?assertEqual("<<>>", lists:flatten(format("~P", [<<>>, 1], 50))),
-    ?assertEqual("<<...>>", lists:flatten(format("~W", [<<>>, 1], 50))),
+    ?assertEqual("<<>>", lists:flatten(format("~W", [<<>>, 1], 50))),
 
     ?assertEqual("{abc,<<\"abc\\\"\">>}", lists:flatten(format("~P", [{abc,<<"abc\"">>}, 4], 50))),
 
diff --git a/src/lager_util.erl b/src/lager_util.erl
index ae88d19..d912103 100644
--- a/src/lager_util.erl
+++ b/src/lager_util.erl
@@ -353,17 +353,16 @@
     NewNow = calendar:gregorian_seconds_to_datetime(Seconds),
     calculate_next_rotation(T, NewNow).
 
-
+-spec trace_filter(Query :: 'none' | [tuple()]) -> {ok, any()}.
 trace_filter(Query) ->
     trace_filter(?DEFAULT_TRACER, Query).
 
 %% TODO: Support multiple trace modules 
+%-spec trace_filter(Module :: atom(), Query :: 'none' | [tuple()]) -> {ok, any()}.
 trace_filter(Module, Query) when Query == none; Query == [] ->
-    trace_filter(Module, glc:null(false));
+    {ok, _} = glc:compile(Module, glc:null(false));
 trace_filter(Module, Query) when is_list(Query) ->
-    trace_filter(Module, glc_lib:reduce(trace_any(Query)));
-trace_filter(Module, Query) ->
-    {ok, _} = glc:compile(Module, Query).
+    {ok, _} = glc:compile(Module, glc_lib:reduce(trace_any(Query))).
 
 validate_trace({Filter, Level, {Destination, ID}}) when is_tuple(Filter); is_list(Filter), is_atom(Level), is_atom(Destination) ->
     case validate_trace({Filter, Level, Destination}) of
@@ -392,6 +391,7 @@
     false;
 validate_trace_filter(Filter) ->
         case lists:all(fun({Key, '*'}) when is_atom(Key) -> true; 
+                          ({Key, '!'}) when is_atom(Key) -> true;
                           ({Key, _Value})      when is_atom(Key) -> true;
                           ({Key, '=', _Value}) when is_atom(Key) -> true;
                           ({Key, '<', _Value}) when is_atom(Key) -> true;
@@ -416,6 +416,8 @@
 	lists:reverse(Acc);
 trace_acc([{Key, '*'}|T], Acc) ->
 	trace_acc(T, [glc:wc(Key)|Acc]);
+trace_acc([{Key, '!'}|T], Acc) ->
+	trace_acc(T, [glc:nf(Key)|Acc]);
 trace_acc([{Key, Val}|T], Acc) ->
 	trace_acc(T, [glc:eq(Key, Val)|Acc]);
 trace_acc([{Key, '=', Val}|T], Acc) ->
@@ -585,6 +587,7 @@
     ok.
 
 check_trace_test() ->
+    lager:start(),
     trace_filter(none),
     %% match by module
     ?assertEqual([foo], check_traces([{module, ?MODULE}], ?EMERGENCY, [
@@ -625,7 +628,7 @@
                 {[{module, '*'}], config_to_mask('!=info'), anythingbutinfo},
                 {[{module, '*'}], config_to_mask('!=notice'), anythingbutnotice}
                 ], [])),
-
+    application:stop(lager),
     ok.
 
 is_loggable_test_() ->
diff --git a/test/lager_test_backend.erl b/test/lager_test_backend.erl
index 59590ba..648bdb9 100644
--- a/test/lager_test_backend.erl
+++ b/test/lager_test_backend.erl
@@ -109,7 +109,7 @@
 has_line_numbers() ->
     %% are we R15 or greater
     Rel = erlang:system_info(otp_release),
-    {match, [Major]} = re:run(Rel, "^R(\\d+)[A|B](|0(\\d))$", [{capture, [1], list}]),
+    {match, [Major]} = re:run(Rel, "^R(\\d+)[A|B](|0(\\d))", [{capture, [1], list}]),
     list_to_integer(Major) >= 15.
 
 not_running_test() ->
@@ -388,10 +388,16 @@
                         lager:info([{requestid, 8}], "hello world"),
                         lager:info([{requestid, 9}, {foo, bar}], "hello world"),
                         lager:info([{requestid, 10}], "hello world"),
-                        ?assertEqual(7, count()),
+                        lager:trace(?MODULE, [{fu, '!'}]),
+                        lager:info([{foo, bar}], "hello world"),
+                        lager:info([{ooh, car}], "hello world"),
+                        lager:info([{fu, bar}], "hello world"),
+                        lager:trace(?MODULE, [{fu, '*'}]),
+                        lager:info([{fu, bar}], "hello world"),
+                        ?assertEqual(10, count()),
                         lager:clear_all_traces(),
                         lager:info([{requestid, 6}], "hello world"),
-                        ?assertEqual(7, count()),
+                        ?assertEqual(10, count()),
                         ok
                 end
             },
@@ -441,7 +447,7 @@
                         ?assertEqual(0, count()),
                         application:stop(lager),
                         application:set_env(lager, traces, [{lager_test_backend, [{foo, bar}], debug}]),
-                        application:start(lager),
+                        lager:start(),
                         lager:debug([{foo, bar}], "hello world"),
                         ?assertEqual(1, count()),
                         application:unset_env(lager, traces),
@@ -555,7 +561,7 @@
     application:load(lager),
     application:set_env(lager, handlers, [{?MODULE, info}]),
     application:set_env(lager, error_logger_redirect, false),
-    application:start(lager),
+    lager:start(),
     gen_event:call(lager_event, ?MODULE, flush).
 
 cleanup(_) ->
@@ -608,7 +614,7 @@
                 application:load(lager),
                 application:set_env(lager, error_logger_redirect, true),
                 application:set_env(lager, handlers, [{?MODULE, error}]),
-                application:start(lager),
+                lager:start(),
                 crash:start()
         end,
 
@@ -655,7 +661,7 @@
                 application:load(lager),
                 application:set_env(lager, error_logger_redirect, true),
                 application:set_env(lager, handlers, [{?MODULE, info}]),
-                application:start(lager),
+                lager:start(),
                 lager:log(error, self(), "flush flush"),
                 timer:sleep(100),
                 gen_event:call(lager_event, ?MODULE, flush)
@@ -1154,7 +1160,7 @@
                 application:set_env(lager, error_logger_redirect, false),
                 application:set_env(lager, async_threshold, 10),
                 application:set_env(lager, handlers, [{?MODULE, info}]),
-                application:start(lager)
+                lager:start()
         end,
         fun(_) ->
                 application:unset_env(lager, async_threshold),
diff --git a/tools.mk b/tools.mk
new file mode 100644
index 0000000..8e0e1b9
--- /dev/null
+++ b/tools.mk
@@ -0,0 +1,48 @@
+test: compile
+	./rebar eunit skip_deps=true
+
+docs:
+	./rebar doc skip_deps=true
+
+xref: compile
+	./rebar xref skip_deps=true
+
+PLT ?= $(HOME)/.riak_combo_dialyzer_plt
+LOCAL_PLT = .local_dialyzer_plt
+DIALYZER_FLAGS ?= -Wunmatched_returns
+
+${PLT}: compile
+ifneq (,$(wildcard $(PLT)))
+	dialyzer --check_plt --plt $(PLT) --apps $(DIALYZER_APPS) && \
+		dialyzer --add_to_plt --plt $(PLT) --output_plt $(PLT) --apps $(DIALYZER_APPS) ; test $$? -ne 1
+else
+	dialyzer --build_plt --output_plt $(PLT) --apps $(DIALYZER_APPS); test $$? -ne 1
+endif
+
+${LOCAL_PLT}: compile
+ifneq (,$(wildcard deps/*))
+ifneq (,$(wildcard $(LOCAL_PLT)))
+	dialyzer --check_plt --plt $(LOCAL_PLT) deps/*/ebin  && \
+		dialyzer --add_to_plt --plt $(LOCAL_PLT) --output_plt $(LOCAL_PLT) deps/*/ebin ; test $$? -ne 1
+else
+	dialyzer --build_plt --output_plt $(LOCAL_PLT) deps/*/ebin ; test $$? -ne 1
+endif
+endif
+
+dialyzer: ${PLT} ${LOCAL_PLT}
+	@echo "==> $(shell basename $(shell pwd)) (dialyzer)"
+	@if [ -f $(LOCAL_PLT) ]; then \
+		dialyzer $(DIALYZER_FLAGS) --plts $(PLT) $(LOCAL_PLT) -c ebin; \
+	else \
+		dialyzer $(DIALYZER_FLAGS) --plts $(PLT) -c ebin; \
+	fi
+
+cleanplt:
+	@echo 
+	@echo "Are you sure?  It takes several minutes to re-build."
+	@echo Deleting $(PLT) and $(LOCAL_PLT) in 5 seconds.
+	@echo 
+	sleep 5
+	rm $(PLT)
+	rm $(LOCAL_PLT)
+