通用的事件处理
基础程序
代码演示:
-module(event_handler).
-export([make/1,add_handler/2,event/2]).
make(Name) ->
register(Name, spawn(fun() ->my_handler(fun no_op/1) end)).
add_handler(Name, Fun) ->Name ! {add, Fun}.
event(Name, X) ->Name ! {event, X}.
no_op(_) ->void.
my_handler(Fun) ->
receive
{add, Fun1} ->
my_handler(Fun1);
{event, Any} ->
(catch Fun(Any)),
my_handler(Fun)
end.
作为最简单的事件处理程序,不对事情进行任何处理,而是直接丢掉。事件处理程序未安装回调模块。
执行结果:
1> c(event_handler).
{ok,event_handler}
2> event_handler:make(errors).
true
3> event_handler:event(errors, hi).
{event,hi}
加回调模块
代码演示:
-module(motor_controller).
-export([add_event_handler/0]).
add_event_handler() ->
event_handler:add_handler(errors, fun controller/1).
%具体处理操作
controller(too_hot) ->
io:format("Turn off the motor~n");
controller(X) ->
io:format("~w ignored event: ~p~n",[?MODULE, X]).
执行结果:
4> c(motor_controller).
{ok,motor_controller}
5> motor_controller:add_event_handler().
{add,#Fun<motor_controller.0.125151531>}
6> event_handler:event(errors, cool).
motor_controller ignored event: cool
{event,cool}
7> event_handler:event(errors, too_hot).
Turn off the motor
{event,too_hot}
可以看出,在Erlang中处理事件,允许解耦掉事件的产生和事件的处理两个过程。两者完全分离,可以在任何需要的时候改变事件的处理,没有什么东西是静态连接的,随时可以换用别的事件处理。所以系统演化的过程不需停机,也不需升级代码。
错误日志
OTP系统已经内置了一个可自定义的错误日志模块。
记录一个错误
API对应方法:
1.error_logger:error_msg(String) -> ok
向错误日志发送一个错误消息
执行结果:
8> error_logger:error_msg("An error has occurred\n").
=ERROR REPORT==== 19-Sep-2023::23:08:36.313000 ===
An error has occurred
ok
2.error_logger:error_msg(Format, Data) -> ok
也是同样向错误日志发送一个错误消息,它的参数与io:format(Format,Data)函数的参数一样,用的比较多
执行结果:
9> error_logger:error_msg("~s, An error has occurred\n", ["Joe"]).
=ERROR REPORT==== 19-Sep-2023::23:13:19.095000 ===
Joe, An error has occurred
ok
3.error_logger:error_report(Report) -> ok
向错误日志发送一个标准错误报告
执行结果:
10> error_logger:error_report([{tag1, data1}, a_term, {tag2, data}]).
=ERROR REPORT==== 19-Sep-2023::23:21:29.430000 ===
tag1: data1
a_term
tag2: data
ok
配置错误日志
对错误日志可以进行自定义配置,可以把在shell中报告的所有错误写到一个格式化的文本文件中。除此之外,还能创建一个循环日志,循环日志是一个由错误日志产生的巨大环形缓存区域。新的消息进来时,会加到日志的尾部,如果日志被装满了,最早的条目会被清除。
循环日志决定了总共有多少个日志文件以及单个日志文件的大小,系统负责帮我们删除旧文件以及创建新文件来维持整个巨大的环形数据区域,可以通过调整日志的大小来记录最近几天的操作。
1.标准错误日志
erl -boot start_clean
创建一个适合程序开发的环境,只会提供错误日志的简单形式。
erl -boot start_sasl
会创建一个适合产品化系统的环境。SASL负责错误日志,过载保护等。
2.不进行配置的SASL
在启动SASL时不进行配置:
erl -boot start_sasl
PS D:\Erlang6m\first\src> erl -boot start_sasl
Eshell V10.7 (abort with ^G)
1> error_logger:error_msg("This is an error\n").
=ERROR REPORT==== 20-Sep-2023::22:02:25.891000 ===
This is an error
ok
错误是在Erlang shell中报告出来的,错误报告取决于错误日志记录器的配置。
3.控制记录何种日志
错误日志记录器会产生三种不同类型的报告:
1)监管报告, 在监管进程启动或者停止被监管的进程时产生;
2)进程报告, 每次OTP监管进程启动或者停止的时候产生;
3)崩溃报告, 当被监管的进程退出时, 如果退出原因不是normal或者shutdown则产生此报告。
三种报告自动产生,除此之外,程序显示,调用error_handler的方法时也会产生三种日志报告,通过这三种报告程序可以记录错误、警报以及提示信息。这三个用语并没有特殊的语义,程序员可以任意使用这三种标签,标明错误日志条目的自然属性。
进行错误日志分析时,也可以用这三种标签协助我们检查问题,过滤日志条目。
比如说只保存错误,其他的信息不进行存储:
elog1.config文件内:
[{sasl, [{sasl_error_logger, false}]}].
执行结果
1> error_logger:error_msg("This is an error\n").
ok
=ERROR REPORT==== 20-Sep-2023::22:36:55.179000 ===
This is an error