Browse Source

Support for separate sing for error_logger messages

pull/303/head
Daniil Fedotov 9 years ago
parent
commit
2248a2aad1
3 changed files with 60 additions and 31 deletions
  1. +17
    -0
      README.md
  2. +2
    -0
      include/lager.hrl
  3. +41
    -31
      src/error_logger_lager_h.erl

+ 17
- 0
README.md View File

@ -231,6 +231,23 @@ application variable. If set to `undefined` it is not written at all.
Messages in the crash log are subject to a maximum message size which can be
specified via the `crash_log_msg_size` application variable.
Messages from `error_logger` will be redirected to `error_logger_lager_event` sink
if it is defined so it can be redirected to another log file.
For example:
```
[{lager, [
{extra_sinks,
[
{error_logger_lager_event,
[{handlers, [
{lager_file_backend, [{file, "error_logger.log"}, {level, info}]}]
}]
}]
}]
}].
```
Will send all `error_logger` messages to `error_logger.log` file.
Overload Protection
-------------------

+ 2
- 0
include/lager.hrl View File

@ -18,6 +18,8 @@
-define(DEFAULT_TRUNCATION, 4096).
-define(DEFAULT_TRACER, lager_default_tracer).
-define(DEFAULT_SINK, lager_event).
-define(ERROR_LOGGER_SINK, error_logger_lager_event).
-define(LEVELS,
[debug, info, notice, warning, error, critical, alert, emergency, none]).

+ 41
- 31
src/error_logger_lager_h.erl View File

@ -34,23 +34,24 @@
-export([format_reason/1, format_mfa/1, format_args/3]).
-record(state, {
sink :: atom(),
shaper :: lager_shaper(),
%% group leader strategy
groupleader_strategy :: handle | ignore | mirror
}).
-define(LOGMSG(Level, Pid, Msg),
-define(LOGMSG(Sink, Level, Pid, Msg),
case ?SHOULD_LOG(Level) of
true ->
_ =lager:log(Level, Pid, Msg),
_ =lager:log(Sink, Level, Pid, Msg, []),
ok;
_ -> ok
end).
-define(LOGFMT(Level, Pid, Fmt, Args),
-define(LOGFMT(Sink, Level, Pid, Fmt, Args),
case ?SHOULD_LOG(Level) of
true ->
_ = lager:log(Level, Pid, Fmt, Args),
_ = lager:log(Sink, Level, Pid, Fmt, Args),
ok;
_ -> ok
end).
@ -71,7 +72,8 @@ set_high_water(N) ->
-spec init(any()) -> {ok, #state{}}.
init([HighWaterMark, GlStrategy]) ->
Shaper = #lager_shaper{hwm=HighWaterMark},
{ok, #state{shaper=Shaper, groupleader_strategy=GlStrategy}}.
Sink = configured_sink(),
{ok, #state{sink=Sink, shaper=Shaper, groupleader_strategy=GlStrategy}}.
handle_call({set_high_water, N}, #state{shaper=Shaper} = State) ->
NewShaper = Shaper#lager_shaper{hwm=N},
@ -79,12 +81,12 @@ handle_call({set_high_water, N}, #state{shaper=Shaper} = State) ->
handle_call(_Request, State) ->
{ok, unknown_call, State}.
handle_event(Event, #state{shaper=Shaper} = State) ->
handle_event(Event, #state{sink=Sink, shaper=Shaper} = State) ->
case lager_util:check_hwm(Shaper) of
{true, 0, NewShaper} ->
eval_gl(Event, State#state{shaper=NewShaper});
{true, Drop, #lager_shaper{hwm=Hwm} = NewShaper} when Drop > 0 ->
?LOGFMT(warning, self(),
?LOGFMT(Sink, warning, self(),
"lager_error_logger_h dropped ~p messages in the last second that exceeded the limit of ~p messages/sec",
[Drop, Hwm]),
eval_gl(Event, State#state{shaper=NewShaper});
@ -98,11 +100,19 @@ handle_info(_Info, State) ->
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, {state, Shaper, GLStrategy}, _Extra) ->
{ok, #state{sink=configured_sink(), shaper=Shaper, groupleader_strategy=GLStrategy}};
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% internal functions
configured_sink() ->
case proplists:get_value(?ERROR_LOGGER_SINK, application:get_env(lager, extra_sinks, [])) of
undefined -> ?DEFAULT_SINK;
_ -> ?ERROR_LOGGER_SINK
end.
eval_gl(Event, #state{groupleader_strategy=GlStrategy0}=State) when is_pid(element(2, Event)) ->
case element(2, Event) of
GL when node(GL) =/= node(), GlStrategy0 =:= ignore ->
@ -117,7 +127,7 @@ eval_gl(Event, #state{groupleader_strategy=GlStrategy0}=State) when is_pid(eleme
eval_gl(Event, State) ->
log_event(Event, State).
log_event(Event, State) ->
log_event(Event, #state{sink=Sink} = State) ->
case Event of
{error, _GL, {Pid, Fmt, Args}} ->
case Fmt of
@ -125,19 +135,19 @@ log_event(Event, State) ->
%% gen_server terminate
[Name, _Msg, _State, Reason] = Args,
?CRASH_LOG(Event),
?LOGFMT(error, Pid, "gen_server ~w terminated with reason: ~s",
?LOGFMT(Sink, error, Pid, "gen_server ~w terminated with reason: ~s",
[Name, format_reason(Reason)]);
"** State machine "++_ ->
%% gen_fsm terminate
[Name, _Msg, StateName, _StateData, Reason] = Args,
?CRASH_LOG(Event),
?LOGFMT(error, Pid, "gen_fsm ~w in state ~w terminated with reason: ~s",
?LOGFMT(Sink, error, Pid, "gen_fsm ~w in state ~w terminated with reason: ~s",
[Name, StateName, format_reason(Reason)]);
"** gen_event handler"++_ ->
%% gen_event handler terminate
[ID, Name, _Msg, _State, Reason] = Args,
?CRASH_LOG(Event),
?LOGFMT(error, Pid, "gen_event ~w installed in ~w terminated with reason: ~s",
?LOGFMT(Sink, error, Pid, "gen_event ~w installed in ~w terminated with reason: ~s",
[ID, Name, format_reason(Reason)]);
"** Cowboy handler"++_ ->
%% Cowboy HTTP server error
@ -145,13 +155,13 @@ log_event(Event, State) ->
case Args of
[Module, Function, Arity, _Request, _State] ->
%% we only get the 5-element list when its a non-exported function
?LOGFMT(error, Pid,
?LOGFMT(Sink, error, Pid,
"Cowboy handler ~p terminated with reason: call to undefined function ~p:~p/~p",
[Module, Module, Function, Arity]);
[Module, Function, Arity, _Class, Reason | Tail] ->
%% any other cowboy error_format list *always* ends with the stacktrace
StackTrace = lists:last(Tail),
?LOGFMT(error, Pid,
?LOGFMT(Sink, error, Pid,
"Cowboy handler ~p terminated in ~p:~p/~p with reason: ~s",
[Module, Module, Function, Arity, format_reason({Reason, StackTrace})])
end;
@ -160,11 +170,11 @@ log_event(Event, State) ->
?CRASH_LOG(Event),
case Args of
[Ref, _Protocol, Worker, {[{reason, Reason}, {mfa, {Module, Function, Arity}}, {stacktrace, StackTrace} | _], _}] ->
?LOGFMT(error, Worker,
?LOGFMT(Sink, error, Worker,
"Ranch listener ~p terminated in ~p:~p/~p with reason: ~s",
[Ref, Module, Function, Arity, format_reason({Reason, StackTrace})]);
[Ref, _Protocol, Worker, Reason] ->
?LOGFMT(error, Worker,
?LOGFMT(Sink, error, Worker,
"Ranch listener ~p terminated with reason: ~s",
[Ref, format_reason(Reason)])
end;
@ -179,34 +189,34 @@ log_event(Event, State) ->
_ ->
Error
end,
?LOGFMT(error, Pid, "Webmachine error at path ~p : ~s", [Path, format_reason(StackTrace)]);
?LOGFMT(Sink, error, Pid, "Webmachine error at path ~p : ~s", [Path, format_reason(StackTrace)]);
_ ->
?CRASH_LOG(Event),
?LOGFMT(error, Pid, Fmt, Args)
?LOGFMT(Sink, error, Pid, Fmt, Args)
end;
{error_report, _GL, {Pid, std_error, D}} ->
?CRASH_LOG(Event),
?LOGMSG(error, Pid, print_silly_list(D));
?LOGMSG(Sink, error, Pid, print_silly_list(D));
{error_report, _GL, {Pid, supervisor_report, D}} ->
?CRASH_LOG(Event),
case lists:sort(D) of
[{errorContext, Ctx}, {offender, Off}, {reason, Reason}, {supervisor, Name}] ->
Offender = format_offender(Off),
?LOGFMT(error, Pid,
?LOGFMT(Sink, error, Pid,
"Supervisor ~w had child ~s exit with reason ~s in context ~w",
[supervisor_name(Name), Offender, format_reason(Reason), Ctx]);
_ ->
?LOGMSG(error, Pid, "SUPERVISOR REPORT " ++ print_silly_list(D))
?LOGMSG(Sink, error, Pid, "SUPERVISOR REPORT " ++ print_silly_list(D))
end;
{error_report, _GL, {Pid, crash_report, [Self, Neighbours]}} ->
?CRASH_LOG(Event),
?LOGMSG(error, Pid, "CRASH REPORT " ++ format_crash_report(Self, Neighbours));
?LOGMSG(Sink, error, Pid, "CRASH REPORT " ++ format_crash_report(Self, Neighbours));
{warning_msg, _GL, {Pid, Fmt, Args}} ->
?LOGFMT(warning, Pid, Fmt, Args);
?LOGFMT(Sink, warning, Pid, Fmt, Args);
{warning_report, _GL, {Pid, std_warning, Report}} ->
?LOGMSG(warning, Pid, print_silly_list(Report));
?LOGMSG(Sink, warning, Pid, print_silly_list(Report));
{info_msg, _GL, {Pid, Fmt, Args}} ->
?LOGFMT(info, Pid, Fmt, Args);
?LOGFMT(Sink, info, Pid, Fmt, Args);
{info_report, _GL, {Pid, std_info, D}} when is_list(D) ->
Details = lists:sort(D),
case Details of
@ -215,14 +225,14 @@ log_event(Event, State) ->
{ok, true} when Reason == stopped ->
ok;
_ ->
?LOGFMT(info, Pid, "Application ~w exited with reason: ~s",
?LOGFMT(Sink, info, Pid, "Application ~w exited with reason: ~s",
[App, format_reason(Reason)])
end;
_ ->
?LOGMSG(info, Pid, print_silly_list(D))
?LOGMSG(Sink, info, Pid, print_silly_list(D))
end;
{info_report, _GL, {Pid, std_info, D}} ->
?LOGFMT(info, Pid, "~w", [D]);
?LOGFMT(Sink, info, Pid, "~w", [D]);
{info_report, _GL, {P, progress, D}} ->
Details = lists:sort(D),
case Details of
@ -231,19 +241,19 @@ log_event(Event, State) ->
{ok, true} ->
ok;
_ ->
?LOGFMT(info, P, "Application ~w started on node ~w",
?LOGFMT(Sink, info, P, "Application ~w started on node ~w",
[App, Node])
end;
[{started, Started}, {supervisor, Name}] ->
MFA = format_mfa(get_value(mfargs, Started)),
Pid = get_value(pid, Started),
?LOGFMT(debug, P, "Supervisor ~w started ~s at pid ~w",
?LOGFMT(Sink, debug, P, "Supervisor ~w started ~s at pid ~w",
[supervisor_name(Name), MFA, Pid]);
_ ->
?LOGMSG(info, P, "PROGRESS REPORT " ++ print_silly_list(D))
?LOGMSG(Sink, info, P, "PROGRESS REPORT " ++ print_silly_list(D))
end;
_ ->
?LOGFMT(warning, self(), "Unexpected error_logger event ~w", [Event])
?LOGFMT(Sink, warning, self(), "Unexpected error_logger event ~w", [Event])
end,
{ok, State}.

Loading…
Cancel
Save