diff --git a/README.md b/README.md index 3f335d3..fa1365f 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ -------- eRum is a Erlang logger. 基于lager3.9.0 rewrite +TODO +-------- +trace相关代码整理 + 特点 -------- diff --git a/eRum.sample.config b/eRum.sample.config index 2d41749..fa08283 100644 --- a/eRum.sample.config +++ b/eRum.sample.config @@ -55,8 +55,6 @@ %% ******************************************** format相关 ****************************************************** %% 元数据名单列表 {metadataWhitelist, []}, - %% 是否美化堆栈 - {rPrettyStrace, true}, %% ********************************************** 日志文件配置相关 ************************************************ %% 可选的日志路径, 默认情况下是当前路径 diff --git a/include/eRum.hrl b/include/eRum.hrl index 154a69f..7d8146d 100644 --- a/include/eRum.hrl +++ b/include/eRum.hrl @@ -16,15 +16,15 @@ %% Level, Pid, Node, Module, Function, Line, Other -define(rumLog(Severity, Format, Args, Safety), - ?rumLog(?RumDefSink, Severity, self(), node(), ?MODULE, ?FUNCTION_NAME, ?LINE, eRum:md(), Format, Args, ?RumDefTruncation, Safety)). + ?rumLog(?RumDefSink, Severity, self(), node(), ?MODULE, ?FUNCTION_NAME, ?LINE, eRum:getMd(), Format, Args, ?RumDefTruncation, Safety)). -define(rumLog(Severity, Metadata, Format, Args, Safety), - ?rumLog(?RumDefSink, Severity, self(), node(), ?MODULE, ?FUNCTION_NAME, ?LINE, Metadata ++ eRum:md(), Format, Args, ?RumDefTruncation, Safety)). + ?rumLog(?RumDefSink, Severity, self(), node(), ?MODULE, ?FUNCTION_NAME, ?LINE, Metadata ++ eRum:getMd(), Format, Args, ?RumDefTruncation, Safety)). -define(rumLog(Sink, Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Size, Safety), case ?eRumCfg:get(Sink) band Severity /= 0 of true -> - eRum:do_log_impl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety); + eRum:doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety); _ -> ok end). diff --git a/src/eRum.erl b/src/eRum.erl index 066ffcd..a113dd3 100644 --- a/src/eRum.erl +++ b/src/eRum.erl @@ -14,13 +14,12 @@ , stop/0 %% log and log param - , dispatch_log/12 - , do_log_impl/13 - , safe_format/3 - , safe_format_chop/3 - , unsafe_format/2 - , md/0 - , md/1 + , dispatchLog/12 + , doLogImpl/13 + , safeFormat/3 + , unsafeFormat/2 + , getMd/0 + , setMd/1 , getLogLevel/1 , getLogLevel/2 , setLogLevel/2 @@ -31,22 +30,19 @@ , setLogHwm/2 , setLogHwm/3 , setLogHwm/4 - , rotate_handler/1 - , rotate_handler/2 - , rotate_sink/1 - , rotate_all/0 - , posix_error/1 - - %% stack - , pr/2 - , pr/3 - , pr_stacktrace/1 - , pr_stacktrace/2 + , rotateHandler/1 + , rotateHandler/2 + , rotateSink/1 + , rotateAll/0 + + %% stack parse + , parseStack/1 + , parseStack/3 %% trace , trace/2 , trace/3 - , trace_file/2 + , traceFile/2 , trace_file/3 , trace_file/4 , trace_console/1 @@ -79,27 +75,21 @@ start() -> stop() -> application:stop(eRum). --spec dispatch_log(atom(), rumAtomLevel(), pid(), node(), atom(), atom(), integer(), list(), string(), list() | none, pos_integer(), safe | unsafe) -> ok | {error, lager_not_running} | {error, {sink_not_configured, atom()}}. +-spec dispatchLog(atom(), rumAtomLevel(), 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 rumTransform (lines 173-216) -dispatch_log(Sink, Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Size, Safety) -> +dispatchLog(Sink, Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Size, Safety) -> case ?eRumCfg:get(Sink) band Severity /= 0 of true -> - do_log_impl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety); + doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety); _ -> ok end. -do_log_impl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety) -> +doLogImpl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, Severity, Size, Sink, Safety) -> TraceFilters = rumConfig:ptGet({Sink, trace}, []), - {Destinations, TraceSinkPid} = - case TraceFilters of - [] -> - {[], undefined}; - _ -> - {rumUtil:check_traces(Metadata, Severity, TraceFilters, []), whereis(?RumTrackSink)} - end, + Destinations = ?IIF(TraceFilters /= [], rumUtil:check_traces(Metadata, Severity, TraceFilters, []), []), - MsgStr = ?IIF(Args /= [] andalso Args /= undefined, ?IIF(Safety == safe, eFmt:formatBin(Format, [Args], [{charsLimit, Size}]), eFmt:formatBin(Format, [Args])), Format), + MsgStr = ?IIF(Args /= [] andalso Args /= undefined, ?IIF(Safety == safe, safeFormat(Format, [Args], [{charsLimit, Size}]), unsafeFormat(Format, [Args])), Format), NowMs = rumTime:nowMs(), NowStr = rumUtil:msToBinStr(NowMs), RumMsg = #rumMsg{severity = Severity, pid = Pid, node = Node, module = Module, function = Function, line = Line, metadata = Metadata, datetime = NowStr, timestamp = NowMs, message = MsgStr, destinations = Destinations}, @@ -110,16 +100,16 @@ do_log_impl(Severity, Pid, Node, Module, Function, Line, Metadata, Format, Args, false -> gen_emm:call_notify(Sink, {mWriteLog, RumMsg}) end, - case TraceSinkPid /= undefined of - true -> - gen_emm:info_notify(TraceSinkPid, {mWriteLog, RumMsg}); - false -> - ok + case whereis(?RumTrackSink) of + undefined -> + ok; + TraceSinkPid -> + gen_emm:info_notify(TraceSinkPid, {mWriteLog, RumMsg}) end. %% @doc Get lager metadata for current process --spec md() -> [{atom(), any()}]. -md() -> +-spec getMd() -> [{atom(), any()}]. +getMd() -> case erlang:get(?PdMdKey) of undefined -> []; MD -> MD @@ -127,8 +117,8 @@ md() -> %% @doc Set lager metadata for current process. %% Will badarg if you don't supply a list of {key, value} tuples keyed by atoms. --spec md([{atom(), any()}, ...]) -> ok. -md(NewMD) when is_list(NewMD) -> +-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; @@ -137,23 +127,12 @@ md(NewMD) when is_list(NewMD) -> true -> erlang:put(?PdMdKey, NewMD), ok; - false -> + _ -> erlang:error(badarg) end; -md(_) -> +setMd(_) -> erlang:error(badarg). - -validate_trace_filters(Filters, Level, Backend) -> - Sink = proplists:get_value(sink, Filters, ?RumDefSink), - {Sink, - rumUtil:validate_trace({ - proplists:delete(sink, Filters), - Level, - Backend - }) - }. - %% @doc Set the loglevel for a particular backend. setLogLevel(Handler, Level) when is_atom(Level) -> setLogLevel(?RumDefSink, Handler, undefined, Level). @@ -207,66 +186,91 @@ setLogHwm(Sink, Handler, Hwm) when is_integer(Hwm) -> setLogHwm(Sink, Handler, Ident, Hwm) when is_integer(Hwm) -> gen_emm:call(Sink, {Handler, Ident}, {mSetLogHwm, Hwm}, infinity). -%% @doc Print stacktrace in human readable form -pr_stacktrace(Stacktrace) -> - Stacktrace1 = - case rumUtil:get_env(rPrettyStrace, true) of - true -> - lists:reverse(Stacktrace); - _ -> - Stacktrace - end, - pr_stacktrace_(Stacktrace1). - -pr_stacktrace_(Stacktrace) -> - Indent = "\n ", - lists:foldl( - fun(Entry, Acc) -> - Acc ++ Indent ++ binary_to_list(rumErrLoggerH:formatMfa(Entry)) - end, - [], - Stacktrace). - -pr_stacktrace(Stacktrace, {Class, Reason}) -> - case rumUtil:get_env(rPrettyStrace, true) of +%% @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; +upLogLevelCfg(Sink) -> + Traces = rumConfig:ptGet({Sink, trace}, []), + AllLogLevel = allLogLevel(getLogLevels(Sink), 0), + case Traces /= [] of true -> - lists:flatten( - pr_stacktrace_(lists:reverse(Stacktrace)) ++ "\n" ++ io_lib:format("~s:~p", [Class, Reason])); + ets:insert(?eRumEts, {Sink, 16#ff}), + AllSinks = ets:tab2list(?eRumEts), + rumKvsToBeam:load(?eRumCfg, AllSinks); _ -> - lists:flatten( - io_lib:format("~s:~p", [Class, Reason]) ++ pr_stacktrace_(Stacktrace)) + ets:insert(?eRumEts, {Sink, AllLogLevel}), + AllSinks = ets:tab2list(?eRumEts), + rumKvsToBeam:load(?eRumCfg, AllSinks) end. -rotate_sink(Sink) -> +allLogLevel([], Acc) -> + Acc; +allLogLevel([OneLv | Levels], Acc) -> + allLogLevel(Levels, OneLv bor Acc). + +rotateSink(Sink) -> Handlers = rumConfig:ptGet(handlers, []), RotateHandlers = lists:filtermap( fun({Handler, _, S}) when S == Sink -> {true, {Handler, Sink}}; (_) -> false end, Handlers), - rotate_handlers(RotateHandlers). + rotateHandlers(RotateHandlers). -rotate_all() -> - rotate_handlers(lists:map(fun({H, _, S}) -> {H, S} end, +rotateAll() -> + rotateHandlers(lists:map(fun({H, _, S}) -> {H, S} end, rumConfig:ptGet(handlers, []))). -rotate_handlers(Handlers) -> - [rotate_handler(Handler, Sink) || {Handler, Sink} <- Handlers]. +rotateHandlers(Handlers) -> + [rotateHandler(Handler, Sink) || {Handler, Sink} <- Handlers]. -rotate_handler(Handler) -> +rotateHandler(Handler) -> Handlers = rumConfig:ptGet(handlers, []), case lists:keyfind(Handler, 1, Handlers) of - {Handler, _, Sink} -> rotate_handler(Handler, Sink); + {Handler, _, Sink} -> rotateHandler(Handler, Sink); false -> ok end. -rotate_handler(Handler, Sink) -> +rotateHandler(Handler, Sink) -> gen_emm:call(Sink, Handler, mRotate, ?RumRotateTimeout). +%% @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 + >>. + +parseStack(Stacktrace, Class, Reason) -> + eFmt:formatBin(<<"~n Class:~s~n Reason:~p~n Stacktrace:~s">>, [Class, Reason, parseStack(Stacktrace)]). -trace_file(File, Filter) -> +trace(BkdMod, Filter) -> + trace(BkdMod, Filter, debug). + +trace({rumBkdFile, File}, Filter, Level) -> + trace_file(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. + +traceFile(File, Filter) -> trace_file(File, Filter, debug, []). trace_file(File, Filter, Level) when is_atom(Level) -> @@ -277,7 +281,7 @@ trace_file(File, Filter, Options) when is_list(Options) -> trace_file(File, Filter, Level, Options) -> FileName = rumUtil:parsePath(File), - case validate_trace_filters(Filter, Level, {rumBkdFile, FileName}) of + case validateTraceFilters(Filter, Level, {rumBkdFile, FileName}) of {Sink, {ok, Trace}} -> Handlers = rumConfig:ptGet(handlers, []), %% check if this file backend is already installed @@ -317,23 +321,8 @@ trace_console(Filter) -> trace_console(Filter, Level) -> trace(rumBkdConsole, Filter, Level). -trace(Backend, Filter) -> - trace(Backend, Filter, debug). - -trace({rumBkdFile, File}, Filter, Level) -> - trace_file(File, Filter, Level); - -trace(Backend, Filter, Level) -> - case validate_trace_filters(Filter, Level, Backend) of - {Sink, {ok, Trace}} -> - add_trace_to_loglevel_config(Trace, Sink), - {ok, {Backend, Filter, Level}}; - {_Sink, Error} -> - Error - end. - stop_trace(Backend, Filter, Level) -> - case validate_trace_filters(Filter, Level, Backend) of + case validateTraceFilters(Filter, Level, Backend) of {Sink, {ok, Trace}} -> stop_trace_int(Trace, Sink); {_Sink, Error} -> @@ -343,6 +332,17 @@ stop_trace(Backend, Filter, Level) -> stop_trace({Backend, Filter, Level}) -> stop_trace(Backend, Filter, Level). + +validateTraceFilters(Filters, Level, Backend) -> + Sink = proplists:get_value(sink, Filters, ?RumDefSink), + {Sink, + rumUtil: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 %% the trace tuple. @@ -491,16 +491,6 @@ get_sink_handler_status(Sink, Handler, Level) -> [] end. -%% @doc Try to convert an atom to a posix error, but fall back on printing the -%% term if its not a valid posix error code. -posix_error(Error) when is_atom(Error) -> - case erl_posix_msg:message(Error) of - "unknown POSIX error" -> atom_to_list(Error); - Message -> Message - end; -posix_error(Error) -> - safe_format_chop("~p", [Error], ?RumDefTruncation). - %% @private add_trace_to_loglevel_config(Trace, Sink) -> Traces = rumConfig:ptGet({Sink, trace}, []), @@ -514,49 +504,23 @@ add_trace_to_loglevel_config(Trace, Sink) -> ok end. -%% @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; -upLogLevelCfg(Sink) -> - Traces = rumConfig:ptGet({Sink, trace}, []), - AllLogLevel = allLogLevel(getLogLevels(Sink), 0), - case Traces /= [] of - true -> - ets:insert(?eRumEts, {Sink, 16#ff}), - AllSinks = ets:tab2list(?eRumEts), - rumKvsToBeam:load(?eRumCfg, AllSinks); - _ -> - ets:insert(?eRumEts, {Sink, AllLogLevel}), - AllSinks = ets:tab2list(?eRumEts), - rumKvsToBeam:load(?eRumCfg, AllSinks) - end. - -allLogLevel([], Acc) -> - Acc; -allLogLevel([OneLv | Levels], Acc) -> - allLogLevel(Levels, OneLv bor Acc). - - %% @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 %% arguments. The caller is NOT crashed. -safe_format(Fmt, Args, Limit) -> - safe_format_2(Fmt, Args, Limit). +unsafeFormat(Fmt, Args) -> + try io_lib:format(Fmt, Args) + catch + _:_ -> io_lib:format("FORMAT ERROR: ~p ~p", [Fmt, Args]) + end. -safe_format_2(Fmt, Args, Limit) -> +safeFormat(Fmt, Args, Limit) -> try eFmt:formatBin(Fmt, Args, [{charsLimit, Limit}]) catch _:_ -> eFmt:formatBin(<<"FORMAT ERROR: ~p ~p">>, [Fmt, Args], [{charsLimit, Limit}]) end. -%% @private -safe_format_chop(Fmt, Args, Limit) -> - safe_format_2(Fmt, Args, Limit). - %% @private Print the format string `Fmt' with `Args' without a size limit. %% This is unsafe because the output of this function is unbounded. %% @@ -568,75 +532,6 @@ safe_format_chop(Fmt, Args, Limit) -> %% If the format string is invalid or not enough arguments are %% supplied a 'FORMAT ERROR' message is printed instead with the %% offending arguments. The caller is NOT crashed. -unsafe_format(Fmt, Args) -> - try io_lib:format(Fmt, Args) - catch - _:_ -> io_lib:format("FORMAT ERROR: ~p ~p", [Fmt, Args]) - end. - -%% @doc Print a record or a list of records lager found during parse transform -pr(Record, Module) when is_tuple(Record), is_atom(element(1, Record)) -> - pr(Record, Module, []); -pr(List, Module) when is_list(List) -> - pr(List, Module, []); -pr(Record, _) -> - Record. - -%% @doc Print a record or a list of records lager found during parse transform -pr(Record, Module, Options) when is_tuple(Record), is_atom(element(1, Record)), is_list(Options) -> - try - case is_record_known(Record, Module) of - false -> - Record; - {RecordName, RecordFields} -> - {'$lager_record', RecordName, - zip(RecordFields, tl(tuple_to_list(Record)), Module, Options, [])} - end - catch - error:undef -> - Record - end; -pr([Head | Tail], Module, Options) when is_list(Options) -> - [pr(Head, Module, Options) | pr(Tail, Module, Options)]; -pr(Record, _, _) -> - Record. - -zip([FieldName | RecordFields], [FieldValue | Record], Module, Options, ToReturn) when is_list(FieldValue) -> - zip(RecordFields, Record, Module, Options, - [{FieldName, pr(FieldValue, Module, Options)} | ToReturn]); -zip([FieldName | RecordFields], [FieldValue | Record], Module, Options, ToReturn) -> - Compress = lists:member(compress, Options), - case is_tuple(FieldValue) andalso - tuple_size(FieldValue) > 0 andalso - is_atom(element(1, FieldValue)) andalso - is_record_known(FieldValue, Module) of - false when Compress andalso FieldValue =:= undefined -> - zip(RecordFields, Record, Module, Options, ToReturn); - false -> - zip(RecordFields, Record, Module, Options, [{FieldName, FieldValue} | ToReturn]); - _Else -> - F = {FieldName, pr(FieldValue, Module, Options)}, - zip(RecordFields, Record, Module, Options, [F | ToReturn]) - end; -zip([], [], _Module, _Compress, ToReturn) -> - lists:reverse(ToReturn). - -is_record_known(Record, Module) -> - Name = element(1, Record), - Attrs = Module:module_info(attributes), - case lists:keyfind(lager_records, 1, Attrs) of - false -> false; - {lager_records, Records} -> - case lists:keyfind(Name, 1, Records) of - false -> false; - {Name, RecordFields} -> - case (tuple_size(Record) - 1) =:= length(RecordFields) of - false -> false; - true -> {Name, RecordFields} - end - end - end. - %% @private trace_func(#trace_func_state_v1{pid = Pid, level = Level, format_string = Fmt} = FuncState, Event, ProcState) -> diff --git a/src/utils/rumUtil.erl b/src/utils/rumUtil.erl index ba27389..febd47d 100644 --- a/src/utils/rumUtil.erl +++ b/src/utils/rumUtil.erl @@ -504,9 +504,9 @@ parsePath(RelPath) -> %% "logRoot"), but the file paths inside Handlers are not. find_file(_File1, _Handlers = []) -> false; -find_file(File1, [{{lager_file_backend, File2}, _Handler, _Sink} = HandlerInfo | Handlers]) -> +find_file(File1, [{{rumBkdFile, File2}, _Handler, _Sink} = HandlerInfo | Handlers]) -> File1Abs = File1, - File2Abs = lager_util:expand_path(File2), + File2Abs = rumUtil:parsePath(File2), case File1Abs =:= File2Abs of true -> % The file inside HandlerInfo is the same as the file we are looking diff --git a/进度.md b/进度.md deleted file mode 100644 index 124ccfd..0000000 --- a/进度.md +++ /dev/null @@ -1,28 +0,0 @@ -# Done complete - - eRum_sup - eRum.app.src - rumHWatcherSup - rumRotatorExm - -# Done incomplete - - app.config done - eRum_app - rumHWatcherSrv 部分还需要修改 删除测试代码 - rumRotatorIns 旋转日志格式还需要修改 - -# Doing - -# 优化改进之处: - - 日志旋转date格式转换函数修改(注释 对于某些月份 不存在29 30 或者 31天时 要避免M29 M30 M31的配法 代码并没有修复此种情况) - io_lib:format 修改为eFmt:format - -# TODO - - io_lib:format 替换为 eFmt:formatBin - trace代码整理 - - - \ No newline at end of file