lager是一个erlang的日志库,详解介绍参考 这里。
在使用lager进行日志记录时, 只需要调用lager:Level/2,3即可(Level包括debug,info,notice,warning等等).例如:
lager:info("hello world").
在编译时使用lager写日志的模块都需要指定编译选项:
-compile([{parse_transform, lager_transform}]).
如果使用的是rebar, 也可以在配置文件中增加对应的参数, 而不需要在每个模块中都增加编译选项.
{erl_opts, [{parse_transform, lager_transform}]}.
上述都是使用的简单介绍,那么重点是在lager模块中找不到debug/2,debug/3,info/2等函数的实现。
实际上是erlang将编译源文件生成的Abstract code交由lager_transform模块的parse_transform函数再次进行处理,这个函数会将debug/2, debug/3这些函数直接转换为Abstract code。这也就是需要指定编译选项{parse_transform, lager_transform}的原因。
什么是Abstract code? 其格式是怎样的? 这里不多解释,直接翻看官方文档。
代码 lager:info("hello world"). 通过转换后的Abstract code为:
[{'case',34,
{tuple,34,
[{call,34,{atom,34,whereis},[{atom,34,lager_event}]},
{call,34,
{remote,34,{atom,34,lager_config},{atom,34,get}},
[{atom,34,loglevel},{tuple,34,[{integer,34,0},{nil,34}]}]}]},
[{clause,34,
[{tuple,34,[{atom,34,undefined},{var,34,'_'}]}],
[],
[{call,34,
{'fun',34,
{clauses,
[{clause,34,[],[],
[{tuple,34,
[{atom,34,error},{atom,34,lager_not_running}]}]}]}},
[]}]},
{clause,34,
[{tuple,34,
[{var,34,'__Pidtest34'},
{tuple,34,
[{var,34,'__Leveltest34'},{var,34,'__Tracestest34'}]}]}],
[[{op,34,'orelse',
{op,34,'/=',
{op,34,'band',{var,34,'__Leveltest34'},{integer,34,64}},
{integer,34,0}},
{op,34,'/=',{var,34,'__Tracestest34'},{nil,34}}}]],
[{call,34,
{remote,34,{atom,34,lager},{atom,34,do_log}},
[{atom,34,info},
{cons,34,
{tuple,34,[{atom,34,application},{atom,34,upu}]},
{cons,34,
{tuple,34,[{atom,34,module},{atom,34,test}]},
{cons,34,
{tuple,34,[{atom,34,function},{atom,34,start}]},
{cons,34,
{tuple,34,[{atom,34,line},{integer,34,34}]},
{cons,34,
{tuple,34,
[{atom,34,pid},
{call,34,
{atom,34,pid_to_list},
[{call,34,{atom,34,self},[]}]}]},
{cons,34,
{tuple,34,[{atom,34,node},{call,34,{atom,34,node},[]}]},
{call,34,{remote,34,{atom,34,lager},{atom,34,md}},[]}}}}}}},
{string,34,"hello world"},
{atom,34,none},
{integer,34,4096},
{integer,34,64},
{var,34,'__Leveltest34'},
{var,34,'__Tracestest34'},
{var,34,'__Pidtest34'}]}]},
{clause,34,[{var,34,'_'}],[],[{atom,34,ok}]}]}]}]}
翻译成erlang代码为:
case {whereis(lager_event), lager_config:get(loglevel, {0,[]})} of
{undefined, _} ->
fun() ->
{error, lager_not_running}
end();
{__Pidtest15, {__Leveltest15, __Tracestest15}}
when (__Leveltest15 band 64) /= 0 orelse
__Tracetest /= [] ->
lager:do_log(info, [{application, App},
{module, Module},
{function, Function},
{line, LINE},
{pid, pid_to_list(self())},
{node, node()} | lager:md()],
"hello world",
none, 4096, 64
__Leveltest15, __Tracestest15, __Pidtest15);
_ ->
ok
end.
注: 上述代码中 App, Module, Function, Line分别表示实际应用的名称,模块的名称,函数的名称,所在行数。