lager的使用

haogongju、人人IT网、59n南龙、360doc不要抄我的烂博客了,私人备忘用。


erlang本身提供了日志管理,但这与其它语言中常见的log4xxx的日志框架很不同:
日志文件是二进制的,查看起来很不方便;
每条日志跨多行文本,也不方便查找和分析。

总之,这自带的日志系统让用惯log4xxx系列的人用起来很不习惯。后来陆续有log4erl这样的应用,lager算是后来者,不过在性能等方面有独到之处,这是因为它使用parse_transformation机制的原因。


[size=large]一、lager使用的步骤[/size]

直接在代码中用lager:debug, lager:info, lager:warning, lager:error系列函数输出日志就行了。这些函数的参数和io:format基本一样,除了一点,日志字符串结尾不用自己手动加回车。

麻烦的是其它工作,包括编译方式、参数配置,lager应用的启动,不过好在都是一次性的:

[size=medium]1. 编译选项 parse_transformation[/size]

最笨的办法是在每个模块的开头使用编译指令
-compile([{parse_transform, lager_transform}]).

所有要使用lager的模块都加上这个指令代码无疑是很烦的事情,好在erlang编译器提供了一个选项,[url=http://www.erlang.org/doc/man/compile.html]见compile[/url]。

当然如果用rebar的话更加简单,只要在rebar.config配置文件中添加:
{erl_opts, [[color=green]{parse_transform, lager_transform}[/color]]}.

这样的编译就会自动织入lager代码,不需要给每个模块添加编译指令了。

[size=medium]2. lager应用的启动[/size]

这包括它依赖的两个erlang的lib应用:syntax_tools和compiler,一般用发布工具发布时会自动包含进来。但是开发中我们一般比较少直接使用发布工具,所以erl启动时lager不会也随之自动启动,lager本身作为应用要预先启动,有很多办法:

1) 最直观的,我们当然可以用 application:start(lager) 手工启动lager应用。但是lager还依赖compiler和syntax_tools,这两个应用要先启动,lager才能正常启动。虽然在lager应用的lager.app文件有在applications属性中指出这些依赖,但是这似乎只对发布有效,application:start/1不会坚持这些依赖并启动这些依赖。

2) 这里的问题是application:start/1函数只负责启动指定的application,如果它依赖的其它applications没有启动,则启动过程失败,该函数返回值:{error, {not_started, DepApp}}。
如果erlang能提供一个启动应用及其依赖的方法就好了。
后来,lager模块为此提供了一个专门的start方法,负责启动它自己依赖的这两个应用:
lager:start().

下面是它的源代码,有时候我们自己写应用直接的互相依赖可以借鉴一下:
-export([start/0]).

start() -> start(lager).

start(App) ->
start_ok(App, application:start(App, permanent)).

start_ok(_App, ok) -> ok;
start_ok(_App, {error, {already_started, _App}}) -> ok;
start_ok(App, {error, {not_started, Dep}}) ->
ok = start(Dep),
start(App);
start_ok(App, {error, Reason}) ->
erlang:error({app_start_failed, App, Reason}).


3) 如果是用工具发布的应用系统,例如rebar发布配置文件(reltool.config)中,在'rel' 列出的应用里增加lager,这样,发布后lager会自动在系统初始化时启动,如下
{sys, [
{lib_dirs, ["../../", "../deps/"]},
{rel, "rts", "1",
[
kernel,
stdlib,
sasl,
[color=blue]lager[/color],
rts
]},


[size=medium]3. lager的配置[/size]

可以在发布的app.config(后来rebar改名成sys.config)中配置。配置参数很多,日志输出级别,日志输出方式,如果是以文件的方式,又包括日志文件名,日志文件大小,循环日志文件等等。列出这些配置参数很枯燥,还是直接看手册。


[size=large]二、其它技巧[/size]
1.日志的颜色区分
当然你也可以用unix管道grep出你关心的日志,不过如果是需要参照出错附近的日志时。有时候直接在控制台上看日志更糙猛快点。
这种情况下如果能在一大堆日志中用不同颜色标出不同等级的日志信息无疑是很节省眼力的。

lager提供了这种支持,但不幸的是erlang是从R16版开始才官方支持,R15B版本erlang控制台并不直接支持ANSI ASCII字符。这需要修改erlang源代码重新编译,不过还好这不是什么难事:
修改erts/emulator/drivers/unix/ttsl_drv.c源代码(R15B03版)第915行开始的几行代码。
将如下代码
	} else if (ch == '\n' || ch == '\r') {
write_buf(lbuf + buffpos, lpos - buffpos);
outc('\r');
if (ch == '\n')
outc('\n');
改成:

	} else if (ch == '\e' || ch == '\n' || ch == '\r') {
write_buf(lbuf + buffpos, lpos - buffpos);
if (ch == '\e') {
outc('\e');
} else {
outc('\r');
if (ch == '\n')
outc('\n');
}

重新编译的Erlang/OTP R15B就能支持彩色ASCII的控制台了。

最后修改lager的配置(lager.app.src),colored设为true。现在可以在erlang控制台上看到各种颜色的日志信息了,debug没有变化,info是亮白色,warning是黄色,error是红色,等等
这些颜色当然也是可以自定义的,来自用term上bbs时代,或者了解ASCII字符艺术的同学对此应该并不陌生。

参考:Support ANSI in the console
http://erlang.org/pipermail/erlang-patches/2012-November/003127.html

[size=large]三、常见问题和陷阱[/size]

[size=medium]lager:info/debug/warning/error函数未定义错误[/size]

当运行时出现有如下片断的错误:
... {'EXIT',{undef,[{lager,info, ...
(其中的info可以是 debug, warning等)

这是因为编译时的parse_transform没有“正确”设置的缘故,原因很多,以下是可能碰到的两个陷阱:

1. 只是修改配置信息(如修改rebar.config文件,加入{erl_opts, [{parse_transform, lager_transform}]} ),然后rebar compile是不会自动重新编译之前已有的编译好的代码的,必须清空已编译好的代码重新编译才行:rebar clean compile
原因其实也简单:rebar compile只会根据源代码的时间戳判断是否有必要重新编译,而编译配置选项的修改显然与之无关。

2. 对于rebar.config里的erl_opts配置,顺序很重要,{parse_transform, lager_transform} 必须在其他erl_opts的前面。
用不惯sasl的,可以用log4xxx的erlang版,log4erl。 log4erl Manual: =============== TOC: ==== 1. Features 2. Installation 3. Usage 4. API 5. Configuration 6. Known issues 7. Future development 8. License 1. FEATURES: ============ - Multiple logs - Currently, only size-based log rotation of files for file appender - Support default logger if no logger specified - 5 predifined log levels (debug, info, warn, error, fatal) - A log handler for error_logger - Support for user-specified log levels - Support for a log formatter (similar to Layouts in Log4J) - Support for console log - Support for smtp formatter - Support for XML logs - Support for syslog - Support for changing format and level of appender during run-time 2. INSTALLATION: ================ To compile & install log4erl, download source from google code's website (http://code.google.com/p/log4erl/) or from svn: $> svn checkout http://log4erl.googlecode.com/svn/trunk/ log4erl or from github public repository (http://github.com/ahmednawras/log4erl/). $> cd log4erl $> make or you can run the below from erlang shell: $> cd src $> erl 1> make:all([{outdir, "../ebin"}]). 3. USAGE: ========= 1- In order to use log4erl, you need to first include it in the path. There are 2 ways to do this: a) include the "log4erl" directory in erlang's "lib" directory in the target machine (cp -Rf log4erl /where/erlang/is/lib). $> cp -Rf log4erl /usr/local/lib/erlang/lib/ b) include the "log4erl" ebin directory in the path when running you program $> erl -pz /path/to/log4erl ... 2- Once the log4erl directory is included, you can use its API as described in section "API". but before, you need to run: > application:start(log4erl). 3- Create a configuration file and load it using log4erl:conf(File) > log4erl:conf("priv/log4erl.conf"). 4- Alternatevly, you can create loggers & add appenders to them programmatically as appropriate. You can do this as per the API below. > log4erl:add_logger(messages_log). > log4erl:add_console_appender(messages_log, cmd_logs, {warn, "[%L] %l%n"}). where Conf is the erlang term describing how the log is to be handled You can also add more types of appenders, which is explained in API.txt and Appneders_API.txt. 5- Now, you can log whatever messages you like as per logging functions described in API. > log4erl:info("Information message"). Precedance of log levels are: all = debug < info < warn < error < fatal < none User defined levels are always written except when none level is specified in the logger specification (See below). 4. API: ======= Please look at API.txt file for more information about the API. 5. CONFIGURATION: ================= Please look at CONFIGURATION.txt for more information about how to configure log4erl. 6. KNOWN ISSUES: ================ - Name of both loggers & appenders should be unique and not registered since log4erl will try and register their names. If the name is already registered, nothing will happen. This will be fixed soon. - If you run change_log_format/1,2 and appender crashed, a restart from the supervisor will not record the latest format used. It will only use either the default format or the format used in the argument is supplied. 7. FUTURE DEVELOPMENT: ====================== - Add support for different log persistance methods (e.g files, XML, console, DB, SNMP, syslog...etc) - Add support for time-based log rotation - Multiple configuration format (Erlang terms, XML?, properties files?) - Add support for NDC & MDC ??? Please send your suggestion to ahmed.nawras <at @ at> gmail <dot . dot> com 8. LICENSE: =========== This software is subject to "Mozilla Public License 1.1". You can find the license terms in the file 'LICENSE.txt' shipping along with the source code. You may also get a copy of the license term from the URL: "http://www.mozilla.org/MPL/MPL-1.1.html".
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值