查询 Erlang 进程的状态?

发布于 2024-08-02 09:05:09 字数 368 浏览 7 评论 0原文

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

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

是否有任何方法可以使用 bif 或跟踪或其他方式查询正在运行的进程的状态?由于崩溃消息显示“...当状态为...”并显示崩溃进程的状态,我认为这很容易,但令我失望的是我无法找到 bif 来执行此操作。

因此,我认为使用 dbg 模块的跟踪就可以做到这一点。不幸的是,我相信因为这些循环是尾部调用优化的,所以 dbg 将仅捕获对函数的第一次调用。

有什么解决办法吗?

A common pattern in Erlang is the recursive loop that maintains state:

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

Is there any way to query the state of a running process with a bif or tracing or something? Since crash messages say "...when state was..." and show the crashed process's state, I thought this would be easy, but I was disappointed that I haven't been able to find a bif to do this.

So, then, I figured using the dbg module's tracing would do it. Unfortunately, I believe because these loops are tail call optimized, dbg will only capture the first call to the function.

Any solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

财迷小姐 2024-08-09 09:05:09

如果您的进程使用 OTP,则执行 sys:get_status(Pid)

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

您在示例代码中引用的状态只是尾递归函数的参数。除了跟踪 BIF 之外,没有其他方法可以提取它。我想这在生产代码中不是一个合适的解决方案,因为跟踪仅用于调试目的

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

If your process is using OTP, it is enough to do sys:get_status(Pid).

The error message you mentions is displayed by SASL. SASL is an error reporting daemon in OTP.

The state you are referring in your example code is just an argument of tail recursive function. There is no way to extract it using anything except for tracing BIFs. I guess this would be not a proper solution in production code, since tracing is intended to be used only for debug purposes.

Proper, and industry tested, solution would be make extensive use of OTP in your project. Then you can take full advantage of SASL error reporting, rb module to collect these reports, sys - to inspect the state of the running OTP-compatible process, proc_lib - to make short-lived processes OTP-compliant, etc.

清晰传感 2024-08-09 09:05:09

事实证明,如果您使用 OTP,则有比所有这些更好的答案:

sys:get_state/1

可能当时它不存在。

It turns out there's a better answer than all of these, if you're using OTP:

sys:get_state/1

Probably it didn't exist at the time.

因为看清所以看轻 2024-08-09 09:05:09

看起来你是在无中生有地制造问题。 erlang:process_info/1 提供了足够的信息用于调试目的。如果您确实需要循环函数参数,为什么不将其返回给调用者以响应您自己定义的特殊消息之一?

更新:
只是为了澄清术语。在语言级别上最接近“进程状态”的是进程字典,强烈建议不要使用它。可以通过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>                                                                                           

It looks like you're making the problem out of nothing. erlang:process_info/1 gives enough information for debugging purposes. If your REALLY need loop function arguments, why don't you give it back to caller in response to one of the special messages that you define yourself?

UPDATE:
Just to clarify terminology. The closest thing to the 'state of the process' on the language level is process dictionary, usage of which is highly discouraged. It can be queried by erlang:process_info/1 or erlang:process/2.
What you actually need is to trace process's local functions calls along with their arguments:

-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.                                                                                    

Console:

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>                                                                                           
苍白女子 2024-08-09 09:05:09
{status,Pid,_,[_,_,_,_,[_,_,{data,[{_,State}]}]]} = sys:get_status(Pid).

这就是我用来获取 gen_server 状态的方法。 (尝试将其作为评论添加到上面的回复中,但无法正确设置格式。)

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

That's what I use to get the state of a gen_server. (Tried to add it as a comment to the reply above, but couldn't get formatting right.)

秋意浓 2024-08-09 09:05:09

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

-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) 调用。可怜人的调试。

As far as I know you cant get the arguments passed to a locally called function. I would love for someone to prove me wrong.

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

If we want to trace this module you do the following in the shell.

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

Using this tracing setting you get to see local calls (the 'l' in tpl means that local calls will be traced as well, not only global ones).

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

As you see, just the calls are included. No arguments in sight.

My recommendation is to base correctness in debugging and testing on the messages sent rather than state kept in processes. I.e. if you send the process a bunch of messages, assert that it does the right thing, not that it has a certain set of values.

But of course, you could also sprinkle some erlang:display(State) calls in your code temporarily. Poor man's debugging.

信仰 2024-08-09 09:05:09

这是一个可以在 shell 中使用的“oneliner”。

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

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

This is a "oneliner" That can be used in the shell.

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

It helps you convert a pid string into a Pid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文