使用Lager库来管理erlang应用的日志模块
erlang本身已经提供了基础的日志模块error_logger还有OTP 21.0之后的Logger模块,这些模块在项目比较轻量,日志可控,功能简单的情况下完全可以满足需要,但是Lager提供了一个更加成熟的完整的解决方案,从日志文件的配置,等级设定,到跟踪,日志文件轮转提供了完整的生态接口,通过Lager几乎可以满足所有的日志需求,而且不需要考虑erlang版本变更带来的问题。
基础使用
Lager的ReadMe已经描述了最基础的使用范例,简单来说需要以下几步:
- 需要在编译选项中加入{parse_transform, lager_transform},因为Lager是通过parse_transform来完成了lager:info这种函数的具体实现,不像传统的日志模块,直接调用,所有的module都必须在该编译选项下才能调用lager
对于使用rebar的项目,只需要在rebar.config中修改或者增加erl_opts项,加入{parse_transform, lager_transform}即可,MakeFile同理
如果只给单个文件提供日志功能,可以在erl中加入编译选项声明-compile([{parse_transform, lager_transform}]).
不要在自己项目的基础模块中将lager调用包装成函数,然后其他模块再调用函数,这样会影响后续lager的功能,只能通过宏来完成,宏到时候会进行代码替换,确保lager功能都是直接原生调用
- 编写测试代码,加入lager调用,创建lage_test.erl 把下列代码写入到文件中,使用带编译项的第一步配置进行编译
-module(lager_test).
%% API
-export([test/0]).
test() ->
application:ensure_all_started(lager),
lager:error("error msg"),
lager:warning("warning msg"),
lager:debug("debug msg"),
lager:info("info msg"),
lager:critical("critical msg"),
erlang:spawn_link(fun() -> erlang:throw("this is test") end).
- 启动命令行,执行lager_test:test(). 命令行启动的时候通过-pa把lager加入到代码加载路径
执行后在当前目录的log目录下会生成error.log
和console.log
,因为lager的默认日志handle配置就是
-define(DEFAULT_HANDLER_CONF,
[{lager_console_backend, [{level, info}]},
{lager_file_backend,
[{file, "log/error.log"}, {level, error},
{size, 10485760}, {date, "$D0"}, {count, 5}]
},
{lager_file_backend,
[{file, "log/console.log"}, {level, info},
{size, 10485760}, {date, "$D0"}, {count, 5}]
}
]).
lager提供的日志等级定义在
-define(LEVELS,
[debug, info, notice, warning, error, critical, alert, emergency, none]).
列表中的值都可以使用,lager:LEVEL进行调用
配置
Lager配置主要通过配置Lager的application环境变量来实现,也就是他的一部分基础配置来自于lager.app,也就是lager.app.src中
{env, [
%% Note: application:start(lager) overwrites previously defined environment variables
%% thus declaration of default handlers is done at lager_app.erl
%% What colors to use with what log levels
{colored, false},
{colors, [
{debug, "\e[0;38m" },
{info, "\e[1;37m" },
{notice, "\e[1;36m" },
{warning, "\e[1;33m" },
{error, "\e[1;31m" },
{critical, "\e[1;35m" },
{alert, "\e[1;44m" },
{emergency, "\e[1;41m" }
]},
%% Whether to write a crash log, and where. False means no crash logger.
{crash_log, "log/crash.log"},
%% Maximum size in bytes of events in the crash log - defaults to 65536
{crash_log_msg_size, 65536},
%% Maximum size of the crash log in bytes, before its rotated, set
%% to 0 to disable rotation - default is 0
{crash_log_size, 10485760},
%% What time to rotate the crash log - default is no time
%% rotation. See the README for a description of this format.
{crash_log_date, "$D0"},
%% Number of rotated crash logs to keep, 0 means keep only the
%% current one - default is 0
{crash_log_count, 5},
%% Crash Log Rotator Module - default is lager_rotator_default
{crash_log_rotator, lager_rotator_default},
%% Whether to redirect error_logger messages into the default lager_event sink - defaults to true
{error_logger_redirect, true},
%% How many messages per second to allow from error_logger before we start dropping them
{error_logger_hwm, 50},
%% How big the gen_event mailbox can get before it is
%% switched into sync mode. This value only applies to
%% the default sink; extra sinks can supply their own.
{async_threshold, 20},
%% Switch back to async mode, when gen_event mailbox size
%% decrease from `async_threshold' to async_threshold -
%% async_threshold_window. This value only applies to the
%% default sink; extra sinks can supply their own.
{async_threshold_window, 5}
]},
这部分的内容都是可以通过beam启动的时候通过设置配置文件来覆盖,类似于 erl -config app.config,而app.config中内容也就是对lager的env进行扩展,一份简单的内容如下:
{lager, [
{log_root, "/var/log/hello"},
{handlers, [
{lager_console_backend, [{level, info}]},
{lager_file_backend, [{file, "error.log"}, {level, error}]},
{lager_file_backend, [{file, "console.log"}, {level, info}]}
]}
]}.
通过log_root
指定了日志文件所在的目录,如果是相对路径就是相对的Lager启动的时候pwd()函数返回的路径
handles
就是日志处理模块指定,也是配置的核心内容,上述配置中启用了1个lager_console_backend接收器用来将日志输出到命令行中,两个将日志输出到文件中的lager_file_backend分别将error级别以上的日志和info级别以上的日志分别写入到"error.log"和"console.log"中
日志扩展
上一步中讲到的日志都是基于内建的lager_event事件来进行的配置,因为类似lager:info这种调用最终调用的就是lager:d