OTP系统自带一个可定制的错误记录器。可以从三个角度看待错误记录器:程序员视角关心程序员为了记录错误而在代码里中做的函数调用;配置视角关心错误记录器在何处以及如何保存数据;报告视角关心对已发生错误的分析。
记录错误
以下是错误记录器(error_logger)的API子集:
发送一个错误消息。
-spec error_logger:error_msg(String) -> ok
%% 向错误记录器发送一个错误消息。它的参数和io:format(Format, Data)相同。
-spec error_logger:error_msg(Format,Data) -> ok
%% 向错误记录器发送一个标准错误报告。
-spec error_logger:error_report(Report) -> ok
-type Report = [{Tag, Data} | term() | string()].
-type Tag = term().
-type Data = term().
配置错误记录器
有多种方式可用来配置错误记录器。可以让Erlang shell显示所有错误(如果没有特别设置的话就是默认值),也可以把shell里报告的所有错误写入一个格式化文本文件。最后,还可以创建一个滚动日志(rotating log)。可以把滚动日志看作是一个大型循环缓冲区,内含错误记录器生成的消息。新消息进来后会被附加到日志的末尾,如果日志满了,最早的条目就会被删除。
标准错误记录器
在启动Erlang时可以给系统提供一个启动参数。
$ erl -boot start_clean
它会创建一个适合进行程序开发的环境,只提供一种简单的错误记录形式。(不带启动参数的erl命令就等于erl -boot start_clean。)
$ erl -boot start_sasl
它会创建一个适合运行生产系统的环境。系统架构支持(System Architecture Support Libraries,简称SASL)将负责错误记录和过载保护等工作。
无配置SASL
以下是不带配置文件启动SASL时会发生的情况:
现在调用error_logger里的某个方法来报告一个错误:
而这时的错误是在在Erlang shell里报告的。错误的报告位置由错误记录器配置决定。
控制记录内容
错误记录器会生成多种报告类型。
监控器报告:这些报告会在OTP监控器启动或停止被监控进程时生成。
进度报告:这些报告会在OTP监控器启动或停止时生成。
崩溃报告:如果某个被OTP行为启动的进程因为normal或shutdown以外的原因终止,这些报告就会生成。
这三种报告会自动生成,程序员无须做任何事。另外,还可以显式调用error_logger模块里的方法来生成三种类型的日志报告。
后面分析错误日志时,可以用这些标签来决定该调查哪些日志条目。在配置错误记录器时可以选择只保存错误,丢弃其他所有类型的条目。现在,编写配置文件elog1.config来配置错误记录器。
%% 无tty
[ {sasl, [
{sasl_error_logger, false}
]}].
文本文件和shell
接下来的配置文件会在shell里列出错误报告,所有的进度报告则会保存在一个文件里。
%% 单文本文件,最小化tty
[ {sasl, [
{sasl_error_logger, {file, "/Users/joe/error_logs/THELOG"}}
]}].
以启动Erlang,生成一个错误消息,然后查看日志文件。
这里只列出了进度报告,而它们原本应该出现在shell里。进度报告是关于大事件的,比如启动和停止应用程序。但是error_logger:error_msg/1报告的错误没有保存在日志里,为此必须配置一个滚动日志。
滚动日志和shell
下面的配置既能提供shell输出,又能把写入shell的所有信息复制到一个滚动日志文件里。
%% 滚动日志和最小化tty
[ {sasl, [
{sasl_error_logger, false},
%% 定义滚动日志的参数
%% 日志文件目录
{error_logger_mf_dir, "/User/joe/error_logs"},
%% # 每个日志文件的字节数
{error_logger_mf_maxbytes, 10485760}, % 10 MB
%% 日志文件的最大数量
{error_logger_mf_maxfiles, 10}
]}].
这个日志的最大文件大小是10MB,达到10MB时会回绕或者“滚动”。可想而知,这是一个非常有用的配置。 运行系统时,所有的错误都会写入一个滚动错误日志。
生产环境
在生产环境里,只有错误才是需要的,而非进度或信息报告,所以只让错误记录器报告错误。如果没有这个设置,系统也许就会被信息和进度报告所淹没。