- 警报器管理
我们编写的应用程序只需要一个警报,这个警报会在CPU因为计算超大质数而开始熔化时抛出(别忘了我们正在建设一家销售质数的公司)。这次将使用真正的OTP警报处理器(而不是在本章开头看到的简单版)。这个警报处理器是OTPgen_event行为的回调模块,它的代码如下。
%%%-------------------------------------------------------------------
%%% @author ZhengNan
%%% @copyright (C) 2024, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 13. 9月 2024 23:22
%%%-------------------------------------------------------------------
-module(my_alarm_handler).
-author("ZhengNan").
%%%=======================EXPORT=======================
-export([init/1, handler_event/2, handler_call/2, handler_info/2, terminate/2, code_change/3]).
%%%=======================INCLUDE======================
%%%=======================RECORD=======================
%%%=======================DEFINE=======================
%%%=======================TYPE=========================
%%%=================EXPORTED FUNCTIONS=================
%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------
init(Args) ->
io:format("init my_alarm_handler by:~p~n ", [Args]),
{ok, 0}.
handler_event({set_alarm, too_hot}, N) ->
error_logger:error_msg("Tell the engineer to turn on the aircondition~n"),
{ok, N + 1};
handler_event({clear_alarm, too_hot}, N) ->
error_logger:error_msg("Danger over. Turn off the aircondition~n"),
{ok, N};
handler_event(Event, N) ->
io:format("unmatch event:~p~n", [Event]),
{ok, N}.
handler_call(_Request, N) ->
Reply = N, {ok, Reply, N}.
handler_info(_Info, N) ->
{ok, N}.
terminate(_Reason, _N) ->
ok.
code_change(_OlderVsn, State, _Extra) ->
{ok, State}.
%%%===================LOCAL FUNCTIONS==================
%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------
现在来找点乐子:启动系统,生成一个警报,安装警报处理器,再生成一个警报……
PS C:\CodeProjects\ErlangProjects\erlang_learning\src\otp> erl -boot start_sasl -config .cfg/erlog
Eshell V9.3 (abort with ^G)
1> alarm_handler:set_alarm(too_hot).
ok
=INFO REPORT==== 18-Sep-2024::23:04:56 ===
alarm_handler: {set,too_hot}
2> gen_event:swap_handler(alarm_handler,{alarm_handler,swap},{my_alarm_handler,zhengnan}). %%这里我们将警报器换成了上述我们自己编写的警报器
init my_alarm_handler by:{zhengnan,{alarm_handler,[too_hot]}}
ok
3> alarm_handler:set_alarm(too_hot).
ok
4>
=ERROR REPORT==== 18-Sep-2024::23:06:36 ===
** gen_event handler my_alarm_handler crashed. %% 这里报错显示handle_event这个方法未导出
** Was installed in alarm_handler %% 我就应该仔细去看方法名称是否写错了
** Last event was: {set_alarm,too_hot}
** When handler state == 0
** Reason == {'function not exported',
[{my_alarm_handler,handle_event,[{set_alarm,too_hot},0],[]},
{gen_event,server_update,4,
[{file,"gen_event.erl"},{line,574}]},
{gen_event,server_notify,4,
[{file,"gen_event.erl"},{line,556}]},
{gen_event,handle_msg,6,[{file,"gen_event.erl"},{line,297}]},
{proc_lib,init_p_do_apply,3,
[{file,"proc_lib.erl"},{line,247}]}]}
4> c(my_alarm_handler).
{ok,my_alarm_handler}
但是这里报错了,为什么呢,我来会比对发现,我粗心这里把handle_event方法写成了handler_event,还有如果我们把这行代码添加上,就算下次写错了,idea也会提示我们存在没有实现的方法需要我们编写,这样一眼就能看出错误了
这里是正确的代码
%%%-------------------------------------------------------------------
%%% @author ZhengNan
%%% @copyright (C) 2024, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 13. 9月 2024 23:22
%%%-------------------------------------------------------------------
-module(my_alarm_handler).
-author("ZhengNan").
%%%=======================EXPORT=======================
-export([init/1, handle_event/2, handle_call/2, handle_info/2, terminate/2, code_change/3]).
-behaviour(gen_event).
%%%=======================INCLUDE======================
%%%=======================RECORD=======================
%%%=======================DEFINE=======================
%%%=======================TYPE=========================
%%%=================EXPORTED FUNCTIONS=================
%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------
init(Args) ->
io:format("init my_alarm_handler by:~p~n ", [Args]),
{ok, 0}.
handle_event({set_alarm, too_hot}, N) ->
error_logger:error_msg("Tell the engineer to turn on the aircondition~n"),
{ok, N + 1};
handle_event({clear_alarm, too_hot}, N) ->
error_logger:error_msg("Danger over. Turn off the aircondition~n"),
{ok, N};
handle_event(Event, N) ->
io:format("unmatch event:~p~n", [Event]),
{ok, N}.
handle_call(_Request, N) ->
Reply = N, {ok, Reply, N}.
handle_info(_Info, N) ->
{ok, N}.
terminate(_Reason, _N) ->
ok.
code_change(_OlderVsn, State, _Extra) ->
{ok, State}.
%%%===================LOCAL FUNCTIONS==================
%% ----------------------------------------------------
%% Description:
%% ----------------------------------------------------
PS C:\CodeProjects\ErlangProjects\erlang_learning\src\otp> erl -boot start_sasl -config .cfg/erlog
Eshell V9.3 (abort with ^G)
1> alarm_handler:set_alarm(too_hot).
ok
=INFO REPORT==== 18-Sep-2024::23:14:31 ===
alarm_handler: {set,too_hot}
2> gen_event:swap_handler(alarm_handler,{alarm_handler,swap},{my_alarm_handler,zhengnan}).
init my_alarm_handler by:{zhengnan,{alarm_handler,[too_hot]}}
ok
3> alarm_handler:set_alarm(too_hot).
=ERROR REPORT==== 18-Sep-2024::23:14:43 ===
Tell the engineer to turn on the aircondition
ok
4> alarm_handler:clear_alarm(too_hot).
=ERROR REPORT==== 18-Sep-2024::23:20:42 ===
Danger over. Turn off the aircondition
ok
5>
- 读取日志
让我们回到错误记录器里去看看发生了什么。
6> rb:start([{max,20}]).
=ERROR REPORT==== 18-Sep-2024::23:32:10 ===
Danger over. Turn off the aircondition
rb: reading report...done.
{ok,<0.73.0>}
7> rb:list().
No Type Process Date Time
== ==== ======= ==== ====
8 progress <0.57.0> 2024-09-18 23:31:56
7 progress <0.57.0> 2024-09-18 23:31:56
6 progress <0.57.0> 2024-09-18 23:31:56
5 progress <0.51.0> 2024-09-18 23:31:56
4 info_report <0.57.0> 2024-09-18 23:31:59
3 info_report <0.57.0> 2024-09-18 23:32:01
2 error <0.57.0> 2024-09-18 23:32:07
1 error <0.57.0> 2024-09-18 23:32:10
ok
8> rb:show(1).
ERROR REPORT <0.61.0> 2024-09-18 23:32:10
===============================================================================
Danger over. Turn off the aircondition
ok
9> rb:show(2).
ERROR REPORT <0.61.0> 2024-09-18 23:32:07
===============================================================================
可以看到错误记录机制运行正常。
在实践中,我们会确保错误日志大到足够支持几天或几周的运作。每隔几天(或几周)就会检查错误日志并调查所有错误。