|
|
@ -21,8 +21,18 @@ |
|
|
|
%% or refer to other properties, if desired. You can also use a {atom, semi-iolist(), semi-iolist()} formatTer, which |
|
|
|
%% acts like a ternary operator's true/false branches. |
|
|
|
%% |
|
|
|
%% The metadata properties date,time, message, severity, and sev will always exist. |
|
|
|
%% The properties pid, file, line, module, and function will always exist if the parser transform is used. |
|
|
|
%% The metadata properties datetime, message, severity, pid, line, module, and function will always exist. |
|
|
|
|
|
|
|
%% @doc使用半ioiolist作为配置为日志消息提供通用的默认格式。允许的任何iolist配置中的 |
|
|
|
%%元素按原样打印。配置中的原子被视为元数据属性 |
|
|
|
%%并从日志消息中提取。可选地,可以使用{atom(),semi-iolist()}的元组。原子会看起来 |
|
|
|
%%的属性,但如果找不到,它将使用semi-iolist()代替。这些后备广告可以类似地嵌套 |
|
|
|
%%或参考其他属性(如果需要)。您还可以使用{atom,semi-iolist(),semi-iolist()} formatTer, |
|
|
|
%%的作用类似于三元运算符的true / false分支。 |
|
|
|
%% |
|
|
|
%%元数据属性日期,时间,消息,严重性和严重性将始终存在。 |
|
|
|
%%如果使用解析器转换,则pid,文件,行,模块和函数的属性将始终存在 |
|
|
|
|
|
|
|
%% |
|
|
|
%% Example: |
|
|
|
%% |
|
|
@ -34,173 +44,148 @@ |
|
|
|
%% |
|
|
|
%% `[{pid, ["My pid is ", pid], ["Unknown Pid"]}]' -> if pid is in the metada print "My pid is ?.?.?", otherwise print "Unknown Pid" |
|
|
|
%% @end |
|
|
|
-spec format(rumMsg:rumMsg(), list(), list()) -> any(). |
|
|
|
format(Msg, [], Colors) -> |
|
|
|
format(Msg, [{eol, "\n"}], Colors); |
|
|
|
format(Msg, [{eol, EOL}], Colors) -> |
|
|
|
|
|
|
|
-spec format(rumMsg(), list()) -> any(). |
|
|
|
format(RumMsg, Config) -> |
|
|
|
[output(V, RumMsg) || V <- Config]. |
|
|
|
|
|
|
|
-spec format(rumMsg(), list(), list()) -> any(). |
|
|
|
format(RumMsg, [], Colors) -> |
|
|
|
format(RumMsg, [{eol, "\n"}], Colors); |
|
|
|
format(RumMsg, [{eol, EOL}], Colors) -> |
|
|
|
Config = |
|
|
|
case rumUtil:get_env(metadataWhitelist, undefined) of |
|
|
|
undefined -> config(EOL, []); |
|
|
|
Whitelist -> config(EOL, Whitelist) |
|
|
|
end, |
|
|
|
format(Msg, Config, Colors); |
|
|
|
format(Message, Config, Colors) -> |
|
|
|
format(RumMsg, Config, Colors); |
|
|
|
format(RumMsg, Config, Colors) -> |
|
|
|
[ |
|
|
|
case V of |
|
|
|
color -> output_color(Message, Colors); |
|
|
|
_ -> output(V, Message) |
|
|
|
color -> outColor(Colors, RumMsg); |
|
|
|
_ -> output(V, RumMsg) |
|
|
|
end || V <- Config |
|
|
|
]. |
|
|
|
|
|
|
|
-spec format(rumMsg:rumMsg(), list()) -> any(). |
|
|
|
format(Msg, Config) -> |
|
|
|
format(Msg, Config, []). |
|
|
|
|
|
|
|
-spec output(term(), rumMsg:rumMsg()) -> iolist(). |
|
|
|
output(message, Msg) -> rumMsg:message(Msg); |
|
|
|
output(datetime, Msg) -> |
|
|
|
rumMsg:datetime(Msg); |
|
|
|
output(severity, Msg) -> |
|
|
|
atom_to_list(rumMsg:severity(Msg)); |
|
|
|
output(severity_upper, Msg) -> |
|
|
|
uppercase_severity(rumMsg:severity(Msg)); |
|
|
|
output(blank, _Msg) -> |
|
|
|
output({blank, " "}, _Msg); |
|
|
|
output(node, _Msg) -> |
|
|
|
output({node, atom_to_list(node())}, _Msg); |
|
|
|
output({blank, Fill}, _Msg) -> |
|
|
|
Fill; |
|
|
|
output(sev, Msg) -> |
|
|
|
%% Write brief acronym for the severity level (e.g. debug -> $D) |
|
|
|
[rumUtil:levelToChr(rumMsg:severity(Msg))]; |
|
|
|
output(metadata, Msg) -> |
|
|
|
output({metadata, "=", " "}, Msg); |
|
|
|
output({metadata, IntSep, FieldSep}, Msg) -> |
|
|
|
MD = lists:keysort(1, rumMsg:metadata(Msg)), |
|
|
|
string:join([io_lib:format("~s~s~p", [K, IntSep, V]) || {K, V} <- MD], FieldSep); |
|
|
|
output({pterm, Key}, Msg) -> |
|
|
|
output({pterm, Key, ""}, Msg); |
|
|
|
output({pterm, Key, Default}, _Msg) -> |
|
|
|
make_printable(maybe_get_persistent_term(Key, Default)); |
|
|
|
output(Prop, Msg) when is_atom(Prop) -> |
|
|
|
Metadata = rumMsg:metadata(Msg), |
|
|
|
make_printable(get_metadata(Prop, Metadata, <<"Undefined">>)); |
|
|
|
output({Prop, Default}, Msg) when is_atom(Prop) -> |
|
|
|
Metadata = rumMsg:metadata(Msg), |
|
|
|
make_printable(get_metadata(Prop, Metadata, output(Default, Msg))); |
|
|
|
output({Prop, Present, Absent}, Msg) when is_atom(Prop) -> |
|
|
|
%% sort of like a poor man's ternary operator |
|
|
|
Metadata = rumMsg:metadata(Msg), |
|
|
|
case get_metadata(Prop, Metadata) of |
|
|
|
-spec output(term(), rumMsg()) -> iolist(). |
|
|
|
output(message, RumMsg) -> RumMsg#rumMsg.message; |
|
|
|
output(datetime, RumMsg) -> RumMsg#rumMsg.datetime; |
|
|
|
output(module, RumMsg) -> atom_to_binary(RumMsg#rumMsg.module, utf8); |
|
|
|
output(function, RumMsg) -> atom_to_binary(RumMsg#rumMsg.function, utf8); |
|
|
|
output(line, RumMsg) -> integer_to_binary(RumMsg#rumMsg.line); |
|
|
|
output(severity, RumMsg) -> loSeverity(RumMsg#rumMsg.severity); |
|
|
|
output(upSeverity, RumMsg) -> upSeverity(RumMsg#rumMsg.severity); |
|
|
|
output(blank, _RumMsg) -> <<" ">>; |
|
|
|
output(node, RumMsg) -> atom_to_binary(RumMsg#rumMsg.node, utf8); |
|
|
|
output(sev, RumMsg) -> sevSeverity(RumMsg#rumMsg.severity); %% Write brief acronym for the severity level (e.g. debug -> $D) |
|
|
|
output(metadata, RumMsg) -> mdJoin(RumMsg#rumMsg.metadata, <<"|">>, <<>>); |
|
|
|
output({blank, Fill}, _RumMsg) -> Fill; |
|
|
|
output({metadata, IntSep, FieldSep}, RumMsg) -> |
|
|
|
MD = lists:keysort(1, RumMsg#rumMsg.metadata), mdJoin(MD, IntSep, FieldSep, <<>>); |
|
|
|
output({pterm, Key}, _RumMsg) -> |
|
|
|
makeStr(getPTerm(Key, <<"">>)); |
|
|
|
output({pterm, Key, Default}, _RumMsg) -> |
|
|
|
makeStr(getPTerm(Key, Default)); |
|
|
|
output(Prop, RumMsg) when is_atom(Prop) -> |
|
|
|
makeStr(getMdKey(Prop, RumMsg#rumMsg.metadata, <<"Undefined">>)); |
|
|
|
output({Prop, Default}, RumMsg) when is_atom(Prop) -> |
|
|
|
makeStr(getMdKey(Prop, RumMsg#rumMsg.metadata, output(Default, RumMsg))); |
|
|
|
output({Prop, Present, Absent}, RumMsg) when is_atom(Prop) -> |
|
|
|
case getMdKey(Prop, RumMsg#rumMsg.metadata) of |
|
|
|
undefined -> |
|
|
|
[output(V, Msg) || V <- Absent]; |
|
|
|
[output(V, RumMsg) || V <- Absent]; |
|
|
|
_ -> |
|
|
|
[output(V, Msg) || V <- Present] |
|
|
|
[output(V, RumMsg) || V <- Present] |
|
|
|
end; |
|
|
|
output({Prop, Present, Absent, Width}, Msg) when is_atom(Prop) -> |
|
|
|
output({Prop, Present, Absent, Width}, RumMsg) when is_atom(Prop) -> |
|
|
|
%% sort of like a poor man's ternary operator |
|
|
|
Metadata = rumMsg:metadata(Msg), |
|
|
|
case get_metadata(Prop, Metadata) of |
|
|
|
case getMdKey(Prop, RumMsg#rumMsg.metadata) of |
|
|
|
undefined -> |
|
|
|
[output(V, Msg, Width) || V <- Absent]; |
|
|
|
[output(V, RumMsg, Width) || V <- Absent]; |
|
|
|
_ -> |
|
|
|
[output(V, Msg, Width) || V <- Present] |
|
|
|
[output(V, RumMsg, Width) || V <- Present] |
|
|
|
end; |
|
|
|
output(Other, _) -> make_printable(Other). |
|
|
|
|
|
|
|
output(message, Msg, _Width) -> rumMsg:message(Msg); |
|
|
|
output(datetime, Msg, _Width) -> |
|
|
|
rumMsg:datetime(Msg); |
|
|
|
output(severity, Msg, Width) -> |
|
|
|
make_printable(atom_to_list(rumMsg:severity(Msg)), Width); |
|
|
|
output(sev, Msg, _Width) -> |
|
|
|
%% Write brief acronym for the severity level (e.g. debug -> $D) |
|
|
|
[rumUtil:levelToChr(rumMsg:severity(Msg))]; |
|
|
|
output(node, Msg, _Width) -> |
|
|
|
output({node, atom_to_list(node())}, Msg, _Width); |
|
|
|
output(blank, _Msg, _Width) -> |
|
|
|
output({blank, " "}, _Msg, _Width); |
|
|
|
output({blank, Fill}, _Msg, _Width) -> |
|
|
|
Fill; |
|
|
|
output(metadata, Msg, _Width) -> |
|
|
|
output({metadata, "=", " "}, Msg, _Width); |
|
|
|
output({metadata, IntSep, FieldSep}, Msg, _Width) -> |
|
|
|
MD = lists:keysort(1, rumMsg:metadata(Msg)), |
|
|
|
[string:join([io_lib:format("~s~s~p", [K, IntSep, V]) || {K, V} <- MD], FieldSep)]; |
|
|
|
output({pterm, Key}, Msg, Width) -> |
|
|
|
output({pterm, Key, ""}, Msg, Width); |
|
|
|
output({pterm, Key, Default}, _Msg, _Width) -> |
|
|
|
make_printable(maybe_get_persistent_term(Key, Default)); |
|
|
|
|
|
|
|
output(Prop, Msg, Width) when is_atom(Prop) -> |
|
|
|
Metadata = rumMsg:metadata(Msg), |
|
|
|
make_printable(get_metadata(Prop, Metadata, <<"Undefined">>), Width); |
|
|
|
output({Prop, Default}, Msg, Width) when is_atom(Prop) -> |
|
|
|
Metadata = rumMsg:metadata(Msg), |
|
|
|
make_printable(get_metadata(Prop, Metadata, output(Default, Msg)), Width); |
|
|
|
output(Other, _, Width) -> make_printable(Other, Width). |
|
|
|
|
|
|
|
output_color(_Msg, []) -> []; |
|
|
|
output_color(Msg, Colors) -> |
|
|
|
Level = rumMsg:severity(Msg), |
|
|
|
case lists:keyfind(Level, 1, Colors) of |
|
|
|
output(Other, _) -> makeStr(Other). |
|
|
|
|
|
|
|
output(message, RumMsg, _Width) -> RumMsg#rumMsg.message; |
|
|
|
output(datetime, RumMsg, _Width) -> RumMsg#rumMsg.datetime; |
|
|
|
output(module, RumMsg, _Width) -> atom_to_binary(RumMsg#rumMsg.module, utf8); |
|
|
|
output(function, RumMsg, _Width) -> atom_to_binary(RumMsg#rumMsg.function, utf8); |
|
|
|
output(line, RumMsg, _Width) -> integer_to_binary(RumMsg#rumMsg.line); |
|
|
|
output(severity, RumMsg, _Width) -> loSeverity(RumMsg#rumMsg.severity); |
|
|
|
output(upSeverity, RumMsg, _Width) -> upSeverity(RumMsg#rumMsg.severity); |
|
|
|
output(blank, _RumMsg, _Width) -> <<" ">>; |
|
|
|
output(node, RumMsg, _Width) -> atom_to_binary(RumMsg#rumMsg.node, utf8); |
|
|
|
output(sev, RumMsg, _Width) -> sevSeverity(RumMsg#rumMsg.severity); %% Write brief acronym for the severity level (e.g. debug -> $D) |
|
|
|
output({blank, Fill}, _RumMsg, _Width) -> Fill; |
|
|
|
output(metadata, RumMsg, _Width) -> mdJoin(RumMsg#rumMsg.metadata, <<"|">>, <<>>); |
|
|
|
output({metadata, IntSep, FieldSep}, RumMsg, _Width) -> |
|
|
|
MD = lists:keysort(1, RumMsg#rumMsg.metadata), mdJoin(MD, IntSep, FieldSep, <<>>); |
|
|
|
output({pterm, Key}, _RumMsg, _Width) -> makeStr(getPTerm(Key, <<"">>)); |
|
|
|
output({pterm, Key, Default}, _RumMsg, _Width) -> makeStr(getPTerm(Key, Default)); |
|
|
|
output(Prop, RumMsg, Width) when is_atom(Prop) -> |
|
|
|
makeStr(getMdKey(Prop, RumMsg#rumMsg.metadata, <<"Undefined">>), Width); |
|
|
|
output({Prop, Default}, RumMsg, Width) when is_atom(Prop) -> |
|
|
|
makeStr(getMdKey(Prop, RumMsg#rumMsg.metadata, output(Default, RumMsg)), Width); |
|
|
|
output(Other, _, Width) -> makeStr(Other, Width). |
|
|
|
|
|
|
|
outColor([], _RumMsg) -> <<>>; |
|
|
|
outColor(Colors, RumMsg) -> |
|
|
|
case lists:keyfind(RumMsg#rumMsg.severity, 1, Colors) of |
|
|
|
{_, Color} -> Color; |
|
|
|
_ -> [] |
|
|
|
_ -> <<>> |
|
|
|
end. |
|
|
|
|
|
|
|
-spec make_printable(any()) -> iolist(). |
|
|
|
make_printable(A) when is_atom(A) -> atom_to_list(A); |
|
|
|
make_printable(P) when is_pid(P) -> pid_to_list(P); |
|
|
|
make_printable(L) when is_list(L) orelse is_binary(L) -> L; |
|
|
|
make_printable(Other) -> io_lib:format("~p", [Other]). |
|
|
|
|
|
|
|
make_printable(A, W) when is_integer(W) -> string:left(make_printable(A), W); |
|
|
|
make_printable(A, {Align, W}) when is_integer(W) -> |
|
|
|
case Align of |
|
|
|
left -> |
|
|
|
string:left(make_printable(A), W); |
|
|
|
centre -> |
|
|
|
string:centre(make_printable(A), W); |
|
|
|
right -> |
|
|
|
string:right(make_printable(A), W); |
|
|
|
_ -> |
|
|
|
string:left(make_printable(A), W) |
|
|
|
end; |
|
|
|
-spec makeStr(any()) -> iolist(). |
|
|
|
makeStr(A) when is_atom(A) -> atom_to_binary(A); |
|
|
|
makeStr(P) when is_pid(P) -> list_to_binary(pid_to_list(P)); |
|
|
|
makeStr(B) when is_binary(B) -> B; |
|
|
|
makeStr(Other) -> eFmt:formatBin("~p", [Other]). |
|
|
|
|
|
|
|
makeList(A) when is_atom(A) -> atom_to_list(A); |
|
|
|
makeList(P) when is_pid(P) -> pid_to_list(P); |
|
|
|
makeList(Other) -> binary_to_list(eFmt:formatBin("~p", [Other])). |
|
|
|
|
|
|
|
makeStr(A, W) when is_integer(W) -> makeStr(left, makeList(A), W); |
|
|
|
makeStr(A, {Align, W}) when is_integer(W) -> |
|
|
|
makeStr(Align, makeList(A), W); |
|
|
|
makeStr(A, _W) -> makeStr(A). |
|
|
|
|
|
|
|
make_printable(A, _W) -> make_printable(A). |
|
|
|
makeStr(left, Str, W) -> |
|
|
|
list_to_binary(string:left(Str, W)); |
|
|
|
makeStr(centre, Str, W) -> |
|
|
|
list_to_binary(string:centre(Str, W)); |
|
|
|
makeStr(right, Str, W) -> |
|
|
|
list_to_binary(string:right(Str, W)); |
|
|
|
makeStr(_, Str, W) -> |
|
|
|
list_to_binary(string:left(Str, W)). |
|
|
|
|
|
|
|
%% persistent term was introduced in OTP 21.2, so |
|
|
|
%% if we're running on an older OTP, just return the |
|
|
|
%% default value. |
|
|
|
maybe_get_persistent_term(Key, Default) -> |
|
|
|
try |
|
|
|
persistent_term:get(Key, Default) |
|
|
|
catch |
|
|
|
_:undef -> Default |
|
|
|
end. |
|
|
|
getPTerm(Key, Default) -> |
|
|
|
persistent_term:get(Key, Default). |
|
|
|
|
|
|
|
run_function(Function, Default) -> |
|
|
|
try Function() of |
|
|
|
Result -> |
|
|
|
Result |
|
|
|
catch |
|
|
|
_:_ -> |
|
|
|
Default |
|
|
|
end. |
|
|
|
getMdKey(Key, Metadata) -> |
|
|
|
getMdKey(Key, Metadata, undefined). |
|
|
|
|
|
|
|
get_metadata(Key, Metadata) -> |
|
|
|
get_metadata(Key, Metadata, undefined). |
|
|
|
|
|
|
|
get_metadata(Key, Metadata, Default) -> |
|
|
|
getMdKey(Key, Metadata, Default) -> |
|
|
|
case lists:keyfind(Key, 1, Metadata) of |
|
|
|
false -> |
|
|
|
Default; |
|
|
|
{Key, Value} when is_function(Value) -> |
|
|
|
run_function(Value, Default); |
|
|
|
{Key, Value} -> |
|
|
|
{_Key, Fun} when is_function(Fun) -> |
|
|
|
runFun(Fun, Default); |
|
|
|
{_Key, Value} -> |
|
|
|
Value |
|
|
|
end. |
|
|
|
|
|
|
|
runFun(Fun, Default) -> |
|
|
|
try Fun() |
|
|
|
catch |
|
|
|
_:_ -> |
|
|
|
Default |
|
|
|
end. |
|
|
|
|
|
|
|
config(EOL, []) -> |
|
|
|
[ |
|
|
|
datetime, " ", color, "[", severity, "] ", |
|
|
@ -226,13 +211,51 @@ config(EOL, MetaWhitelist) -> |
|
|
|
[{M, [atom_to_list(M), "=", M, " "], ""} || M <- MetaWhitelist] ++ |
|
|
|
[message, EOL]. |
|
|
|
|
|
|
|
loSeverity(?debug) -> <<"debug">>; |
|
|
|
loSeverity(?info) -> <<"info">>; |
|
|
|
loSeverity(?notice) -> <<"notice">>; |
|
|
|
loSeverity(?warning) -> <<"warning">>; |
|
|
|
loSeverity(?error) -> <<"error">>; |
|
|
|
loSeverity(?critical) -> <<"critical">>; |
|
|
|
loSeverity(?alert) -> <<"alert">>; |
|
|
|
loSeverity(?emergency) -> <<"emergency">>; |
|
|
|
loSeverity(?none) -> <<"none">>. |
|
|
|
|
|
|
|
upSeverity(?debug) -> <<"DEBUG">>; |
|
|
|
upSeverity(?info) -> <<"INFO">>; |
|
|
|
upSeverity(?notice) -> <<"NOTICE">>; |
|
|
|
upSeverity(?warning) -> <<"WARNING">>; |
|
|
|
upSeverity(?error) -> <<"ERROR">>; |
|
|
|
upSeverity(?critical) -> <<"CRITICAL">>; |
|
|
|
upSeverity(?alert) -> <<"ALERT">>; |
|
|
|
upSeverity(?emergency) -> <<"EMERGENCY">>; |
|
|
|
upSeverity(?none) -> <<"NONE">>. |
|
|
|
|
|
|
|
sevSeverity(?debug) -> <<"[D]">>; |
|
|
|
sevSeverity(?info) -> <<"[I]">>; |
|
|
|
sevSeverity(?notice) -> <<"[N]">>; |
|
|
|
sevSeverity(?warning) -> <<"[W]">>; |
|
|
|
sevSeverity(?error) -> <<"[E]">>; |
|
|
|
sevSeverity(?critical) -> <<"[C]">>; |
|
|
|
sevSeverity(?alert) -> <<"[A]">>; |
|
|
|
sevSeverity(?emergency) -> <<"[E]">>; |
|
|
|
sevSeverity(?none) -> <<"[o]">>. |
|
|
|
|
|
|
|
mdJoin([], _FieldSep, BinAcc) -> |
|
|
|
BinAcc; |
|
|
|
mdJoin([{_K, V}], _FieldSep, BinAcc) -> |
|
|
|
<<BinAcc/binary, (eFmt:formatBin("~p", [V]))/binary>>; |
|
|
|
mdJoin([{_K, V} | Left], FieldSep, BinAcc) -> |
|
|
|
mdJoin(Left, FieldSep, <<BinAcc/binary, (eFmt:formatBin("~p", [V]))/binary, FieldSep/binary>>). |
|
|
|
|
|
|
|
mdJoin([], _IntSep, _FieldSep, BinAcc) -> |
|
|
|
BinAcc; |
|
|
|
mdJoin([{K, V}], IntSep, _FieldSep, BinAcc) -> |
|
|
|
<<BinAcc/binary, (eFmt:formatBin("~p~s~p", [K, IntSep, V]))/binary>>; |
|
|
|
mdJoin([{K, V} | Left], IntSep, FieldSep, BinAcc) -> |
|
|
|
mdJoin(Left, FieldSep, <<BinAcc/binary, (eFmt:formatBin("~p~s~p", [K, IntSep, V]))/binary, FieldSep/binary>>). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uppercase_severity(debug) -> "DEBUG"; |
|
|
|
uppercase_severity(info) -> "INFO"; |
|
|
|
uppercase_severity(notice) -> "NOTICE"; |
|
|
|
uppercase_severity(warning) -> "WARNING"; |
|
|
|
uppercase_severity(error) -> "ERROR"; |
|
|
|
uppercase_severity(critical) -> "CRITICAL"; |
|
|
|
uppercase_severity(alert) -> "ALERT"; |
|
|
|
uppercase_severity(emergency) -> "EMERGENCY". |