|
|
@ -75,139 +75,140 @@ walk_clauses(Acc, [{clause, Line, Arguments, Guards, Body}|T]) -> |
|
|
|
walk_body(Acc, []) -> |
|
|
|
lists:reverse(Acc); |
|
|
|
walk_body(Acc, [H|T]) -> |
|
|
|
walk_body([transform_statement(H)|Acc], T). |
|
|
|
walk_body([transform_statement(H, [lager])|Acc], T). |
|
|
|
|
|
|
|
transform_statement({call, Line, {remote, _Line1, {atom, _Line2, lager}, |
|
|
|
{atom, _Line3, Severity}}, Arguments0} = Stmt) -> |
|
|
|
case lists:member(Severity, ?LEVELS) of |
|
|
|
transform_statement({call, Line, {remote, _Line1, {atom, _Line2, Module}, |
|
|
|
{atom, _Line3, Function}}, Arguments0} = Stmt, |
|
|
|
Sinks) -> |
|
|
|
case lists:member(Module, Sinks) of |
|
|
|
true -> |
|
|
|
SeverityAsInt=lager_util:level_to_num(Severity), |
|
|
|
DefaultAttrs0 = {cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, module}, {atom, Line, get(module)}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, function}, {atom, Line, get(function)}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, line}, |
|
|
|
{integer, Line, Line}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, pid}, |
|
|
|
{call, Line, {atom, Line, pid_to_list}, [ |
|
|
|
{call, Line, {atom, Line ,self}, []}]}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, node}, |
|
|
|
{call, Line, {atom, Line, node}, []}]}, |
|
|
|
%% get the metadata with lager:md(), this will always return a list so we can use it as the tail here |
|
|
|
{call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, md}}, []}}}}}}, |
|
|
|
%{nil, Line}}}}}}}, |
|
|
|
DefaultAttrs = case erlang:get(application) of |
|
|
|
undefined -> |
|
|
|
DefaultAttrs0; |
|
|
|
App -> |
|
|
|
%% stick the application in the attribute list |
|
|
|
concat_lists({cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, application}, |
|
|
|
{atom, Line, App}]}, |
|
|
|
{nil, Line}}, DefaultAttrs0) |
|
|
|
end, |
|
|
|
{Traces, Message, Arguments} = case Arguments0 of |
|
|
|
[Format] -> |
|
|
|
{DefaultAttrs, Format, {atom, Line, none}}; |
|
|
|
[Arg1, Arg2] -> |
|
|
|
%% some ambiguity here, figure out if these arguments are |
|
|
|
%% [Format, Args] or [Attr, Format]. |
|
|
|
%% The trace attributes will be a list of tuples, so check |
|
|
|
%% for that. |
|
|
|
case {element(1, Arg1), Arg1} of |
|
|
|
{_, {cons, _, {tuple, _, _}, _}} -> |
|
|
|
{concat_lists(Arg1, DefaultAttrs), |
|
|
|
Arg2, {atom, Line, none}}; |
|
|
|
{Type, _} when Type == var; |
|
|
|
Type == lc; |
|
|
|
Type == call; |
|
|
|
Type == record_field -> |
|
|
|
%% crap, its not a literal. look at the second |
|
|
|
%% argument to see if it is a string |
|
|
|
case Arg2 of |
|
|
|
{string, _, _} -> |
|
|
|
{concat_lists(Arg1, DefaultAttrs), |
|
|
|
Arg2, {atom, Line, none}}; |
|
|
|
_ -> |
|
|
|
%% not a string, going to have to guess |
|
|
|
%% it's the argument list |
|
|
|
{DefaultAttrs, Arg1, Arg2} |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
{DefaultAttrs, Arg1, Arg2} |
|
|
|
end; |
|
|
|
[Attrs, Format, Args] -> |
|
|
|
{concat_lists(Attrs, DefaultAttrs), Format, Args} |
|
|
|
end, |
|
|
|
%% Generate some unique variable names so we don't accidentaly export from case clauses. |
|
|
|
%% Note that these are not actual atoms, but the AST treats variable names as atoms. |
|
|
|
LevelVar = make_varname("__Level", Line), |
|
|
|
TracesVar = make_varname("__Traces", Line), |
|
|
|
PidVar = make_varname("__Pid", Line), |
|
|
|
%% Wrap the call to lager_dispatch log in a case that will avoid doing any work if this message is not elegible for logging |
|
|
|
%% case {whereis(lager_event(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of |
|
|
|
{'case', Line, |
|
|
|
{tuple, Line, |
|
|
|
[{call, Line, {atom, Line, whereis}, [{atom, Line, lager_event}]}, |
|
|
|
{call, Line, {remote, Line, {atom, Line, lager_config}, {atom, Line, get}}, [{atom, Line, loglevel}, {tuple, Line, [{integer, Line, 0},{nil, Line}]}]}]}, |
|
|
|
[ |
|
|
|
%% {undefined, _} -> {error, lager_not_running} |
|
|
|
{clause, Line, |
|
|
|
[{tuple, Line, [{atom, Line, undefined}, {var, Line, '_'}]}], |
|
|
|
[], |
|
|
|
%% trick the linter into avoiding a 'term constructed by not used' error: |
|
|
|
%% (fun() -> {error, lager_not_running} end)(); |
|
|
|
[{call, Line, {'fun', Line, {clauses, [{clause, Line, [],[], [{tuple, Line, [{atom, Line, error},{atom, Line, lager_not_running}]}]}]}}, []}]}, |
|
|
|
%% If we care about the loglevel, or there's any traces installed, we have do more checking |
|
|
|
%% {Level, Traces} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] -> |
|
|
|
{clause, Line, |
|
|
|
[{tuple, Line, [{var, Line, PidVar}, {tuple, Line, [{var, Line, LevelVar}, {var, Line, TracesVar}]}]}], |
|
|
|
[[{op, Line, 'orelse', |
|
|
|
{op, Line, '/=', {op, Line, 'band', {var, Line, LevelVar}, {integer, Line, SeverityAsInt}}, {integer, Line, 0}}, |
|
|
|
{op, Line, '/=', {var, Line, TracesVar}, {nil, Line}}}]], |
|
|
|
[ |
|
|
|
%% do the call to lager:dispatch_log |
|
|
|
{call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, do_log}}, |
|
|
|
[ |
|
|
|
{atom,Line,Severity}, |
|
|
|
Traces, |
|
|
|
Message, |
|
|
|
Arguments, |
|
|
|
{integer, Line, get(truncation_size)}, |
|
|
|
{integer, Line, SeverityAsInt}, |
|
|
|
{var, Line, LevelVar}, |
|
|
|
{var, Line, TracesVar}, |
|
|
|
{atom, Line, lager_event}, |
|
|
|
{var, Line, PidVar} |
|
|
|
] |
|
|
|
} |
|
|
|
]}, |
|
|
|
%% otherwise, do nothing |
|
|
|
%% _ -> ok |
|
|
|
{clause, Line, [{var, Line, '_'}],[],[{atom, Line, ok}]} |
|
|
|
]}; |
|
|
|
case lists:member(Function, ?LEVELS) of |
|
|
|
true -> |
|
|
|
SinkName = list_to_atom(atom_to_list(Module) ++ "_event"), |
|
|
|
do_transform(Line, SinkName, Function, Arguments0); |
|
|
|
false -> |
|
|
|
Stmt |
|
|
|
end; |
|
|
|
false -> |
|
|
|
Stmt |
|
|
|
list_to_tuple(transform_statement(tuple_to_list(Stmt), Sinks)) |
|
|
|
end; |
|
|
|
transform_statement({call, Line, {remote, Line1, {atom, Line2, boston_lager}, |
|
|
|
{atom, Line3, Severity}}, Arguments}) -> |
|
|
|
NewArgs = case Arguments of |
|
|
|
[{string, L, Msg}] -> [{string, L, re:replace(Msg, "r", "h", [{return, list}, global])}]; |
|
|
|
[{string, L, Format}, Args] -> [{string, L, re:replace(Format, "r", "h", [{return, list}, global])}, Args]; |
|
|
|
Other -> Other |
|
|
|
end, |
|
|
|
transform_statement({call, Line, {remote, Line1, {atom, Line2, lager}, |
|
|
|
{atom, Line3, Severity}}, NewArgs}); |
|
|
|
transform_statement(Stmt) when is_tuple(Stmt) -> |
|
|
|
list_to_tuple(transform_statement(tuple_to_list(Stmt))); |
|
|
|
transform_statement(Stmt) when is_list(Stmt) -> |
|
|
|
[transform_statement(S) || S <- Stmt]; |
|
|
|
transform_statement(Stmt) -> |
|
|
|
transform_statement(Stmt, Sinks) when is_tuple(Stmt) -> |
|
|
|
list_to_tuple(transform_statement(tuple_to_list(Stmt), Sinks)); |
|
|
|
transform_statement(Stmt, Sinks) when is_list(Stmt) -> |
|
|
|
[transform_statement(S, Sinks) || S <- Stmt]; |
|
|
|
transform_statement(Stmt, _Sinks) -> |
|
|
|
Stmt. |
|
|
|
|
|
|
|
do_transform(Line, SinkName, Severity, Arguments0) -> |
|
|
|
SeverityAsInt=lager_util:level_to_num(Severity), |
|
|
|
DefaultAttrs0 = {cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, module}, {atom, Line, get(module)}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, function}, {atom, Line, get(function)}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, line}, |
|
|
|
{integer, Line, Line}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, pid}, |
|
|
|
{call, Line, {atom, Line, pid_to_list}, [ |
|
|
|
{call, Line, {atom, Line ,self}, []}]}]}, |
|
|
|
{cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, node}, |
|
|
|
{call, Line, {atom, Line, node}, []}]}, |
|
|
|
%% get the metadata with lager:md(), this will always return a list so we can use it as the tail here |
|
|
|
{call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, md}}, []}}}}}}, |
|
|
|
%{nil, Line}}}}}}}, |
|
|
|
DefaultAttrs = case erlang:get(application) of |
|
|
|
undefined -> |
|
|
|
DefaultAttrs0; |
|
|
|
App -> |
|
|
|
%% stick the application in the attribute list |
|
|
|
concat_lists({cons, Line, {tuple, Line, [ |
|
|
|
{atom, Line, application}, |
|
|
|
{atom, Line, App}]}, |
|
|
|
{nil, Line}}, DefaultAttrs0) |
|
|
|
end, |
|
|
|
{Traces, Message, Arguments} = case Arguments0 of |
|
|
|
[Format] -> |
|
|
|
{DefaultAttrs, Format, {atom, Line, none}}; |
|
|
|
[Arg1, Arg2] -> |
|
|
|
%% some ambiguity here, figure out if these arguments are |
|
|
|
%% [Format, Args] or [Attr, Format]. |
|
|
|
%% The trace attributes will be a list of tuples, so check |
|
|
|
%% for that. |
|
|
|
case {element(1, Arg1), Arg1} of |
|
|
|
{_, {cons, _, {tuple, _, _}, _}} -> |
|
|
|
{concat_lists(Arg1, DefaultAttrs), |
|
|
|
Arg2, {atom, Line, none}}; |
|
|
|
{Type, _} when Type == var; |
|
|
|
Type == lc; |
|
|
|
Type == call; |
|
|
|
Type == record_field -> |
|
|
|
%% crap, its not a literal. look at the second |
|
|
|
%% argument to see if it is a string |
|
|
|
case Arg2 of |
|
|
|
{string, _, _} -> |
|
|
|
{concat_lists(Arg1, DefaultAttrs), |
|
|
|
Arg2, {atom, Line, none}}; |
|
|
|
_ -> |
|
|
|
%% not a string, going to have to guess |
|
|
|
%% it's the argument list |
|
|
|
{DefaultAttrs, Arg1, Arg2} |
|
|
|
end; |
|
|
|
_ -> |
|
|
|
{DefaultAttrs, Arg1, Arg2} |
|
|
|
end; |
|
|
|
[Attrs, Format, Args] -> |
|
|
|
{concat_lists(Attrs, DefaultAttrs), Format, Args} |
|
|
|
end, |
|
|
|
%% Generate some unique variable names so we don't accidentaly export from case clauses. |
|
|
|
%% Note that these are not actual atoms, but the AST treats variable names as atoms. |
|
|
|
LevelVar = make_varname("__Level", Line), |
|
|
|
TracesVar = make_varname("__Traces", Line), |
|
|
|
PidVar = make_varname("__Pid", Line), |
|
|
|
%% Wrap the call to lager_dispatch log in a case that will avoid doing any work if this message is not elegible for logging |
|
|
|
%% case {whereis(lager_event(lager_event), lager_config:get(loglevel, {?LOG_NONE, []})} of |
|
|
|
{'case', Line, |
|
|
|
{tuple, Line, |
|
|
|
[{call, Line, {atom, Line, whereis}, [{atom, Line, SinkName}]}, |
|
|
|
{call, Line, {remote, Line, {atom, Line, lager_config}, {atom, Line, get}}, [{atom, Line, loglevel}, {tuple, Line, [{integer, Line, 0},{nil, Line}]}]}]}, |
|
|
|
[ |
|
|
|
%% {undefined, _} -> {error, lager_not_running} |
|
|
|
{clause, Line, |
|
|
|
[{tuple, Line, [{atom, Line, undefined}, {var, Line, '_'}]}], |
|
|
|
[], |
|
|
|
%% trick the linter into avoiding a 'term constructed by not used' error: |
|
|
|
%% (fun() -> {error, lager_not_running} end)(); |
|
|
|
[{call, Line, {'fun', Line, {clauses, [{clause, Line, [],[], [{tuple, Line, [{atom, Line, error},{atom, Line, lager_not_running}]}]}]}}, []}]}, |
|
|
|
%% If we care about the loglevel, or there's any traces installed, we have do more checking |
|
|
|
%% {Level, Traces} when (Level band SeverityAsInt) /= 0 orelse Traces /= [] -> |
|
|
|
{clause, Line, |
|
|
|
[{tuple, Line, [{var, Line, PidVar}, {tuple, Line, [{var, Line, LevelVar}, {var, Line, TracesVar}]}]}], |
|
|
|
[[{op, Line, 'orelse', |
|
|
|
{op, Line, '/=', {op, Line, 'band', {var, Line, LevelVar}, {integer, Line, SeverityAsInt}}, {integer, Line, 0}}, |
|
|
|
{op, Line, '/=', {var, Line, TracesVar}, {nil, Line}}}]], |
|
|
|
[ |
|
|
|
%% do the call to lager:dispatch_log |
|
|
|
{call, Line, {remote, Line, {atom, Line, lager}, {atom, Line, do_log}}, |
|
|
|
[ |
|
|
|
{atom,Line,Severity}, |
|
|
|
Traces, |
|
|
|
Message, |
|
|
|
Arguments, |
|
|
|
{integer, Line, get(truncation_size)}, |
|
|
|
{integer, Line, SeverityAsInt}, |
|
|
|
{var, Line, LevelVar}, |
|
|
|
{var, Line, TracesVar}, |
|
|
|
{atom, Line, SinkName}, |
|
|
|
{var, Line, PidVar} |
|
|
|
] |
|
|
|
} |
|
|
|
]}, |
|
|
|
%% otherwise, do nothing |
|
|
|
%% _ -> ok |
|
|
|
{clause, Line, [{var, Line, '_'}],[],[{atom, Line, ok}]} |
|
|
|
]}. |
|
|
|
|
|
|
|
make_varname(Prefix, Line) -> |
|
|
|
list_to_atom(Prefix ++ atom_to_list(get(module)) ++ integer_to_list(Line)). |
|
|
|
|
|
|
|