gen_server在erlang otp编程中的地位是无可撼动的,几乎都是gen_server或者gen_fsm的模型。那么程序运行起来的时候 我们如何查看gen_server的内部状态呢。有2种方法:
1. 自己写个类似于info这样的函数,来获取状态。
2. 利用系统现有的架构。sasl应用带了一个si的东西 全名是status inspector, 这个东西就是设计来帮用户解决这个问题的。
实验开始:
-
root@nd-desktop:~# cat abc.erl
-
-module(abc).
-
-behaviour(gen_server).
-
-export([start_link/0]).
-
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
-
terminate/2, code_change/3]).
-
-
-export([format_status/2]).
-
-export([test/0]).
-
-
-record(state, {a, b}).
-
-
-define(SERVER, ?MODULE).
-
-
start_link() ->
-
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
-
-
test()->
-
gen_server:call(?SERVER, {test, "param1"}).
-
-
init([]) ->
-
{ok, #state{a=hello, b=world}}.
-
-
handle_call({test, _} = Request, _From, State) ->
-
io:format("got msg ~p~n", [Request]),
-
{reply, ok, State};
-
-
handle_call(_Request, _From, State) ->
-
Reply = ok,
-
{reply, Reply, State}.
-
-
handle_cast(_Msg, State) ->
-
{noreply, State}.
-
-
handle_info(_Info, State) ->
-
{noreply, State}.
-
-
terminate(_Reason, _State) ->
-
ok.
-
-
code_change(_OldVsn, State, _Extra) ->
-
{ok, State}.
-
-
format_status(_Opt, [_PDict, #state{a=A,
-
b = B
-
}]) ->
-
-
[{data, [{"a===", A},
-
{"b===", B}]}].
-
-
root@nd-desktop:~# erl -boot start_sasl
-
Erlang R13B03 (erts-5.7.4) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]
-
-
-
=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
-
supervisor: {local,sasl_safe_sup}
-
started: [{pid,<0.35.0>},
-
{name,alarm_handler},
-
{mfa,{alarm_handler,start_link,[]}},
-
{restart_type,permanent},
-
{shutdown,2000},
-
{child_type,worker}]
-
-
=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
-
supervisor: {local,sasl_safe_sup}
-
started: [{pid,<0.36.0>},
-
{name,overload},
-
{mfa,{overload,start_link,[]}},
-
{restart_type,permanent},
-
{shutdown,2000},
-
{child_type,worker}]
-
-
=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
-
supervisor: {local,sasl_sup}
-
started: [{pid,<0.34.0>},
-
{name,sasl_safe_sup},
-
{mfa,
-
{supervisor,start_link,
-
[{local,sasl_safe_sup},sasl,safe]}},
-
{restart_type,permanent},
-
{shutdown,infinity},
-
{child_type,supervisor}]
-
-
=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
-
supervisor: {local,sasl_sup}
-
started: [{pid,<0.37.0>},
-
{name,release_handler},
-
{mfa,{release_handler,start_link,[]}},
-
{restart_type,permanent},
-
{shutdown,2000},
-
{child_type,worker}]
-
-
=PROGRESS REPORT==== 29-Oct-2009::16:07:24 ===
-
application: sasl
-
started_at: nonode@nohost
-
Eshell V5.7.4 (abort with ^G)
-
1> si:start(). %必须手动启动
-
-
=PROGRESS REPORT==== 29-Oct-2009::16:07:31 ===
-
supervisor: {local,sasl_sup}
-
started: [{pid,<0.43.0>},
-
{name,si_server},
-
{mfa,{si_sasl_supp,start_link,[[]]}},
-
{restart_type,temporary},
-
{shutdown,brutal_kill},
-
{child_type,worker}]
-
{ok,<0.43.0>}
-
2> si:help().
-
-
Status Inspection tool - usage
-
==============================
-
For all these functions, Opt is an optional argument
-
which can be 'normal' or 'all'; default is 'normal'.
-
If 'all', all information will be printed.
-
A Pid can be: "", {A, B, C}, B, a registered_name or an abbrev.
-
ANY PROCESS
-
si:pi([Opt,] Pid) - Formatted information about any process that
-
SI recognises.
-
si:pi([Opt,] A,B,C) - Same as si:pi({A, B, C}).
-
si:ppi(Pid) - Pretty formating of process_info.
-
Works for any process.
-
MISC
-
si:abbrevs() - Lists valid abbreviations.
-
si:start_log(Filename) - Logging to file.
-
si:stop_log()
-
si:start() - Starts Status Inspection (the si_server).
-
si:start([{start_log, FileName}])
-
si:stop() - Shut down SI.
-
ok
-
3> abc:start_link().
-
{ok,<0.46.0>}
-
4> abc:test().
-
got msg {test,"param1"}
-
ok
-
5> sys:log(abc,true). %打开gen_server的消息log功能
-
ok
-
6> abc:test(). %这个请求消息被记录
-
got msg {test,"param1"}
-
ok
-
7> si:pi(abc). %好戏开始
-
-
Status for generic server abc
-
===============================================================================
-
Pid <0.46.0>
-
Status running
-
Parent <0.41.0>
-
Logged events %这个是log到的消息
-
{10,
-
[{{out,ok,<0.41.0>,{state,hello,world}},
-
abc,
-
{gen_server,print_event}},
-
{{in,{'$gen_call',{<0.41.0>,#Ref<0.0.0.85>},{test,"param1"}}},
-
abc,
-
{gen_server,print_event}}]}
-
-
%这个是format_status的结果 如果没有format_status那么导出是 {a=hello, b=world}
-
-
a=== hello
-
b=== world
-
-
ok
-
8> si:ppi(abc).
-
-
Pretty Process Info
-
-------------------
-
[{registered_name,abc},
-
{current_function,{gen_server,loop,6}},
-
{initial_call,{proc_lib,init_p,5}},
-
{status,waiting},
-
{message_queue_len,0},
-
{messages,[]},
-
{links,[<0.41.0>]},
-
{dictionary,[{'$ancestors',[<0.41.0>]},{'$initial_call',{abc,init,1}}]},
-
{trap_exit,false},
-
{error_handler,error_handler},
-
{priority,normal},
-
{group_leader,<0.25.0>},
-
{total_heap_size,233},
-
{heap_size,233},
-
{stack_size,9},
-
{reductions,117},
-
{garbage_collection,[{fullsweep_after,65535},{minor_gcs,0}]},
-
{suspending,[]}]
-
ok
-
-
9> sys:get_status(abc). %当然你也可以这么看
-
{status,<0.46.0>,
-
{module,gen_server},
-
[[{'$ancestors',[<0.41.0>]},{'$initial_call',{abc,init,1}}],
-
running,<0.41.0>,
-
[{log,{10,
-
[{{out,ok,<0.41.0>,{state,hello,world}},
-
abc,
-
{gen_server,print_event}},
-
{{in,{'$gen_call',{<0.41.0>,#Ref<0.0.0.85>},
-
{test,"param1"}}},
-
abc,
-
{gen_server,print_event}}]}}],
-
[abc,{state,hello,world},abc,infinity]]}
结论:
这个是文档未公开的功能。上面演示了如何sys打开log, 如何察看gen_server的状态
from:
http://mryufeng.iteye.com/blog/506609