erlang 错误日志

错误日志

OTP系统已经内置了一个可定制的错误日志模块。我们可以从三种不同的视角来看错误日志。程序员的视角关注代码中要记录一个错误日志的函数调用?配置的视角关注错误日志如何存储以及保存在哪里?报告的视角则关心错误发生之后,如何进行分析。我们将逐条讲述这些内容。

记录一个错误日志

在程序员的视角,错误日志的API很简单,下面是这些API的一部分:

@spec error_logger:error_msg(String) -> ok

向错误日志发送一个错误消息

1> error_logger:error_msg("An error has occurred ").

=ERROR REPORT==== 28-Mar-2007::10:46:28 === An error has occurred

ok

@spec error_logger:error_msg(Format, Data) -> ok

向错误日志发送一个错误消息。它的参数与io:format(Format, Data)函数的参数一样。

2> error_logger:error_msg("~s, an error has occurred ", ["Joe"]).

=ERROR REPORT==== 28-Mar-2007::10:47:09 === Joe, an error has occurred

ok

@spec error_logger:error_report(Report) -> ok

向错误日志发送一个标准错误报告。

@type Report = [{Tag, Data} | term()] | string() | term()]

@type Tag = term()

@type Data = term()

3> error_logger:error_report([{tag1,data1},a_term,{tag2,data}]).

=ERROR REPORT==== 28-Mar-2007::10:51:51 ===

tag1: data1

a_term tag2: data

需要说明的是,这只是可用错误日志API中的一小部分。详细讨论这些API没啥意思。下面的例子中,我们也只会用到error_msg。完整的细节可以参考手册中error_logger的部分。

配置错误日志

可以对错误日志进行多种配置。在Erlangshell中我们可以看到所有的错误信息(如果我们什么都不配,这就是默认的配置)。我们可以把报告给shell中的错误写到一个格式化的文本文件中。此外,我们还能创建一个循环日志。你可以把循环日志想像成一个由错误日志产生的巨大环形缓存区域。新的消息进来时,会把它加到日志的尾部,如果日志被装满了,最早的条目就会被清除。

循环日志是一个极有用的特性。你可以决定总共有多少个日志文件,以及单个日志文件的大小。系统负责帮你删除旧文件以及创建新文件,以维持整个巨大的环形数据区域。你可以调整日志大小,以用来记录最近几天的操作,这在大多数情况下都是绰绰有余的了。

标准错误日志

启动Erlang的时候,我们可以给系统设置一些启动参数:

$ erl -boot start_clean

这会创建一个适合程序开发的环境。只会提供错误日志的简单形式(不带boot参数的erl启动命令其效果等同于erl –boot start_clean)。

$erl –boot start_sasl

这会创建一个适合产品化系统的环境。SASLSystem Architecture Support Libraries的缩写,它负责错误日志,过载保护等等。

谁也没法记住日志记录器的所有配置(也没这个必要),所以,最好还是把错误日志文件的配置信息记到一个配置文件中。 下面的小节,我们会考察默认配置下系统中的错误日志是如何工作的。然后会了解四种典型的配置方式下,错误日志不同的工作方式。

不进行配置的SASL

这是在SASL下启动,不进行配置的情况:

$ erl -boot start_sasl

Erlang (BEAM) emulator version 5.5.3 [async-threads:0] ...

=PROGRESS REPORT==== 27-Mar-2007::11:49:12 ===

supervisor: {local,sasl_safe_sup}

started: [{pid,<0.32.0>},

{name,alarm_handler},

{mfa,{alarm_handler,start_link,[]}},

{restart_type,permanent},

{shutdown,2000},

{child_type,worker}]

... many lines removed ...

Eshell V5.5.3 (abort with ^G)

现在我们调用error_logger的方法来报告错误:

1> error_logger:error_msg("This is an error ").

=ERROR REPORT==== 27-Mar-2007::11:53:08 === This is an error

ok

注意,错误是在Erlangshell中报告出来的。错误报告取决于错误日志记录器的配置。

控制记录何种日志

错误日志记录器会产生几种类型的报告:

Supervisor报告

Supervisor启动或者停止被监管的进程时,会产生这个报告(我们在18.5节监管树“第345页”中会讨论它)。

Progress报告

每次OTP监管进程启动或者停止的时候会产生这个报告。

Crash报告

当被监管的进程退出时,如果它的退出原因不是normal或者shutdown,就会产生这个报告。

这三种报告是自动产生的,程序员无需关心。除此之外,当程序显式调用error_handler的方法时,也会产生三种日志报告。通过这三种报告,程序可以记录错误,警报以及提示信息。在这里,这三个术语并没有什么特别的语意,仅仅是程序员可以使用的三种标签,用来标明错误日志条目的自然属性(也就是说,想怎么用,随你)。

在日后对错误日志进行分析的时候,我们可以用这三种标签协助我们来检查问题,过滤日志条目。在对日志进行配置的时候,我们也可以指定,比如,只保存错误,其他的信息不予保存。下面我们就来写一个这样的配置文件。

elog1.config

%% no tty

[{sasl, [

{sasl_error_logger, false}

]}].

如果用这个配置文件启动系统,只有错误报告会被记录,progress报告之类的全部被忽略掉。而且,所有的错误都报告在shell当中。

$ erl -boot start_sasl -config elog1

1> error_logger:error_msg("This is an error ").

=ERROR REPORT==== 27-Mar-2007::11:53:08 === This is an error

Ok

文本文件和shell

无配置方法:

erl -boot start_sasl -sasl sasl_error_logger {file,"path/to/logfile.log"} 

%%有些{}不需转义.

下一个配置文件,错误信息会同时出现在shell和一个文本文件之中:

elog2.config

%% single text file - minimal tty

[{sasl, [

%% All reports go to this file

{sasl_error_logger, {file, "/home/joe/error_logs/THELOG" }}

]}].

我们启动Erlang,生成一些错误信息,然后看看日志文件,以检查这个配置文件的效果。

$ erl -boot start_sasl -config elog2

1> error_logger:error_msg("This is an error ").

=ERROR REPORT==== 27-Mar-2007::11:53:08 === This is an error ok

我们可以查看/home/joe/error_logs/THELOG文件的内容,应该是这样的:

=PROGRESS REPORT==== 28-Mar-2007::11:30:55 ===

supervisor: {local,sasl_safe_sup}

started: [{pid,<0.34.0>},

{name,alarm_handler},

{mfa,{alarm_handler,start_link,[]}},

{restart_type,permanent},

{shutdown,2000},

{child_type,worker}]

...

循环日志和Shell

这个配置下,日志会在Shell以及一个循环日志中同时输出。这是一个很有用的配置。

elog3.config

%% rotating log and minimal tty

[{sasl, [

{sasl_error_logger, false},

%% define the parameters of the rotating log

%% the log file directory

{error_logger_mf_dir,"/home/joe/error_logs" },

%% # bytes per logfile

{error_logger_mf_maxbytes,10485760}, % 10 MB

%% maximum number of logfiles

{error_logger_mf_maxfiles, 10}

]}].

$erl -boot start_sasl -config elog3

1> error_logger:error_msg("This is an error ").

=ERROR REPORT==== 28-Mar-2007::11:36:19 === This is an error

False

当用这个配置运行系统的时候,所有的错误也会输出到这个循环日志中。本章后面的章节,我们会看到从日志中提取错误信息的方法。

产品化环境

在产品化环境中,我们只关注错误,而对progressinformation日志不感兴趣。所有我们在配置中让日志记录器仅仅记录错误。以免这些信息淹没在大量的progressinformation日志中。

elog4.config

%% rotating log and errors

[{sasl, [

%% minimise shell error logging

{sasl_error_logger, false},

%% only report errors

{errlog_type, error},

%% define the parameters of the rotating log

%% the log file directory

{error_logger_mf_dir,"/home/joe/error_logs" },

%% # bytes per logfile

{error_logger_mf_maxbytes,10485760}, % 10 MB

%% maximum number of

{error_logger_mf_maxfiles, 10}

]}].

运行的时候,这个配置与前一个配置的效果看起来很相似,唯一的区别在于,只有错误会被记录到日志中。

分析错误日志

读取错误日志是rb模块的职责。它的接口相当简单。

1> rb:help().

Report Browser Tool - usage

===========================

rb:start()  - start the rb_server with default options rb:start(Options) - where Options is a list of:

{start_log, FileName}

- default: standard_io

{max, MaxNoOfReports}

- MaxNoOfReports should be an integer or 'all'

- default: all

...

... 此处省略很多行 ...

...

我们启动report browser的时候可以指定它需要读取多少行(这个例子中,是最后的20行)

2> rb:start([{max,20}]).

rb: reading report...done.

3> rb:list().

No   Type       Process Date  Time

==   ====      ======= ====     ====

11    progress <0.29.0> 2007-03-28 11:34:31

10    progress <0.29.0> 2007-03-28 11:34:31

9     progress <0.29.0> 2007-03-28 11:34:31

8     progress <0.29.0> 2007-03-28 11:34:31

7     progress <0.22.0> 2007-03-28 11:34:31

6     progress <0.29.0> 2007-03-28 11:35:53

5     progress <0.29.0> 2007-03-28 11:35:53

4     progress <0.29.0> 2007-03-28 11:35:53

3     progress <0.29.0> 2007-03-28 11:35:53

2     progress <0.22.0> 2007-03-28 11:35:53

1     error       <0.23.0> 2007-03-28 11:36:19

ok

> rb:show(1).

ERROR REPORT <0.40.0>   2007-03-28 11:36:19

===========================================================

This is an error ok

要隔离一个特定的错误,我们可以使用rb:grep(RegExp)命令。它会找出所有匹配这个正则表达式的记录。我这里就不深入分析错误日志的细节问题了,学习它的最好方法是花一点时间,自己来和rb进行一些交互,看看都能做点什么。注意,你根本不需要自己来删日志,循环机制会删除旧的日志。

如果你想要保留所有的日志,那么你就需要每隔一段特定的时间过来抓取,并自己进行清理。

原文地址:https://www.cnblogs.com/xiao0913/p/3597121.html