SisMaker 3 лет назад
Родитель
Сommit
89190b6499
5 измененных файлов: 407 добавлений и 412 удалений
  1. +2
    -2
      include/lgDef.hrl
  2. +3
    -3
      src/backend/lgBkdConsole.erl
  3. +2
    -2
      src/backend/lgBkdFile.erl
  4. +398
    -403
      src/eLog.erl
  5. +2
    -2
      src/utils/lgUtil.erl

+ 2
- 2
include/lgDef.hrl Просмотреть файл

@ -120,9 +120,9 @@
%%
-define(LgLevels, [debug, info, notice, warning, error, critical, alert, emergency, none]).
-define(LgShouldLog(Sink, Level), (lgUtil:levelToNum(Level) band ?eLogCfg:get(Sink)) /= 0).
-define(LgShouldLog(Sink, Level), (lgUtil:levelToNum(Level) band ?eLogCfg:get(Sink)) =/= 0).
-define(LgShouldLog(Level), (lgUtil:levelToNum(Level) band ?eLogCfg:get(?LgDefSink)) /= 0).
-define(LgShouldLog(Level), (lgUtil:levelToNum(Level) band ?eLogCfg:get(?LgDefSink)) =/= 0).
-define(LgNotify(Level, Pid, Format, Args),
gen_emm:info_notify(?LgDefSink, {mWriteLog, #lgMsg{severity = Level, pid = Pid, node = node(), module = ?MODULE, function = ?FUNCTION_NAME, line = ?LINE, metadata = [], datetime = lgUtil:msToBinStr(), timestamp = lgTime:nowMs(), message = eFmt:formatBin(Format, Args), destinations = []}})).

+ 3
- 3
src/backend/lgBkdConsole.erl Просмотреть файл

@ -62,7 +62,7 @@ checkOpts([]) -> true;
checkOpts([{id, {?MODULE, _}} | T]) ->
checkOpts(T);
checkOpts([{level, Level} | T]) ->
?IIF(lgUtil:validateLogLevel(Level) /= false, checkOpts(T), {error, {bad_level, Level}});
?IIF(lgUtil:validateLogLevel(Level) =/= false, checkOpts(T), {error, {bad_level, Level}});
checkOpts([{use_stderr, Flag} | T]) when is_boolean(Flag) ->
checkOpts(T);
checkOpts([{fmtTer, M} | T]) when is_atom(M) ->
@ -107,7 +107,7 @@ handleInfo(_Msg, _State) ->
terminate(removeEpm, State) ->
%% have to do this asynchronously because we're in the event handlr
spawn(fun() -> eLog:clearTraceByDestination(State#state.id) end),
spawn(fun() -> eLog:clearTraceByDest(State#state.id) end),
ok;
terminate(_Reason, _State) ->
ok.
@ -129,4 +129,4 @@ isNewStyleConsole() ->
%% 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 is_pid(whereis(user_drv)).
init:get_argument(noshell) =/= error orelse element(1, os:type()) =/= win32 orelse is_pid(whereis(user_drv)).

+ 2
- 2
src/backend/lgBkdFile.erl Просмотреть файл

@ -259,7 +259,7 @@ checkOpts([], IsFile) ->
checkOpts([{file, _File} | Tail], _IsFile) ->
checkOpts(Tail, true);
checkOpts([{level, Level} | Tail], IsFile) ->
?IIF(lgUtil:validateLogLevel(Level) /= false, checkOpts(Tail, IsFile), {error, {invalid_log_level, Level}});
?IIF(lgUtil:validateLogLevel(Level) =/= false, checkOpts(Tail, IsFile), {error, {invalid_log_level, Level}});
checkOpts([{size, Size} | Tail], IsFile) when is_integer(Size), Size >= 0 ->
checkOpts(Tail, IsFile);
checkOpts([{count, Count} | Tail], IsFile) when is_integer(Count), Count >= 0 ->
@ -277,7 +277,7 @@ checkOpts([{syncSize, SyncSize} | Tail], IsFile) when is_integer(SyncSize), Sync
checkOpts([{checkInt, CheckInt} | Tail], IsFile) when is_integer(CheckInt), CheckInt >= 0; CheckInt == always ->
checkOpts(Tail, IsFile);
checkOpts([{syncOn, Level} | Tail], IsFile) ->
?IIF(lgUtil:validateLogLevel(Level) /= false, checkOpts(Tail, IsFile), {error, {invalid_sync_on, Level}});
?IIF(lgUtil:validateLogLevel(Level) =/= false, checkOpts(Tail, IsFile), {error, {invalid_sync_on, Level}});
checkOpts([{fmtTer, Fmt} | Tail], IsFile) when is_atom(Fmt) ->
checkOpts(Tail, IsFile);
checkOpts([{fmtCfg, FmtCfg} | Tail], IsFile) when is_list(FmtCfg) ->

+ 398
- 403
src/eLog.erl Просмотреть файл

@ -8,337 +8,332 @@
%% API
-export([
%% start stop
start/0
, stop/0
%% log and log param
, dispatchLog/12
, doLogImpl/13
, safeFormat/3
, unsafeFormat/2
, getMd/0
, setMd/1
, getLogLevel/1
, getLogLevel/2
, setLogLevel/2
, setLogLevel/3
, setLogLevel/4
, getLogLevels/1
, upLogLevelCfg/1
, setLogHwm/2
, setLogHwm/3
, setLogHwm/4
, rotateHandler/1
, rotateHandler/2
, rotateSink/1
, rotateAll/0
%% stack parse
, parseStack/1
, parseStack/3
%% trace
, trace/2
, trace/3
, traceFile/2
, trace_file/3
, trace_file/4
, trace_console/1
, trace_console/2
, install_trace/2
, install_trace/3
, remove_trace/1
, trace_state/3
, trace_func/3
, listAllSinks/0
, clearAllTraces/0
, clearTraceByDestination/1
, stop_trace/1
, stop_trace/3
, status/0
%% start stop
start/0
, stop/0
%% log and log param
, dispatchLog/12
, doLogImpl/13
, safeFormat/3
, unsafeFormat/2
, getMd/0
, setMd/1
, getLogLevel/1
, getLogLevel/2
, setLogLevel/2
, setLogLevel/3
, setLogLevel/4
, getLogLevels/1
, upLogLevelCfg/1
, setLogHwm/2
, setLogHwm/3
, setLogHwm/4
, rotateHandler/1
, rotateHandler/2
, rotateSink/1
, rotateAll/0
%% stack parse
, parseStack/1
, parseStack/3
%% trace
, trace/2
, trace/3
, traceFile/2
, traceFile/3
, traceFile/4
, traceConsole/1
, traceConsole/2
, installTrace/2
, installTrace/3
, removeTrace/1
, traceState/3
, traceFunc/3
, listAllSinks/0
, clearAllTraces/0
, clearTraceByDest/1
, stopTrace/1
, stopTrace/3
, status/0
]).
-record(trace_func_state_v1, {
pid :: undefined | pid(),
level :: lgAtomLevel(),
count :: infinity | pos_integer(),
format_string :: string(),
timeout :: infinity | pos_integer(),
started = os:timestamp() :: erlang:timestamp() %% use os:timestamp for compatability
pid :: undefined | pid(),
level :: lgAtomLevel(),
count :: infinity | pos_integer(),
format_string :: string(),
timeout :: infinity | pos_integer(),
started = os:timestamp() :: erlang:timestamp() %% use os:timestamp for compatability
}).
start() ->
application:ensure_all_started(eLog).
application:ensure_all_started(eLog).
stop() ->
application:stop(eLog).
application:stop(eLog).
-spec dispatchLog(atom(), lgAtomLevel(), pid(), node(), atom(), atom(), integer(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok | {error, lager_not_running} | {error, {sink_not_configured, atom()}}.
%% this is the same check that the parse transform bakes into the module at compile time see lgTransform (lines 173-216)
-spec dispatchLog(atom(), lgAtomLevel(), pid(), node(), atom(), atom(), integer(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok.
dispatchLog(Sink, Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Size, Safety) ->
case ?eLogCfg:get(Sink) band Severity /= 0 of
true ->
doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety);
_ ->
ok
end.
case ?eLogCfg:get(Sink) band Severity =/= 0 of
true ->
doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety);
_ ->
ok
end.
doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety) ->
TraceFilters = lgConfig:ptGet({Sink, trace}, []),
Destinations = ?IIF(TraceFilters /= [], lgUtil:check_traces(Metadata, Severity, TraceFilters, []), []),
MsgStr = ?IIF(Args /= [] andalso Args /= undefined, ?IIF(Safety == safe, safeFormat(Format, [Args], [{charsLimit, Size}]), unsafeFormat(Format, [Args])), Format),
NowMs = lgTime:nowMs(),
NowStr = lgUtil:msToBinStr(NowMs),
LgMsg = #lgMsg{severity = Severity, pid = Pid, node = Node, module = Module, function = Function, line = Line, metadata = Metadata, datetime = NowStr, timestamp = NowMs, message = MsgStr, destinations = Destinations},
case lgConfig:ptGet({Sink, async}, false) of
true ->
gen_emm:info_notify(Sink, {mWriteLog, LgMsg});
_ ->
gen_emm:call_notify(Sink, {mWriteLog, LgMsg})
end,
case whereis(?LgTrackSink) of
undefined ->
ok;
TraceSinkPid ->
gen_emm:info_notify(TraceSinkPid, {mWriteLog, LgMsg})
end.
TraceFilters = lgConfig:ptGet({Sink, trace}, []),
Destinations = ?IIF(TraceFilters =/= [], lgUtil:check_traces(Metadata, Severity, TraceFilters, []), []),
MsgStr = ?IIF(Args =/= [] andalso Args =/= undefined, ?IIF(Safety == safe, safeFormat(Format, [Args], [{charsLimit, Size}]), unsafeFormat(Format, [Args])), Format),
NowMs = lgTime:nowMs(),
NowStr = lgUtil:msToBinStr(NowMs),
LgMsg = #lgMsg{severity = Severity, pid = Pid, node = Node, module = Module, function = Function, line = Line, metadata = Metadata, datetime = NowStr, timestamp = NowMs, message = MsgStr, destinations = Destinations},
case lgConfig:ptGet({Sink, async}, false) of
true ->
gen_emm:info_notify(Sink, {mWriteLog, LgMsg});
_ ->
gen_emm:call_notify(Sink, {mWriteLog, LgMsg})
end,
case whereis(?LgTrackSink) of
undefined ->
ok;
TraceSinkPid ->
gen_emm:info_notify(TraceSinkPid, {mWriteLog, LgMsg})
end.
%% @doc Get lager metadata for current process
-spec getMd() -> [{atom(), any()}].
getMd() ->
case erlang:get(?PdMdKey) of
undefined -> [];
MD -> MD
end.
case erlang:get(?PdMdKey) of
undefined -> [];
MD -> MD
end.
%% @doc Set lager metadata for current process.
%% Will badarg if you don't supply a list of {key, value} tuples keyed by atoms.
-spec setMd([{atom(), any()}, ...]) -> ok.
setMd(NewMD) when is_list(NewMD) ->
%% make sure its actually a real proplist
case lists:all(
fun({Key, _Value}) when is_atom(Key) -> true;
(_) -> false
end, NewMD) of
true ->
erlang:put(?PdMdKey, NewMD),
ok;
_ ->
erlang:error(badarg)
end;
%% make sure its actually a real proplist
case lists:all(
fun({Key, _Value}) when is_atom(Key) -> true;
(_) -> false
end, NewMD) of
true ->
erlang:put(?PdMdKey, NewMD),
ok;
_ ->
erlang:error(badarg)
end;
setMd(_) ->
erlang:error(badarg).
erlang:error(badarg).
%% @doc Set the loglevel for a particular backend.
setLogLevel(Handler, Level) ->
setLogLevel(?LgDefSink, Handler, undefined, Level).
setLogLevel(?LgDefSink, Handler, undefined, Level).
%% @doc Set the loglevel for a particular backend that has multiple identifiers (eg. the file backend).
setLogLevel(Handler, Ident, Level) ->
setLogLevel(?LgDefSink, Handler, Ident, Level).
setLogLevel(?LgDefSink, Handler, Ident, Level).
%% @doc Set the loglevel for a particular sink's backend that potentially has multiple identifiers. (Use `undefined' if it doesn't have any.)
setLogLevel(Sink, Handler, Ident, Level) when is_atom(Level) ->
HandlerArg =
case Ident of
undefined -> Handler;
_ -> {Handler, Ident}
end,
Reply = gen_emm:call(Sink, HandlerArg, {mSetLogLevel, Level}, infinity),
upLogLevelCfg(Sink),
Reply.
HandlerArg =
case Ident of
undefined -> Handler;
_ -> {Handler, Ident}
end,
Reply = gen_emm:call(Sink, HandlerArg, {mSetLogLevel, Level}, infinity),
upLogLevelCfg(Sink),
Reply.
%% @doc Get the loglevel for a particular backend on the default sink. In the case that the backend has multiple identifiers, the lowest is returned.
getLogLevel(Handler) ->
getLogLevel(?LgDefSink, Handler).
getLogLevel(?LgDefSink, Handler).
%% @doc Get the loglevel for a particular sink's backend. In the case that the backend
%% has multiple identifiers, the lowest is returned.
getLogLevel(Sink, Handler) ->
case gen_emm:call(Sink, Handler, mGetLogLevel, infinity) of
Mask when is_integer(Mask) ->
case lgUtil:maskToLevels(Mask) of
[] -> none;
Levels -> hd(Levels)
end;
Y -> Y
end.
case gen_emm:call(Sink, Handler, mGetLogLevel, infinity) of
Mask when is_integer(Mask) ->
case lgUtil:maskToLevels(Mask) of
[] -> none;
Levels -> hd(Levels)
end;
Y -> Y
end.
getLogLevels(Sink) ->
[gen_emm:call(Sink, Handler, mGetLogLevel, infinity) || Handler <- gen_emm:which_epm(Sink)].
[gen_emm:call(Sink, Handler, mGetLogLevel, infinity) || Handler <- gen_emm:which_epm(Sink)].
%% @doc Set the loghwm for the default sink.
setLogHwm(Handler, Hwm) when is_integer(Hwm) ->
setLogHwm(?LgDefSink, Handler, Hwm).
setLogHwm(?LgDefSink, Handler, Hwm).
%% @doc Set the loghwm for a particular backend.
setLogHwm(Sink, Handler, Hwm) when is_integer(Hwm) ->
gen_emm:call(Sink, Handler, {mSetLogHwm, Hwm}, infinity).
gen_emm:call(Sink, Handler, {mSetLogHwm, Hwm}, infinity).
%% @doc Set the loghwm (log high water mark) for file backends with multiple identifiers
setLogHwm(Sink, Handler, Ident, Hwm) when is_integer(Hwm) ->
gen_emm:call(Sink, {Handler, Ident}, {mSetLogHwm, Hwm}, infinity).
gen_emm:call(Sink, {Handler, Ident}, {mSetLogHwm, Hwm}, infinity).
%% @doc recalculate min log level
upLogLevelCfg(error_logger) ->
%% Not a sink under our control, part of the Erlang logging
%% utility that error_logger_lager_h attaches to
true;
%% Not a sink under our control, part of the Erlang logging
%% utility that error_logger_lager_h attaches to
true;
upLogLevelCfg(Sink) ->
Traces = lgConfig:ptGet({Sink, trace}, []),
AllLogLevel = allLogLevel(getLogLevels(Sink), 0),
case Traces /= [] of
true ->
ets:insert(?eLogEts, {Sink, 16#ff}),
AllSinks = ets:tab2list(?eLogEts),
lgKvsToBeam:load(?eLogCfg, AllSinks);
_ ->
ets:insert(?eLogEts, {Sink, AllLogLevel}),
AllSinks = ets:tab2list(?eLogEts),
lgKvsToBeam:load(?eLogCfg, AllSinks)
end.
Traces = lgConfig:ptGet({Sink, trace}, []),
case Traces =/= [] of
[] ->
AllLogLevel = allLogLevel(getLogLevels(Sink), 0),
ets:insert(?eLogEts, {Sink, AllLogLevel}),
AllSinks = ets:tab2list(?eLogEts),
lgKvsToBeam:load(?eLogCfg, AllSinks);
_ ->
ets:insert(?eLogEts, {Sink, 16#ff}),
AllSinks = ets:tab2list(?eLogEts),
lgKvsToBeam:load(?eLogCfg, AllSinks)
end.
allLogLevel([], Acc) ->
Acc;
Acc;
allLogLevel([OneLv | Levels], Acc) ->
allLogLevel(Levels, OneLv bor Acc).
allLogLevel(Levels, OneLv bor Acc).
rotateSink(Sink) ->
Handlers = lgConfig:ptGet(handlers, []),
RotateHandlers = lists:filtermap(
fun({Handler, _, S}) when S == Sink -> {true, {Handler, Sink}};
(_) -> false
end,
Handlers),
rotateHandlers(RotateHandlers).
Handlers = lgConfig:ptGet(handlers, []),
RotateHandlers = lists:filtermap(
fun({Handler, _, S}) when S == Sink -> {true, {Handler, Sink}}; (_) -> false end, Handlers),
rotateHandlers(RotateHandlers).
rotateAll() ->
rotateHandlers(lists:map(fun({H, _, S}) -> {H, S} end,
lgConfig:ptGet(handlers, []))).
rotateHandlers(lists:map(fun({H, _, S}) -> {H, S} end, lgConfig:ptGet(handlers, []))).
rotateHandlers(Handlers) ->
[rotateHandler(Handler, Sink) || {Handler, Sink} <- Handlers].
[rotateHandler(Handler, Sink) || {Handler, Sink} <- Handlers].
rotateHandler(Handler) ->
Handlers = lgConfig:ptGet(handlers, []),
case lists:keyfind(Handler, 1, Handlers) of
{Handler, _, Sink} -> rotateHandler(Handler, Sink);
false -> ok
end.
Handlers = lgConfig:ptGet(handlers, []),
case lists:keyfind(Handler, 1, Handlers) of
{Handler, _, Sink} -> rotateHandler(Handler, Sink);
false -> ok
end.
rotateHandler(Handler, Sink) ->
gen_emm:call(Sink, Handler, mRotate, ?LgRotateTimeout).
gen_emm:call(Sink, Handler, mRotate, ?LgRotateTimeout).
%% @doc Print stacktrace in human readable form
parseStack(Stacktrace) ->
<<
begin
case Location of
[] ->
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")\n">>;
[{file, File}, {line, Line}] ->
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "/", (integer_to_binary(Arity))/binary, "(", (unicode:characters_to_binary(File))/binary, ":", (integer_to_binary(Line))/binary, ")\n">>;
_ ->
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")", (eFmt:formatBin("~w", [Location]))/binary, "\n">>
end
end || {Mod, Func, Arity, Location} <- Stacktrace
>>.
<<
begin
case Location of
[] ->
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")\n">>;
[{file, File}, {line, Line}] ->
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "/", (integer_to_binary(Arity))/binary, "(", (unicode:characters_to_binary(File))/binary, ":", (integer_to_binary(Line))/binary, ")\n">>;
_ ->
<<" ", (atom_to_binary(Mod, utf8))/binary, ":", (atom_to_binary(Func, utf8))/binary, "(", (eFmt:formatBin("~w", [Arity]))/binary, ")", (eFmt:formatBin("~w", [Location]))/binary, "\n">>
end
end || {Mod, Func, Arity, Location} <- Stacktrace
>>.
parseStack(Class, Reason, Stacktrace) ->
eFmt:formatBin(<<"~n Class:~s~n Reason:~p~n Stacktrace:~s">>, [Class, Reason, parseStack(Stacktrace)]).
eFmt:formatBin(<<"~n Class:~s~n Reason:~p~n Stacktrace:~s">>, [Class, Reason, parseStack(Stacktrace)]).
trace(BkdMod, Filter) ->
trace(BkdMod, Filter, debug).
trace(BkdMod, Filter, debug).
trace({lgBkdFile, File}, Filter, Level) ->
trace_file(File, Filter, Level);
traceFile(File, Filter, Level);
trace(Backend, Filter, Level) ->
case validateTraceFilters(Filter, Level, Backend) of
{Sink, {ok, Trace}} ->
add_trace_to_loglevel_config(Trace, Sink),
{ok, {Backend, Filter, Level}};
{_Sink, Error} ->
Error
end.
case validateTraceFilters(Filter, Level, Backend) of
{Sink, {ok, Trace}} ->
add_trace_to_loglevel_config(Trace, Sink),
{ok, {Backend, Filter, Level}};
{_Sink, Error} ->
Error
end.
traceFile(File, Filter) ->
trace_file(File, Filter, debug, []).
trace_file(File, Filter, Level) when is_atom(Level) ->
trace_file(File, Filter, Level, []);
trace_file(File, Filter, Options) when is_list(Options) ->
trace_file(File, Filter, debug, Options).
trace_file(File, Filter, Level, Options) ->
FileName = lgUtil:parsePath(File),
case validateTraceFilters(Filter, Level, {lgBkdFile, FileName}) of
{Sink, {ok, Trace}} ->
Handlers = lgConfig:ptGet(handlers, []),
%% check if this file backend is already installed
Res =
case lgUtil:find_file(FileName, Handlers) of
false ->
%% install the handler
LogFileConfig =
lists:keystore(level, 1,
lists:keystore(file, 1,
Options,
{file, FileName}),
{level, none}),
HandlerInfo =
eLog_app:startHandler(Sink, {lgBkdFile, FileName}, LogFileConfig),
lgConfig:ptSet(handlers, [HandlerInfo | Handlers]),
{ok, installed};
{_Watcher, _Handler, Sink} ->
{ok, exists};
{_Watcher, _Handler, _OtherSink} ->
{error, file_in_use}
end,
case Res of
{ok, _} ->
add_trace_to_loglevel_config(Trace, Sink),
{ok, {{lgBkdFile, FileName}, Filter, Level}};
{error, _} = E ->
E
end;
{_Sink, Error} ->
Error
end.
trace_console(Filter) ->
trace_console(Filter, debug).
trace_console(Filter, Level) ->
trace(lgBkdConsole, Filter, Level).
stop_trace(Backend, Filter, Level) ->
case validateTraceFilters(Filter, Level, Backend) of
{Sink, {ok, Trace}} ->
stopTraceInt(Trace, Sink);
{_Sink, Error} ->
Error
end.
stop_trace({Backend, Filter, Level}) ->
stop_trace(Backend, Filter, Level).
traceFile(File, Filter, debug, []).
traceFile(File, Filter, Level) when is_atom(Level) ->
traceFile(File, Filter, Level, []);
traceFile(File, Filter, Options) when is_list(Options) ->
traceFile(File, Filter, debug, Options).
traceFile(File, Filter, Level, Options) ->
FileName = lgUtil:parsePath(File),
case validateTraceFilters(Filter, Level, {lgBkdFile, FileName}) of
{Sink, {ok, Trace}} ->
Handlers = lgConfig:ptGet(handlers, []),
%% check if this file backend is already installed
Res =
case lgUtil:find_file(FileName, Handlers) of
false ->
%% install the handler
LogFileConfig =
lists:keystore(level, 1,
lists:keystore(file, 1,
Options,
{file, FileName}),
{level, none}),
HandlerInfo =
eLog_app:startHandler(Sink, {lgBkdFile, FileName}, LogFileConfig),
lgConfig:ptSet(handlers, [HandlerInfo | Handlers]),
{ok, installed};
{_Watcher, _Handler, Sink} ->
{ok, exists};
{_Watcher, _Handler, _OtherSink} ->
{error, file_in_use}
end,
case Res of
{ok, _} ->
add_trace_to_loglevel_config(Trace, Sink),
{ok, {{lgBkdFile, FileName}, Filter, Level}};
{error, _} = E ->
E
end;
{_Sink, Error} ->
Error
end.
traceConsole(Filter) ->
traceConsole(Filter, debug).
traceConsole(Filter, Level) ->
trace(lgBkdConsole, Filter, Level).
stopTrace(Backend, Filter, Level) ->
case validateTraceFilters(Filter, Level, Backend) of
{Sink, {ok, Trace}} ->
stopTraceInt(Trace, Sink);
{_Sink, Error} ->
Error
end.
stopTrace({Backend, Filter, Level}) ->
stopTrace(Backend, Filter, Level).
validateTraceFilters(Filters, Level, Backend) ->
Sink = proplists:get_value(sink, Filters, ?LgDefSink),
{Sink,
lgUtil:validate_trace({
proplists:delete(sink, Filters),
Level,
Backend
})
}.
Sink = proplists:get_value(sink, Filters, ?LgDefSink),
{Sink,
lgUtil:validate_trace({
proplists:delete(sink, Filters),
Level,
Backend
})
}.
%% Important: validate_trace_filters orders the arguments of
%% trace tuples differently than the way outside callers have
@ -350,157 +345,157 @@ validateTraceFilters(Filters, Level, Backend) ->
%% and when they come back from validation, they're
%% `{Filter, Level, Backend}'
stopTraceInt({_Filter, _Level, Backend} = Trace, Sink) ->
Traces = lgConfig:ptGet({Sink, trace}, []),
NewTraces = lists:delete(Trace, Traces),
_ = lgUtil:trace_filter([element(1, T) || T <- NewTraces]),
%MinLevel = minimum_loglevel(get_loglevels() ++ get_trace_levels(NewTraces)),
lgConfig:ptSet({Sink, trace}, NewTraces),
eLog:upLogLevelCfg(Sink),
case getLogLevel(Sink, Backend) of
none ->
%% check no other traces point here
case lists:keyfind(Backend, 3, NewTraces) of
false ->
gen_emm:delEpm(Sink, Backend, []),
lgConfig:ptSet(handlers,
lists:keydelete(Backend, 1,
lgConfig:ptGet(handlers, [])));
_ ->
ok
end;
_ ->
ok
end,
ok.
Traces = lgConfig:ptGet({Sink, trace}, []),
NewTraces = lists:delete(Trace, Traces),
_ = lgUtil:trace_filter([element(1, T) || T <- NewTraces]),
%MinLevel = minimum_loglevel(get_loglevels() ++ get_trace_levels(NewTraces)),
lgConfig:ptSet({Sink, trace}, NewTraces),
eLog:upLogLevelCfg(Sink),
case getLogLevel(Sink, Backend) of
none ->
%% check no other traces point here
case lists:keyfind(Backend, 3, NewTraces) of
false ->
gen_emm:delEpm(Sink, Backend, []),
lgConfig:ptSet(handlers,
lists:keydelete(Backend, 1,
lgConfig:ptGet(handlers, [])));
_ ->
ok
end;
_ ->
ok
end,
ok.
%% @doc installs a lager trace handler into the target process (using sys:install) at the specified level.
-spec install_trace(pid(), lgAtomLevel()) -> ok.
install_trace(Pid, Level) ->
install_trace(Pid, Level, []).
-spec installTrace(pid(), lgAtomLevel()) -> ok.
installTrace(Pid, Level) ->
installTrace(Pid, Level, []).
-spec install_trace(pid(), lgAtomLevel(), [{count, infinity | pos_integer()} | {format_string, string()} | {timeout, timeout()}]) -> ok.
install_trace(Pid, Level, Options) ->
sys:install(Pid, {fun ?MODULE:trace_func/3, trace_state(Pid, Level, Options)}).
-spec installTrace(pid(), lgAtomLevel(), [{count, infinity | pos_integer()} | {format_string, string()} | {timeout, timeout()}]) -> ok.
installTrace(Pid, Level, Options) ->
sys:install(Pid, {fun ?MODULE:traceFunc/3, traceState(Pid, Level, Options)}).
%% @doc remove a previously installed lager trace handler from the target process.
-spec remove_trace(pid()) -> ok.
remove_trace(Pid) ->
sys:remove(Pid, fun ?MODULE:trace_func/3).
-spec removeTrace(pid()) -> ok.
removeTrace(Pid) ->
sys:remove(Pid, fun ?MODULE:traceFunc/3).
listAllSinks() ->
sets:to_list(
lists:foldl(
fun({_Watcher, _Handler, Sink}, Set) ->
sets:add_element(Sink, Set)
end, sets:new(), lgConfig:ptGet(handlers, [])
)
).
sets:to_list(
lists:foldl(
fun({_Watcher, _Handler, Sink}, Set) ->
sets:add_element(Sink, Set)
end, sets:new(), lgConfig:ptGet(handlers, [])
)
).
clearTracesBySink(Sinks) ->
lists:foreach(
fun(S) ->
lgConfig:ptSet({S, trace}, []),
eLog:upLogLevelCfg(S)
end,
Sinks).
lists:foreach(
fun(S) ->
lgConfig:ptSet({S, trace}, []),
eLog:upLogLevelCfg(S)
end,
Sinks).
clearTraceByDestination(ID) ->
Sinks = lists:sort(listAllSinks()),
Traces = findTraces(Sinks),
[stopTraceInt({Filter, Level, Destination}, Sink) || {Sink, {Filter, Level, Destination}} <- Traces, Destination == ID].
clearTraceByDest(ID) ->
Sinks = lists:sort(listAllSinks()),
Traces = findTraces(Sinks),
[stopTraceInt({Filter, Level, Destination}, Sink) || {Sink, {Filter, Level, Destination}} <- Traces, Destination == ID].
clearAllTraces() ->
Handlers = lgConfig:ptGet(handlers, []),
clearTracesBySink(listAllSinks()),
_ = lgUtil:trace_filter(none),
lgConfig:ptSet(handlers,
lists:filter(
fun({Handler, _Watcher, Sink}) ->
case getLogLevel(Sink, Handler) of
none ->
gen_emm:delEpm(Sink, Handler, []),
false;
_ ->
true
end
end, Handlers)).
Handlers = lgConfig:ptGet(handlers, []),
clearTracesBySink(listAllSinks()),
_ = lgUtil:trace_filter(none),
lgConfig:ptSet(handlers,
lists:filter(
fun({Handler, _Watcher, Sink}) ->
case getLogLevel(Sink, Handler) of
none ->
gen_emm:delEpm(Sink, Handler, []),
false;
_ ->
true
end
end, Handlers)).
findTraces(Sinks) ->
lists:foldl(
fun(S, Acc) ->
Traces = lgConfig:ptGet({S, trace}, []),
Acc ++ lists:map(fun(T) -> {S, T} end, Traces)
end,
[], Sinks).
lists:foldl(
fun(S, Acc) ->
Traces = lgConfig:ptGet({S, trace}, []),
Acc ++ lists:map(fun(T) -> {S, T} end, Traces)
end,
[], Sinks).
status() ->
Handlers = lgConfig:ptGet(handlers, []),
Sinks = lists:sort(listAllSinks()),
Traces = findTraces(Sinks),
TraceCount = case length(Traces) of
0 -> 1;
N -> N
end,
Status = ["Lager status:\n",
[begin
Level = getLogLevel(Sink, Handler),
get_sink_handler_status(Sink, Handler, Level)
end || {Handler, _Watcher, Sink} <- lists:sort(fun({_, _, S1},
{_, _, S2}) -> S1 =< S2 end,
Handlers)],
"Active Traces:\n",
[begin
LevelName =
case lgUtil:maskToLevels(Level) of
[] -> none;
Levels -> hd(Levels)
end,
io_lib:format("Tracing messages matching ~p (sink ~s) at level ~p to ~p\n",
[Filter, Sink, LevelName, Destination])
end || {Sink, {Filter, Level, Destination}} <- Traces],
[
"Tracing Reductions:\n",
case ?LgDefTracer:info('query') of
{null, false} -> "";
Query -> io_lib:format("~p~n", [Query])
end
],
[
"Tracing Statistics:\n ",
[begin
[" ", atom_to_list(Table), ": ",
integer_to_list(?LgDefTracer:info(Table) div TraceCount),
"\n"]
end || Table <- [input, output, filter]]
]],
io:put_chars(Status).
Handlers = lgConfig:ptGet(handlers, []),
Sinks = lists:sort(listAllSinks()),
Traces = findTraces(Sinks),
TraceCount = case length(Traces) of
0 -> 1;
N -> N
end,
Status = ["Lager status:\n",
[begin
Level = getLogLevel(Sink, Handler),
get_sink_handler_status(Sink, Handler, Level)
end || {Handler, _Watcher, Sink} <- lists:sort(fun({_, _, S1},
{_, _, S2}) -> S1 =< S2 end,
Handlers)],
"Active Traces:\n",
[begin
LevelName =
case lgUtil:maskToLevels(Level) of
[] -> none;
Levels -> hd(Levels)
end,
io_lib:format("Tracing messages matching ~p (sink ~s) at level ~p to ~p\n",
[Filter, Sink, LevelName, Destination])
end || {Sink, {Filter, Level, Destination}} <- Traces],
[
"Tracing Reductions:\n",
case ?LgDefTracer:info('query') of
{null, false} -> "";
Query -> io_lib:format("~p~n", [Query])
end
],
[
"Tracing Statistics:\n ",
[begin
[" ", atom_to_list(Table), ": ",
integer_to_list(?LgDefTracer:info(Table) div TraceCount),
"\n"]
end || Table <- [input, output, filter]]
]],
io:put_chars(Status).
get_sink_handler_status(Sink, Handler, Level) ->
case Handler of
{lgBkdFile, File} ->
io_lib:format("File ~ts (~s) at level ~p\n", [File, Sink, Level]);
lgBkdConsole ->
io_lib:format("Console (~s) at level ~p\n", [Sink, Level]);
_ ->
[]
end.
case Handler of
{lgBkdFile, File} ->
io_lib:format("File ~ts (~s) at level ~p\n", [File, Sink, Level]);
lgBkdConsole ->
io_lib:format("Console (~s) at level ~p\n", [Sink, Level]);
_ ->
[]
end.
%% @private
add_trace_to_loglevel_config(Trace, Sink) ->
Traces = lgConfig:ptGet({Sink, trace}, []),
case lists:member(Trace, Traces) of
false ->
NewTraces = [Trace | Traces],
_ = lgUtil:trace_filter([element(1, T) || T <- NewTraces]),
lgConfig:ptSet({Sink, trace}, [Trace | Traces]),
eLog:upLogLevelCfg(Sink);
_ ->
ok
end.
Traces = lgConfig:ptGet({Sink, trace}, []),
case lists:member(Trace, Traces) of
false ->
NewTraces = [Trace | Traces],
_ = lgUtil:trace_filter([element(1, T) || T <- NewTraces]),
lgConfig:ptSet({Sink, trace}, [Trace | Traces]),
eLog:upLogLevelCfg(Sink);
_ ->
ok
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
@ -508,16 +503,16 @@ add_trace_to_loglevel_config(Trace, Sink) ->
%% arguments. The caller is NOT crashed.
unsafeFormat(Fmt, Args) ->
try io_lib:format(Fmt, Args)
catch
_:_ -> io_lib:format("FORMAT ERROR: ~p ~p", [Fmt, Args])
end.
try io_lib:format(Fmt, Args)
catch
_:_ -> io_lib:format("FORMAT ERROR: ~p ~p", [Fmt, Args])
end.
safeFormat(Fmt, Args, Limit) ->
try eFmt:formatBin(Fmt, Args, [{charsLimit, Limit}])
catch
_:_ -> eFmt:formatBin(<<"FORMAT ERROR: ~p ~p">>, [Fmt, Args], [{charsLimit, Limit}])
end.
try eFmt:formatBin(Fmt, Args, [{charsLimit, Limit}])
catch
_:_ -> eFmt:formatBin(<<"FORMAT ERROR: ~p ~p">>, [Fmt, Args], [{charsLimit, Limit}])
end.
%% @private Print the format string `Fmt' with `Args' without a size limit.
%% This is unsafe because the output of this function is unbounded.
@ -532,32 +527,32 @@ safeFormat(Fmt, Args, Limit) ->
%% offending arguments. The caller is NOT crashed.
%% @private
trace_func(#trace_func_state_v1{pid = Pid, level = Level, format_string = Fmt} = FuncState, Event, ProcState) ->
_ = eLog:log(Level, Pid, Fmt, [Event, ProcState]),
check_timeout(decrement_count(FuncState)).
traceFunc(#trace_func_state_v1{pid = Pid, level = Level, format_string = Fmt} = FuncState, Event, ProcState) ->
_ = eLog:log(Level, Pid, Fmt, [Event, ProcState]),
check_timeout(decrement_count(FuncState)).
%% @private
trace_state(Pid, Level, Options) ->
#trace_func_state_v1{pid = Pid,
level = Level,
count = proplists:get_value(count, Options, infinity),
timeout = proplists:get_value(timeout, Options, infinity),
format_string = proplists:get_value(format_string, Options, "TRACE ~p ~p")}.
traceState(Pid, Level, Options) ->
#trace_func_state_v1{pid = Pid,
level = Level,
count = proplists:get_value(count, Options, infinity),
timeout = proplists:get_value(timeout, Options, infinity),
format_string = proplists:get_value(format_string, Options, "TRACE ~p ~p")}.
decrement_count(#trace_func_state_v1{count = infinity} = FuncState) ->
FuncState;
FuncState;
decrement_count(#trace_func_state_v1{count = 1}) ->
%% hit the counter limit
done;
%% hit the counter limit
done;
decrement_count(#trace_func_state_v1{count = Count} = FuncState) ->
FuncState#trace_func_state_v1{count = Count - 1}.
FuncState#trace_func_state_v1{count = Count - 1}.
check_timeout(#trace_func_state_v1{timeout = infinity} = FuncState) ->
FuncState;
FuncState;
check_timeout(#trace_func_state_v1{timeout = Timeout, started = Started} = FuncState) ->
case (timer:now_diff(os:timestamp(), Started) / 1000) > Timeout of
true ->
done;
false ->
FuncState
end.
case (timer:now_diff(os:timestamp(), Started) / 1000) > Timeout of
true ->
done;
false ->
FuncState
end.

+ 2
- 2
src/utils/lgUtil.erl Просмотреть файл

@ -101,7 +101,7 @@ maskToLevels(Mask) ->
maskToLevels([], _Mask, Acc) ->
lists:reverse(Acc);
maskToLevels([Level | Levels], Mask, Acc) ->
case (levelToNum(Level) band Mask) /= 0 of
case (levelToNum(Level) band Mask) =/= 0 of
true ->
maskToLevels(Levels, Mask, [Level | Acc]);
_ ->
@ -481,7 +481,7 @@ check_trace(Attrs, {Filter, _Level, Dest}) when is_tuple(Filter) ->
-spec isLoggAble(lgMsg(), lgMaskLevel(), term()) -> boolean().
isLoggAble(LgMsg, Mask, MyName) ->
#lgMsg{severity = Severity, destinations = Destinations} = LgMsg,
(Severity band Mask) /= 0 orelse lists:member(MyName, Destinations).
(Severity band Mask) =/= 0 orelse lists:member(MyName, Destinations).
parsePath(RelPath) ->
NewRelPath =

Загрузка…
Отмена
Сохранить