2015-02-05 94 views
3

我知道我可以將erlang中的seq_trace設置爲正在執行的當前進程。但是我怎樣才能從shell或遠程shell如dbg tracing將其設置在另一個進程上呢?在另一個進程上設置seq_trace

+0

對不起,你爲什麼用Elixir標籤?我在這裏有沒有Elixir的一些元素? – 2015-02-06 16:19:57

+0

主要是不要羞辱標籤。 Erlang的工具也適用於靈藥,所以任何使用靈藥的人都可以回答這個問題。 – 2015-02-06 19:18:11

回答

3

您可以使用dbg啓用對另一個進程的順序跟蹤。例如,假設我們有一個模塊x與導出功能call/2

call(Pid, Msg) -> 
    Pid ! {self(), Msg}, 
    receive  
     {Pid, Reply} -> Reply 
    end. 

該功能實現一個簡單的呼叫響應。我們還假設我們有一個模塊y具有循環接收器功能:

loop() -> 
    receive 
     {Pid, Msg} -> 
      seq_trace:print({?MODULE, self(), Pid, Msg}), 
      Pid ! {self(), {Msg, os:timestamp()}}; 
     _ -> ok 
    end, 
    ?MODULE:loop(). 

該功能預計在x:call/2發送格式的消息,當它接收一個它打印一個消息到連續跟蹤,如果啓用,然後將原始消息發回給調用者並添加一個時間戳。它會忽略所有其他消息。

我們還需要一個函數來收集順序軌跡。下面的遞歸函數systracer/1只是收集seq_trace元組到一個列表中,當問及產生seq_trace郵件列表:

systracer(Acc) -> 
    receive 
     {seq_trace,_,_,_}=S -> 
      systracer([S|Acc]); 
     {seq_trace,_,_}=S -> 
      systracer([S|Acc]); 
     {dump, Pid} -> 
      Pid ! lists:reverse(Acc), 
      systracer([]); 
     stop -> ok 
    end. 

假設我們systracer/1功能是從模塊x導出。

讓我們用我們的Erlang shell來完成這一切。首先,讓我們產卵y:loop/0x:systracer/1

1> Y = spawn(y,loop,[]). 
<0.36.0> 
2> S = spawn(x,systracer,[[]]). 
<0.38.0> 
3> seq_trace:set_system_tracer(S). 
false 

產卵x:systracer/1後,我們設置過程爲seq_trace系統示蹤劑。現在,我們需要開始dbg

4> dbg:tracer(), dbg:p(all,call). 
{ok,[{matched,[email protected],28}]} 

這些dbg電話是非常標準的,尤其是如果你打算調試會話期間使用dbg跟蹤,以及可以隨意根據需要改變它們。

實際上,當您啓用dbg的順序跟蹤時,通常通過鍵入函數的特定參數來實現。這使您可以獲得特定於某個給定函數調用的跟蹤,而無需獲取該函數的所有調用的跟蹤信息。沿着這些方向,當調用x:call/2時,我們將使用dbg:tpl/3打開順序跟蹤標誌,其第二個參數的值爲原子trace。首先,我們使用dbg:fun2ms/1創建相應的匹配規範,使我們要連續跟蹤標誌,那麼我們將在dbg:tpl/3應用匹配規範:

5> Ms = dbg:fun2ms(fun([_,trace]) -> set_seq_token(send,true), set_seq_token('receive',true), set_seq_token(print,true) end). 
[{['_',trace], 
    [], 
    [{set_seq_token,send,true}, 
    {set_seq_token,'receive',true}, 
    {set_seq_token,print,true}]}] 
6> dbg:tpl(x,call,Ms). 
{ok,[{matched,[email protected],1},{saved,1}]} 

現在,我們可以調用x:call/2與第二個參數trace造成順序跟蹤發生。讓我們從衍生進程這一呼籲,以避免殼出現在生成的跟蹤I/O相關的消息:

7> spawn(fun() -> x:call(Y, trace), x:call(Y, foo) end). 
(<0.46.0>) call x:call(<0.36.0>,trace) 
<0.46.0> 

輸出的第一行是來自正常dbg跟蹤,因爲我們指定dbg:p(all, call)更早。要獲得連續的跟蹤結果,我們需要從我們的systrace/1過程中獲取轉儲:

8> S ! {dump, self()}. 
{dump,<0.34.0>} 

這發出迄今收集到我們的shell進程所有連續跟蹤。我們可以使用shell flush()命令來查看他們:

9> flush(). 
Shell got [{seq_trace,0,{send,{0,1},<0.47.0>,<0.36.0>,{<0.47.0>,trace}}}, 
      {seq_trace,0,{'receive',{0,1},<0.47.0>,<0.36.0>,{<0.47.0>,trace}}}, 
      {seq_trace,0,{print,{1,2},<0.36.0>,[],{y,<0.36.0>,<0.47.0>,trace}}}, 
      {seq_trace,0, 
         {send,{1,3}, 
          <0.36.0>,<0.47.0>, 
          {<0.36.0>,{trace,{1423,709096,206121}}}}}, 
      {seq_trace,0, 
         {'receive',{1,3}, 
           <0.36.0>,<0.47.0>, 
           {<0.36.0>,{trace,{1423,709096,206121}}}}}, 
      {seq_trace,0,{send,{3,4},<0.47.0>,<0.36.0>,{<0.47.0>,foo}}}, 
      {seq_trace,0,{'receive',{3,4},<0.47.0>,<0.36.0>,{<0.47.0>,foo}}}, 
      {seq_trace,0,{print,{4,5},<0.36.0>,[],{y,<0.36.0>,<0.47.0>,foo}}}, 
      {seq_trace,0, 
         {send,{4,6}, 
          <0.36.0>,<0.47.0>, 
          {<0.36.0>,{foo,{1423,709096,206322}}}}}, 
      {seq_trace,0, 
         {'receive',{4,6}, 
           <0.36.0>,<0.47.0>, 
           {<0.36.0>,{foo,{1423,709096,206322}}}}}] 

果然,這些都是我們希望看到的連續跟蹤消息。首先,對於包含trace原子的消息,我們從x:call/2發送接着在y:loop/0的接收和seq_trace:print/1的結果,然後從y:loop/0發送回到x:call/2的呼叫者。然後,由於在同一進程中調用了x:call(Y,foo),這意味着所有順序跟蹤標誌仍處於啓用狀態,所以第一組順序跟蹤消息後面跟着一個用於調用x:call(Y,foo)的類似組。

如果我們只需要調用x:call(Y,foo)我們可以看到,我們沒有得到連續的跟蹤消息:

10> spawn(fun() -> x:call(Y, foo) end). 
<0.55.0> 
11> S ! {dump, self()}. 
{dump,<0.34.0>} 
12> flush(). 
Shell got [] 

這是因爲我們的比賽的規格使得連續的跟蹤,只有當第二個參數x:call/2是原子trace

欲瞭解更多信息,請參閱seq_tracedbg手冊頁,並閱讀match specification chapter of the Erlang Run-Time System Application (ERTS) User's Guide

+0

非常酷,正是我之後。 – 2015-02-12 21:54:37