查询Erlang进程的状态?

时间:2009-08-13 21:24:23

标签: erlang

Erlang中的常见模式是维护状态的递归循环:

loop(State) ->
  receive
    Msg ->
      NewState = whatever(Msg),
      loop(NewState)
  end.

有没有办法用bif或者跟踪查询正在运行的进程的状态?由于崩溃消息说“......状态是......”并显示崩溃进程的状态,我认为这很容易,但我很失望,因为我无法找到这样做的bif。

那么,我认为使用dbg模块的跟踪就可以了。不幸的是,我相信因为这些循环是尾调用优化的,所以dbg只捕获对该函数的第一次调用。

任何解决方案?

6 个答案:

答案 0 :(得分:27)

如果您的流程使用的是OTP ,则只需执行sys:get_status(Pid)

您提到的错误消息由 SASL 显示。 SASL是 OTP 中的错误报告守护程序。

您在示例代码中引用的状态只是尾递归函数的参数。除了跟踪BIF之外,没有办法使用任何东西来提取它。我想这不是生产代码中的正确解决方案,因为跟踪仅用于调试目的

正确且经过行业测试的解决方案将在您的项目中广泛使用OTP。然后,您可以充分利用SASL错误报告rb模块来收集这些报告sys - 以检查正在运行的OTP兼容流程的状态proc_lib - 以缩短生活过程符合OTP标准等。

答案 1 :(得分:5)

如果你正在使用OTP,那么事实证明这是一个比所有这些更好的答案:

sys:get_state/1

当时可能不存在。

答案 2 :(得分:4)

看起来你从无到有地解决问题。 erlang:process_info / 1提供了足够的信息用于调试目的。如果您的REALLY需要循环函数参数,为什么不将它返回给调用者以响应您自己定义的一条特殊消息?

更新: 只是为了澄清术语。语言级别上与“进程状态”最接近的是进程字典,非常不鼓励使用它。它可以通过erlang查询:process_info / 1或erlang:process / 2。 您实际需要的是跟踪进程的本地函数调用及其参数:

-module(ping).
-export([start/0, send/1, loop/1]).                                                          

start() ->                                                                                   
     spawn(?MODULE, loop, [0]).                                                              

send(Pid) ->                                                                                 
    Pid ! {self(), ping},                                                                    
    receive                                                                                  
    pong ->                                                                                  
         pong                                                                                
    end.                                                                                     

loop(S) ->                                                                                   
    receive                                                                                  
    {Pid, ping} ->                                                                           
        Pid ! pong,                                                                          
        loop(S + 1)                                                                          
    end.                                                                                    

控制台:

Erlang (BEAM) emulator version 5.6.5 [source] [smp:2] [async-threads:0] [kernel-poll:false]  

Eshell V5.6.5  (abort with ^G)                                                               
1> l(ping).                                                                                  
{module,ping}                                                                                
2> erlang:trace(all, true, [call]).                                                          
23                                                                                           
3> erlang:trace_pattern({ping, '_', '_'}, true, [local]).                                    
5                                                                                            
4> Pid = ping:start().                                                                       
<0.36.0>                                                                                     
5> ping:send(Pid).                                                                           
pong                                                                                         
6> flush().                                                                                  
Shell got {trace,<0.36.0>,call,{ping,loop,[0]}}                                              
Shell got {trace,<0.36.0>,call,{ping,loop,[1]}}                                              
ok                                                                                           
7>                                                                                           

答案 3 :(得分:3)

{status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid).

这就是我用来获取gen_server的状态。 (试图将其添加为对上述回复的评论,但无法正确格式化。)

答案 4 :(得分:2)

据我所知,你无法将参数传递给本地调用的函数。我希望有人证明我错了。

-module(loop).
-export([start/0, loop/1]).
start() ->
  spawn_link(fun () -> loop([]) end).
loop(State) ->
  receive 
    Msg ->
      loop([Msg|State])
  end.

如果我们要跟踪此模块,请在shell中执行以下操作。

dbg:tracer().
dbg:p(new,[c]).                   
dbg:tpl(loop, []).

使用此跟踪设置,您可以看到本地呼叫(tpl中的'l'表示也将跟踪本地呼叫,而不仅仅是全局呼叫。)

5> Pid = loop:start().
(<0.39.0>) call loop:'-start/0-fun-0-'/0
(<0.39.0>) call loop:loop/1
<0.39.0>
6> Pid ! foo.
(<0.39.0>) call loop:loop/1
foo

如您所见,只包括通话。看不到任何争论。

我的建议是在调试和测试发送的消息时确定正确性,而不是在进程中保存状态。即如果你向进程发送一堆消息,断言它做了正确的事情,而不是它有一组特定的值。

但是,当然,您也可以暂时在代码中添加一些erlang:display(State)次调用。穷人的调试。

答案 5 :(得分:1)

这是一个&#34; oneliner&#34;这可以在shell中使用。

sys:get_status(list_to_pid("<0.1012.0>")).

它可以帮助您将pid字符串转换为Pid。