Browse Source

Add colors to lager, not enabled by default

pull/124/head
Pedram Nimreezi 12 years ago
parent
commit
b6a1827490
6 changed files with 83 additions and 33 deletions
  1. +1
    -0
      .gitignore
  2. +1
    -1
      rebar.config
  3. +14
    -0
      src/lager.app.src
  4. +4
    -4
      src/lager_app.erl
  5. +40
    -19
      src/lager_console_backend.erl
  6. +23
    -9
      src/lager_default_formatter.erl

+ 1
- 0
.gitignore View File

@ -5,3 +5,4 @@ doc
*.swp *.swp
erl_crash.dump erl_crash.dump
.project .project
log

+ 1
- 1
rebar.config View File

@ -2,4 +2,4 @@
{erl_first_files, ["src/lager_util.erl"]}. {erl_first_files, ["src/lager_util.erl"]}.
{cover_enabled, true}. {cover_enabled, true}.
{edoc_opts, [{stylesheet_file, "./priv/edoc.css"}]}.
{edoc_opts, [{stylesheet_file, "./priv/edoc.css"}]}.

+ 14
- 0
src/lager.app.src View File

@ -20,6 +20,20 @@
{"log/console.log", info, 10485760, "$D0", 5} {"log/console.log", info, 10485760, "$D0", 5}
]} ]}
]}, ]},
%% What colors to use with what log levels
{colored, false},
{colors, [
{debug, "\e[0;38m" },
{info, "\e[1;37m" },
{notice, "\e[1;36m" },
{warning, "\e[1;33m" },
{error, "\e[1;31m" },
{critical, "\e[1;35m" },
{alert, "\e[1;44m" },
{emergency, "\e[1;41m" }
]},
%% Whether to write a crash log, and where. Undefined means no crash logger. %% Whether to write a crash log, and where. Undefined means no crash logger.
{crash_log, "log/crash.log"}, {crash_log, "log/crash.log"},
%% Maximum size in bytes of events in the crash log - defaults to 65536 %% Maximum size in bytes of events in the crash log - defaults to 65536

+ 4
- 4
src/lager_app.erl View File

@ -78,11 +78,11 @@ start(_StartType, _StartArgs) ->
{ok, false} -> {ok, false} ->
[]; [];
_ -> _ ->
case application:get_env(lager, error_logger_whitelist) of
WhiteList = case application:get_env(lager, error_logger_whitelist) of
undefined -> undefined ->
WhiteList = [];
{ok, WhiteList} ->
WhiteList
[];
{ok, WhiteList0} ->
WhiteList0
end, end,
case supervisor:start_child(lager_handler_watcher_sup, [error_logger, error_logger_lager_h, [HighWaterMark]]) of case supervisor:start_child(lager_handler_watcher_sup, [error_logger, error_logger_lager_h, [HighWaterMark]]) of

+ 40
- 19
src/lager_console_backend.erl View File

@ -24,7 +24,7 @@
-export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2, -export([init/1, handle_call/2, handle_event/2, handle_info/2, terminate/2,
code_change/3]). code_change/3]).
-record(state, {level, formatter,format_config}).
-record(state, {level, formatter,format_config,colors=[]}).
-ifdef(TEST). -ifdef(TEST).
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
@ -32,26 +32,33 @@
-endif. -endif.
-include("lager.hrl"). -include("lager.hrl").
-define(TERSE_FORMAT,[time, " [", severity,"] ", message, "\r\n"]).
-define(TERSE_FORMAT,[time, " ", color, "[", severity,"] ", message]).
%% @private %% @private
init([Level, true]) -> % for backwards compatibility init([Level, true]) -> % for backwards compatibility
init([Level,{lager_default_formatter,[{eol, "\r\n"}]}]);
init([Level,{lager_default_formatter,[{eol, eol()}]}]);
init([Level,false]) -> % for backwards compatibility init([Level,false]) -> % for backwards compatibility
init([Level,{lager_default_formatter,?TERSE_FORMAT}]);
init([Level,{lager_default_formatter,?TERSE_FORMAT ++ [eol()]}]);
init([Level,{Formatter,FormatterConfig}]) when is_atom(Formatter) -> init([Level,{Formatter,FormatterConfig}]) when is_atom(Formatter) ->
try lager_util:config_to_mask(Level) of
Colors = case application:get_env(lager, colored) of
{ok, true} ->
{ok, LagerColors} = application:get_env(lager, colors),
LagerColors;
_ -> []
end,
try lager_util:config_to_mask(Level) of
Levels -> Levels ->
{ok, #state{level=Levels, {ok, #state{level=Levels,
formatter=Formatter, formatter=Formatter,
format_config=FormatterConfig}}
format_config=FormatterConfig,
colors=Colors}}
catch catch
_:_ -> _:_ ->
{error, bad_log_level} {error, bad_log_level}
end; end;
init(Level) -> init(Level) ->
init([Level,{lager_default_formatter,?TERSE_FORMAT}]).
init([Level,{lager_default_formatter,?TERSE_FORMAT ++ [eol()]}]).
%% @private %% @private
@ -70,10 +77,10 @@ handle_call(_Request, State) ->
%% @private %% @private
handle_event({log, Message}, handle_event({log, Message},
#state{level=L,formatter=Formatter,format_config=FormatConfig} = State) ->
#state{level=L,formatter=Formatter,format_config=FormatConfig,colors=Colors} = State) ->
case lager_util:is_loggable(Message, L, ?MODULE) of case lager_util:is_loggable(Message, L, ?MODULE) of
true -> true ->
io:put_chars(user, Formatter:format(Message,FormatConfig)),
io:put_chars(user, Formatter:format(Message,FormatConfig,Colors)),
{ok, State}; {ok, State};
false -> false ->
{ok, State} {ok, State}
@ -93,6 +100,14 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) -> code_change(_OldVsn, State, _Extra) ->
{ok, State}. {ok, State}.
eol() ->
case application:get_env(lager, colored) of
{ok, true} ->
"\e[0m\r\n";
_ ->
"\r\n"
end.
-ifdef(TEST). -ifdef(TEST).
console_log_test_() -> console_log_test_() ->
%% tiny recursive fun that pretends to be a group leader %% tiny recursive fun that pretends to be a group leader
@ -131,16 +146,17 @@ console_log_test_() ->
{"regular console logging", {"regular console logging",
fun() -> fun() ->
Pid = spawn(F(self())), Pid = spawn(F(self())),
gen_event:add_handler(lager_event, lager_console_backend, info),
unregister(user), unregister(user),
register(user, Pid), register(user, Pid),
erlang:group_leader(Pid, whereis(lager_event)), erlang:group_leader(Pid, whereis(lager_event)),
gen_event:add_handler(lager_event, lager_console_backend, info),
lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
lager:log(info, self(), "Test message"), lager:log(info, self(), "Test message"),
receive receive
{io_request, From, ReplyAs, {put_chars, unicode, Msg}} -> {io_request, From, ReplyAs, {put_chars, unicode, Msg}} ->
From ! {io_reply, ReplyAs, ok}, From ! {io_reply, ReplyAs, ok},
?assertMatch([_, "[info]", "Test message\r\n"], re:split(Msg, " ", [{return, list}, {parts, 3}]))
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[info]", TestMsg], re:split(Msg, " ", [{return, list}, {parts, 3}]))
after after
500 -> 500 ->
?assert(false) ?assert(false)
@ -156,11 +172,11 @@ console_log_test_() ->
gen_event:add_handler(lager_event, lager_console_backend, [info, true]), gen_event:add_handler(lager_event, lager_console_backend, [info, true]),
lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}), lager_config:set(loglevel, {element(2, lager_util:config_to_mask(info)), []}),
lager:info("Test message"), lager:info("Test message"),
lager:info("Test message"),
PidStr = pid_to_list(self()), PidStr = pid_to_list(self()),
receive receive
{io_request, _, _, {put_chars, unicode, Msg}} -> {io_request, _, _, {put_chars, unicode, Msg}} ->
?assertMatch([_, _, "[info]", PidStr, _,"Test message\r\n"], re:split(Msg, "[ @]", [{return, list}, {parts, 6}]))
TestMsg = "Test message" ++ eol(),
?assertMatch([_, _, "[info]", PidStr, _, TestMsg], re:split(Msg, "[ @]", [{return, list}, {parts, 6}]))
after after
500 -> 500 ->
?assert(false) ?assert(false)
@ -183,7 +199,8 @@ console_log_test_() ->
ModuleStr = atom_to_list(?MODULE), ModuleStr = atom_to_list(?MODULE),
receive receive
{io_request, _, _, {put_chars, unicode, Msg}} -> {io_request, _, _, {put_chars, unicode, Msg}} ->
?assertMatch([_, _, "info", NodeStr, PidStr, ModuleStr, _, _, _, "Test message\r\n"],
TestMsg = "Test message" ++ eol(),
?assertMatch([_, _, "info", NodeStr, PidStr, ModuleStr, _, _, _, TestMsg],
re:split(Msg, "#", [{return, list}, {parts, 10}])) re:split(Msg, "#", [{return, list}, {parts, 10}]))
after after
500 -> 500 ->
@ -213,7 +230,8 @@ console_log_test_() ->
receive receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} -> {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok}, From1 ! {io_reply, ReplyAs1, ok},
?assertMatch([_, "[debug]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[debug]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after after
500 -> 500 ->
?assert(false) ?assert(false)
@ -242,7 +260,8 @@ console_log_test_() ->
receive receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} -> {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok}, From1 ! {io_reply, ReplyAs1, ok},
?assertMatch([_, "[error]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[error]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after after
1000 -> 1000 ->
?assert(false) ?assert(false)
@ -271,7 +290,8 @@ console_log_test_() ->
receive receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} -> {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok}, From1 ! {io_reply, ReplyAs1, ok},
?assertMatch([_, "[debug]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[debug]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after after
1000 -> 1000 ->
?assert(false) ?assert(false)
@ -301,7 +321,8 @@ console_log_test_() ->
receive receive
{io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} -> {io_request, From1, ReplyAs1, {put_chars, unicode, Msg1}} ->
From1 ! {io_reply, ReplyAs1, ok}, From1 ! {io_reply, ReplyAs1, ok},
?assertMatch([_, "[debug]", "Test message\r\n"], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
TestMsg = "Test message" ++ eol(),
?assertMatch([_, "[debug]", TestMsg], re:split(Msg1, " ", [{return, list}, {parts, 3}]))
after after
1000 -> 1000 ->
?assert(false) ?assert(false)

+ 23
- 9
src/lager_default_formatter.erl View File

@ -27,7 +27,7 @@
%% %%
%% Exported Functions %% Exported Functions
%% %%
-export([format/2]).
-export([format/2, format/3]).
%% %%
%% API Functions %% API Functions
@ -53,22 +53,28 @@
%% %%
%% `[{pid, ["My pid is ", pid], "Unknown Pid"}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid" %% `[{pid, ["My pid is ", pid], "Unknown Pid"}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid"
%% @end %% @end
-spec format(lager_msg:lager_msg(),list()) -> any().
format(Msg,[]) ->
format(Msg, [{eol, "\n"}]);
format(Msg,[{eol, EOL}]) ->
-spec format(lager_msg:lager_msg(),list(),list()) -> any().
format(Msg,[], Colors) ->
format(Msg, [{eol, "\n"}], Colors);
format(Msg,[{eol, EOL}], Colors) ->
format(Msg, format(Msg,
[date, " ", time, " [", severity, "] ",
[date, " ", time, " ", color, "[", severity, "] ",
{pid, ""}, {pid, ""},
{module, [ {module, [
{pid, ["@"], ""}, {pid, ["@"], ""},
module, module,
{function, [":", function], ""}, {function, [":", function], ""},
{line, [":",line], ""}], ""}, {line, [":",line], ""}], ""},
" ", message, EOL]);
format(Message,Config) ->
[ output(V,Message) || V <- Config ].
" ", message, EOL], Colors);
format(Message,Config,Colors) ->
[ case V of
color -> output_color(Message,Colors);
_ -> output(V,Message)
end || V <- Config ].
-spec format(lager_msg:lager_msg(),list()) -> any().
format(Msg, Config) ->
format(Msg, Config, []).
-spec output(term(),lager_msg:lager_msg()) -> iolist(). -spec output(term(),lager_msg:lager_msg()) -> iolist().
output(message,Msg) -> lager_msg:message(Msg); output(message,Msg) -> lager_msg:message(Msg);
@ -97,6 +103,14 @@ output({Prop, Present, Absent}, Msg) when is_atom(Prop) ->
end; end;
output(Other,_) -> make_printable(Other). output(Other,_) -> make_printable(Other).
output_color(_Msg,[]) -> [];
output_color(Msg,Colors) ->
Level = lager_msg:severity(Msg),
case lists:keyfind(Level, 1, Colors) of
{_, Color} -> Color;
_ -> []
end.
-spec make_printable(any()) -> iolist(). -spec make_printable(any()) -> iolist().
make_printable(A) when is_atom(A) -> atom_to_list(A); make_printable(A) when is_atom(A) -> atom_to_list(A);
make_printable(P) when is_pid(P) -> pid_to_list(P); make_printable(P) when is_pid(P) -> pid_to_list(P);

Loading…
Cancel
Save