Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request erlang-lager#74 from basho/adt-tensorwrench-integr…
…ation-2

Changed the messages sent to the backends to include metadata and separated formatting from the backend
  • Loading branch information
Vagabond committed Sep 28, 2012
2 parents d8ad5eb + e04830b commit 9981ca0
Show file tree
Hide file tree
Showing 23 changed files with 788 additions and 557 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -4,3 +4,4 @@ ebin
doc
*.swp
erl_crash.dump
.project
2 changes: 1 addition & 1 deletion Makefile
Expand Up @@ -39,7 +39,7 @@ dialyzer: compile
@echo Use "'make build_plt'" to build PLT prior to using this target.
@echo
@sleep 1
dialyzer -Wno_return -Wunmatched_returns --plt $(COMBO_PLT) ebin | \
dialyzer -Wunmatched_returns --plt $(COMBO_PLT) ebin | \
fgrep -v -f ./dialyzer.ignore-warnings

cleanplt:
Expand Down
39 changes: 39 additions & 0 deletions README.org
Expand Up @@ -74,6 +74,45 @@
The available configuration options for each backend are listed in their
module's documentation.

* Custom Formatting
All loggers have a default formatting that can be overriden. A formatter is any module that
exports format(#lager_log_message{},Config#any()). It is specified as part of the configuration
for the backend:

#+BEGIN_EXAMPLE
{lager, [
{handlers, [
{lager_console_backend, [info, {lager_default_formatter, [time," [",severity,"] ", message, "\n"]}},
{lager_file_backend, [
[{"error.log", error, 10485760, "$D0", 5,{lager_default_formatter,[date, " ", time," [",severity,"] ",pid, " ", message, "\n"]}],
{"console.log", info, 10485760, "$D0", 5}
]}
]}
]}.
#+END_EXAMPLE

Included is lager_default_formatter. This provides a generic, default formatting for log messages using a "semi-iolist"
as configuration. Any iolist allowed elements in the configuration are printed verbatim. Atoms in the configuration
are treated as metadata properties and extracted from the log message.
The metadata properties date,time, message, and severity will always exist.
The properties pid, file, line, module, and function will always exist if the parser transform is used.

#+BEGIN_EXAMPLE
["Foo"] -> "Foo", regardless of message content.
[message] -> The content of the logged message, alone.
[{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
[{pid, ["My pid is ", pid], "Unknown Pid"}] -> if pid is in the metadata print "My pid is <?.?.?>", otherwise print "Unknown Pid"
#+END_EXAMPLE

Optionally, a tuple of {atom(),semi-iolist()}
can be used. The atom will look up the property, but if not found it will use the semi-iolist() instead. These fallbacks
can be nested or refer to other properties.

#+BEGIN_EXAMPLE
[{pid,"Unknown Pid"}] -> "<?.?.?>" if pid is in the metadata, "Unknown Pid" if not.
[{server,[$(,{pid,"Unknown Server"},$)]}}] -> user provided server metadata, otherwise "(<?.?.?>)", otherwise "(Unknown Server)"
#+END_EXAMPLE

* Error logger integration
Lager is also supplied with a error_logger handler module that translates
traditional erlang error messages into a friendlier format and sends them into
Expand Down
15 changes: 11 additions & 4 deletions include/lager.hrl
@@ -1,4 +1,4 @@
%% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
%% Copyright (c) 2011-2012 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
Expand All @@ -14,6 +14,9 @@
%% specific language governing permissions and limitations
%% under the License.


-define(DEFAULT_TRUNCATION, 4096).

-define(LEVELS,
[debug, info, notice, warning, error, critical, alert, emergency, none]).

Expand Down Expand Up @@ -55,9 +58,12 @@
lager_util:level_to_num(Level) =< element(1, lager_mochiglobal:get(loglevel, {?LOG_NONE, []}))).

-define(NOTIFY(Level, Pid, Format, Args),
gen_event:notify(lager_event, {log, lager_util:level_to_num(Level),
lager_util:format_time(), [io_lib:format("[~p] ", [Level]),
io_lib:format("~p ", [Pid]), io_lib:format(Format, Args)]})).
gen_event:notify(lager_event, {log, lager_msg:new(io_lib:format(Format, Args),
lager_util:format_time(),
Level,
[{pid,Pid},{line,?LINE},{file,?FILE},{module,?MODULE}],
[])}
)).

%% FOR INTERNAL USE ONLY
%% internal non-blocking logging call
Expand Down Expand Up @@ -93,3 +99,4 @@
end
end)).
-endif.

20 changes: 10 additions & 10 deletions src/error_logger_lager_h.erl
@@ -1,4 +1,4 @@
%% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
%% Copyright (c) 2011-2012 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
Expand Down Expand Up @@ -88,7 +88,7 @@ handle_event(Event, State) ->
[ID, Name, format_reason(Reason)]);
_ ->
?CRASH_LOG(Event),
?LOG(error, Pid, lager:safe_format(Fmt, Args, 4096))
?LOG(error, Pid, lager:safe_format(Fmt, Args, ?DEFAULT_TRUNCATION))
end;
{error_report, _GL, {Pid, std_error, D}} ->
?CRASH_LOG(Event),
Expand All @@ -102,17 +102,17 @@ handle_event(Event, State) ->
"Supervisor ~w had child ~s exit with reason ~s in context ~w",
[element(2, Name), Offender, format_reason(Reason), Ctx]);
_ ->
?LOG(error, Pid, ["SUPERVISOR REPORT ", print_silly_list(D)])
?LOG(error, Pid, "SUPERVISOR REPORT " ++ print_silly_list(D))
end;
{error_report, _GL, {Pid, crash_report, [Self, Neighbours]}} ->
?CRASH_LOG(Event),
?LOG(error, Pid, ["CRASH REPORT ", format_crash_report(Self, Neighbours)]);
?LOG(error, Pid, "CRASH REPORT " ++ format_crash_report(Self, Neighbours));
{warning_msg, _GL, {Pid, Fmt, Args}} ->
?LOG(warning, Pid, lager:safe_format(Fmt, Args, 4096));
?LOG(warning, Pid, lager:safe_format(Fmt, Args, ?DEFAULT_TRUNCATION));
{warning_report, _GL, {Pid, std_warning, Report}} ->
?LOG(warning, Pid, print_silly_list(Report));
{info_msg, _GL, {Pid, Fmt, Args}} ->
?LOG(info, Pid, lager:safe_format(Fmt, Args, 4096));
?LOG(info, Pid, lager:safe_format(Fmt, Args, ?DEFAULT_TRUNCATION));
{info_report, _GL, {Pid, std_info, D}} when is_list(D) ->
Details = lists:sort(D),
case Details of
Expand All @@ -136,7 +136,7 @@ handle_event(Event, State) ->
?LOG(debug, P, "Supervisor ~w started ~s at pid ~w",
[element(2, Name), MFA, Pid]);
_ ->
?LOG(info, P, ["PROGRESS REPORT ", print_silly_list(D)])
?LOG(info, P, "PROGRESS REPORT " ++ print_silly_list(D))
end;
_ ->
?LOG(warning, self(), "Unexpected error_logger event ~w", [Event])
Expand Down Expand Up @@ -292,17 +292,17 @@ format_args([H|T], FmtAcc, ArgsAcc) ->
print_silly_list(L) when is_list(L) ->
case lager_stdlib:string_p(L) of
true ->
lager_trunc_io:format("~s", [L], 4096);
lager_trunc_io:format("~s", [L], ?DEFAULT_TRUNCATION);
_ ->
print_silly_list(L, [], [])
end;
print_silly_list(L) ->
{Str, _} = lager_trunc_io:print(L, 4096),
{Str, _} = lager_trunc_io:print(L, ?DEFAULT_TRUNCATION),
Str.

print_silly_list([], Fmt, Acc) ->
lager_trunc_io:format(string:join(lists:reverse(Fmt), ", "),
lists:reverse(Acc), 4096);
lists:reverse(Acc), ?DEFAULT_TRUNCATION);
print_silly_list([{K,V}|T], Fmt, Acc) ->
print_silly_list(T, ["~p: ~p" | Fmt], [V, K | Acc]);
print_silly_list([H|T], Fmt, Acc) ->
Expand Down
112 changes: 41 additions & 71 deletions src/lager.erl
@@ -1,4 +1,4 @@
%% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
%% Copyright (c) 2011-2012 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
Expand All @@ -19,15 +19,16 @@
-module(lager).

-include("lager.hrl").
-include_lib("eunit/include/eunit.hrl").

%% API
-export([start/0,
log/9, log_dest/10, log/3, log/4,
log/3, log/4,
trace_file/2, trace_file/3, trace_console/1, trace_console/2,
clear_all_traces/0, stop_trace/1, 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,dispatch_log/9]).
safe_format/3, safe_format_chop/3,dispatch_log/5]).

-type log_level() :: debug | info | notice | warning | error | critical | alert | emergency.
-type log_level_number() :: 0..7.
Expand All @@ -52,69 +53,47 @@ start_ok(App, {error, Reason}) ->
erlang:error({app_start_failed, App, Reason}).


-spec dispatch_log(log_level(), atom(), atom(), pos_integer(), pid(), list(), string(), list(), integer()) ->
ok | {error, lager_not_running}.

dispatch_log(Severity, Module, Function, Line, Pid, Traces, Format, Args, TruncSize) ->
{LevelThreshold,TraceFilters} = lager_mochiglobal:get(loglevel,{?LOG_NONE,[]}),
Result=
case LevelThreshold >= lager_util:level_to_num(Severity) of
true -> lager:log(Severity,Module,Function,Line,Pid,
lager_util:maybe_utc(lager_util:localtime_ms()),
Format,Args,TruncSize);
_ -> ok
end,
case TraceFilters of
[] -> Result;
Match when is_list(Match) ->
lager:log_dest(Severity,Module,Function,Line,Pid,
lager_util:maybe_utc(lager_util:localtime_ms()),
lager_util:check_traces(Traces,
lager_util:level_to_num(Severity),
TraceFilters,
[]),
Format,Args,TruncSize);
_ -> ok
-spec dispatch_log(log_level(), list(), string(), list() | none, pos_integer()) -> ok | {error, lager_not_running}.
dispatch_log(Severity, Metadata, Format, Args, Size) when is_atom(Severity)->
case whereis(lager_event) of
undefined ->
%% lager isn't running
{error, lager_not_running};
Pid ->
{LevelThreshold,TraceFilters} = lager_mochiglobal:get(loglevel,{?LOG_NONE,[]}),
SeverityAsInt=lager_util:level_to_num(Severity),
Destinations = case TraceFilters of
[] -> [];
_ ->
lager_util:check_traces(Metadata,SeverityAsInt,TraceFilters,[])
end,
case (LevelThreshold >= SeverityAsInt orelse Destinations =/= []) of
true ->
Timestamp = lager_util:format_time(),
Msg=case Args of
A when is_list(A) ->safe_format_chop(Format,Args,Size);
_ -> Format
end,
gen_event:sync_notify(Pid, {log, lager_msg:new(Msg, Timestamp,
Severity, Metadata, Destinations)});
_ ->
ok
end
end.

%% @private
-spec log(log_level(), atom(), atom(), pos_integer(), pid(), tuple(), string(), list(), integer()) ->
ok | {error, lager_not_running}.
log(Level, Module, Function, Line, Pid, Time, Format, Args, TruncSize) ->
Timestamp = lager_util:format_time(Time),
Msg = [["[", atom_to_list(Level), "] "],
io_lib:format("~p@~p:~p:~p ", [Pid, Module, Function, Line]),
safe_format_chop(Format, Args, TruncSize)],
safe_notify({log, lager_util:level_to_num(Level), Timestamp, Msg}).

%% @private
-spec log_dest(log_level(), atom(), atom(), pos_integer(), pid(), tuple(), list(), string(), list(), integer()) ->
ok | {error, lager_not_running}.
log_dest(_Level, _Module, _Function, _Line, _Pid, _Time, [], _Format, _Args, _TruncSize) ->
ok;
log_dest(Level, Module, Function, Line, Pid, Time, Dest, Format, Args, TruncSize) ->
Timestamp = lager_util:format_time(Time),
Msg = [["[", atom_to_list(Level), "] "],
io_lib:format("~p@~p:~p:~p ", [Pid, Module, Function, Line]),
safe_format_chop(Format, Args, TruncSize)],
safe_notify({log, Dest, lager_util:level_to_num(Level), Timestamp, Msg}).


%% @doc Manually log a message into lager without using the parse transform.
-spec log(log_level(), pid(), list()) -> ok | {error, lager_not_running}.
log(Level, Pid, Message) ->
Timestamp = lager_util:format_time(),
Msg = [["[", atom_to_list(Level), "] "], io_lib:format("~p ", [Pid]),
safe_format_chop("~s", [Message], 4096)],
safe_notify({log, lager_util:level_to_num(Level), Timestamp, Msg}).
-spec log(log_level(), pid() | [tuple(),...], list()) -> ok | {error, lager_not_running}.
log(Level, Pid, Message) when is_pid(Pid) ->
dispatch_log(Level, [{pid,Pid}], Message, [], ?DEFAULT_TRUNCATION);
log(Level, Metadata, Message) when is_list(Metadata) ->
dispatch_log(Level, Metadata, Message, [], ?DEFAULT_TRUNCATION).

%% @doc Manually log a message into lager without using the parse transform.
-spec log(log_level(), pid(), string(), list()) -> ok | {error, lager_not_running}.
log(Level, Pid, Format, Args) ->
Timestamp = lager_util:format_time(),
Msg = [["[", atom_to_list(Level), "] "], io_lib:format("~p ", [Pid]),
safe_format_chop(Format, Args, 4096)],
safe_notify({log, lager_util:level_to_num(Level), Timestamp, Msg}).
-spec log(log_level(), pid() | [tuple(),...], string(), list()) -> ok | {error, lager_not_running}.
log(Level, Pid, Format, Args) when is_pid(Pid) ->
dispatch_log(Level, [{pid,Pid}], Format, Args, ?DEFAULT_TRUNCATION);
log(Level, Metadata, Format, Args) when is_list(Metadata) ->
dispatch_log(Level, Metadata, Format, Args, ?DEFAULT_TRUNCATION).

trace_file(File, Filter) ->
trace_file(File, Filter, debug).
Expand Down Expand Up @@ -257,7 +236,7 @@ posix_error(Error) when is_atom(Error) ->
Message -> Message
end;
posix_error(Error) ->
safe_format_chop("~p", [Error], 4096).
safe_format_chop("~p", [Error], ?DEFAULT_TRUNCATION).

%% @private
get_loglevels() ->
Expand All @@ -270,15 +249,6 @@ minimum_loglevel([]) ->
minimum_loglevel(Levels) ->
erlang:hd(lists:reverse(lists:sort(Levels))).

safe_notify(Event) ->
case whereis(lager_event) of
undefined ->
%% lager isn't running
{error, lager_not_running};
Pid ->
gen_event:sync_notify(Pid, Event)
end.

%% @doc Print the format string `Fmt' with `Args' safely with a size
%% limit of `Limit'. If the format string is invalid, or not enough
%% arguments are supplied 'FORMAT ERROR' is printed with the offending
Expand Down
44 changes: 41 additions & 3 deletions src/lager_app.erl
@@ -1,4 +1,4 @@
%% Copyright (c) 2011 Basho Technologies, Inc. All Rights Reserved.
%% Copyright (c) 2011-2012 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
Expand All @@ -22,7 +22,9 @@

-behaviour(application).
-include("lager.hrl").

-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
-export([start/0,
start/2,
stop/1]).
Expand Down Expand Up @@ -77,7 +79,43 @@ stop(Handlers) ->
expand_handlers([]) ->
[];
expand_handlers([{lager_file_backend, Configs}|T]) ->
[{{lager_file_backend, element(1, Config)}, Config} || Config <- Configs] ++
[ to_config(Config) || Config <- Configs] ++
expand_handlers(T);
expand_handlers([H|T]) ->
[H | expand_handlers(T)].

to_config({Name,Severity}) ->
{{lager_file_backend, Name}, {Name, Severity}};
to_config({Name,_Severity,_Size,_Rotation,_Count}=Config) ->
{{lager_file_backend, Name}, Config};
to_config({Name,Severity,Size,Rotation,Count,Format}) ->
{{lager_file_backend, Name}, {Name,Severity,Size,Rotation,Count},Format}.



-ifdef(TEST).
application_config_mangling_test_() ->
[{"Explode the file backend handlers",
?_assertMatch(
[{lager_console_backend, info},
{{lager_file_backend,"error.log"},{"error.log",error,10485760, "$D0",5}},
{{lager_file_backend,"console.log"},{"console.log",info,10485760, "$D0",5}}
],
expand_handlers([{lager_console_backend, info},
{lager_file_backend, [
{"error.log", error, 10485760, "$D0", 5},
{"console.log", info, 10485760, "$D0", 5}
]}]
))},
{"Explode with formatter info",
?_assertMatch(
[{{lager_file_backend,"test.log"}, {"test.log", debug, 10485760, "$D0", 5},{lager_default_formatter,["[",severity,"] ", message, "\n"]}},
{{lager_file_backend,"test2.log"}, {"test2.log",debug, 10485760, "$D0", 5},{lager_default_formatter,["2>[",severity,"] ", message, "\n"]}}],
expand_handlers([{lager_file_backend, [
{"test.log", debug, 10485760, "$D0", 5,{lager_default_formatter,["[",severity,"] ", message, "\n"]}},
{"test2.log",debug, 10485760, "$D0", 5,{lager_default_formatter,["2>[",severity,"] ",message, "\n"]}}
]
}])
)
}].
-endif.

0 comments on commit 9981ca0

Please sign in to comment.