haogongju、人人IT网、59n南龙、360doc不要抄我的烂博客了,私人备忘用。
erlang本身提供了日志管理,但这与其它语言中常见的log4xxx的日志框架很不同:
日志文件是二进制的,查看起来很不方便;
每条日志跨多行文本,也不方便查找和分析。
总之,这自带的日志系统让用惯log4xxx系列的人用起来很不习惯。后来陆续有log4erl这样的应用,lager算是后来者,不过在性能等方面有独到之处,这是因为它使用parse_transformation机制的原因。
一、lager使用的步骤
直接在代码中用lager:debug, lager:info, lager:warning, lager:error系列函数输出日志就行了。这些函数的参数和io:format基本一样,除了一点,日志字符串结尾不用自己手动加回车。
麻烦的是其它工作,包括编译方式、参数配置,lager应用的启动,不过好在都是一次性的:
1. 编译选项 parse_transformation
最笨的办法是在每个模块的开头使用编译指令
-compile([{parse_transform, lager_transform}]).
所有要使用lager的模块都加上这个指令代码无疑是很烦的事情,好在erlang编译器提供了一个选项,
见compile。
当然如果用rebar的话更加简单,只要在rebar.config配置文件中添加:
{erl_opts, [
{parse_transform, lager_transform}]}.
这样的编译就会自动织入lager代码,不需要给每个模块添加编译指令了。
2. lager应用的启动
这包括它依赖的两个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,
lager,
rts
]},
3. lager的配置
可以在发布的app.config(后来rebar改名成sys.config)中配置。配置参数很多,日志输出级别,日志输出方式,如果是以文件的方式,又包括日志文件名,日志文件大小,循环日志文件等等。列出这些配置参数很枯燥,还是直接看手册。
二、其它技巧
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
三、常见问题和陷阱
lager:info/debug/warning/error函数未定义错误
当运行时出现有如下片断的错误:
... {'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的前面。
分享到:
相关推荐
本程序为卡尔曼滤波的一个简单小程序,使用者可直接使用。
本程序使用STRUTS2.0+SPRING2.5+HIBERNATE3.2框架编写的网站后台管理系统(无前台)
监视 CPU 使用情况的例子 双击终止程序 CPU Program - by Tim Warthen (tlwarth@mkg.com) Please direct your questions, comments to Tim Warthen tlwarth@mkg.com P.O. Box 517 Cadet, MO 63630 To...
背景flink 集群模式 flink on yarn使用flink 读取kafka 数据 简单处理之后使用自定义richWindowFunction 处理数据的
OpenSSL被曝出现严重安全漏洞后,发现多数通过SSL协议加密的网站使用名为OpenSSL的开源软件包。OpenSSL漏洞不仅影响以https开头的网站,黑客还可利用此漏洞直接对个人电脑发起"心脏出血"(Heartbleed)攻击。据分析,...
为您提供bigjpg 图片无损放大软件下载,bigjpg是一款优秀的AI人工智能图片放大...注意事项 图片大小不得超过10mb,可处理图片的最大尺寸,3000*3000px一个月只能处理20张,请节约使用 处理时间 开始放大后需要处理
myeclise10 svn: E210004: Number is larger than maximum 解决方案 专门解决win7 64位操作系统 下svn插件问题。 下载文件包括: site-1.8.22.zip --->svn离线安装包 Slik-Subversion-1.8.9-x64 --->问题修复必选...
Nodemailer 是一个简单易用的 Node.JS 邮件发送模块(通过 SMTP,sendmail,或者 Amazon SES),支持 unicode,你可以使用任何你喜欢的字符集。 Unicode to use any characters ...
This project functions under the Apache Software Foundation (http://www.apache.org), and is part of a larger community of developers and users. 百科简介 HTTP 协议可能是现在 Internet 上使用得最多、最...
This project functions under the Apache Software Foundation (http://www.apache.org), and is part of a larger community of developers and users. 百科简介 HTTP 协议可能是现在 Internet 上使用得最多、最...
This project functions under the Apache Software Foundation (http://www.apache.org), and is part of a larger community of developers and users. 百科简介 HTTP 协议可能是现在 Internet 上使用得最多、最...
This project functions under the Apache Software Foundation (http://www.apache.org), and is part of a larger community of developers and users. 百科简介 HTTP 协议可能是现在 Internet 上使用得最多、最...
解决了原版无法兼容新版chrome的问题("Cross-origin plugin content from must have a visible size larger than 400 x 300 pixels, or it will be blocked. Invisible content is always blocked.")。解决了原版...
资源是zip格式,同时方便Windows和Mac电脑使用。 资源列表如下: 1)中文 EXCEL 资源 如下: 1. 一页纸项目管理中文模板 2. 自动化分配中心 2)英文 EXCEL 资源 如下: 1. BasicTemplate 2. 12steps 3...
'alexandernst\Scrypt\Scrypt'],] 要派生密钥,请使用以下方法: /*** Scrypt algorithm** @param string $password* @param string $salt* @param int $n CPU/Memory cost parameter, must be larger than 1, a ...
较少使用安装.. 需要较少 v2.4.0 npm install -g less-plugin-skeleton然后在命令行上, lessc file.less --skeleton媒体查询注意:构建媒体查询使用的最佳方法是在相关代码附近创建查询。 例如,如果您想更改小型...
This project functions under the Apache Software Foundation (http://www.apache.org), and is part of a larger community of developers and users. 百科简介 HTTP 协议可能是现在 Internet 上使用得最多、最...
第1题 编写一个脚本,该脚本要求用户输入两个整数,从用户那里获得这两个整数后,在一个警告框中显示较大的整数并在后面加上”is larger”。如果这两个整数相等,则在警告框中显示“These numbers are equal”。 第2...
Starting in 3.4, the WiredTiger internal cache, by default, will use the larger of either: 50% of RAM minus 1 GB, or 256 MB. 即 (总内存 × 50% - 1GB) 和 (256MB) 两者中的较大值。 由于mongodb会占用...
// compress anything larger than 64k mcc.setCompressEnable(true); mcc.setCompressThreshold(64 * 1024); } /**�������*/ public static void inputData(String key, Object Data){ input...