檢視原始碼 dbg (runtime_tools v2.1.1)
文字式追蹤工具
此模組實作了一個基於文字的介面,用於 trace:process/4
、 trace:port/4
和 trace:function/4
BIF,簡化了函數、程序、埠口和訊息的追蹤。
若要快速開始追蹤函數呼叫,您可以在 Erlang shell 中使用以下程式碼
1> dbg:tracer(). % Start the default trace message receiver
{ok,<0.90.0>}
2> dbg:p(all, c). % Set upp call tracing on all processes
{ok,[{matched,nonode@nohost,49}]}
3> dbg:tp(lists, seq, cx). % Set up call and exception tracing on lists:seq/2,3
{ok,[{matched,nonode@nohost,2},{saved,cx}]}
4> lists:seq(1, 10).
(<0.88.0>) call lists:seq(1,10) ({erl_eval,do_apply,7,{"erl_eval.erl",904}})
[1,2,3,4,5,6,7,8,9,10]
(<0.88.0>) returned from lists:seq/2 -> [1,2,3,4,5,6,7,8,9,10]
這些工具也適用於大型系統的系統測試,在這些系統中,其他工具對系統效能的影響過於嚴重。 也包含對循序追蹤的一些基本支援;請參閱進階主題部分。
從 shell 進行簡單追蹤,無需事先設定
若要以最少麻煩的方式追蹤函數呼叫,請呼叫 dbg:c(Module, Name, Arguments)
。dbg:c/3
會啟動一個臨時追蹤接收器,啟用所有追蹤標誌,並從臨時程序呼叫指定的函數。 例如,以下是如何追蹤對 application:which_applications/0
的呼叫
1> dbg:c(application, which_applications, []).
(<0.92.0>) <0.45.0> ! {'$gen_call',{<0.92.0>,
[alias|
#Ref<0.0.11779.270031856.1478295555.230456>]},
which_applications} (Timestamp: {1710,
847802,
479222})
(<0.92.0>) out {gen,do_call,4} (Timestamp: {1710,847802,479231})
(<0.92.0>) in {gen,do_call,4} (Timestamp: {1710,847802,479271})
(<0.92.0>) << {[alias|#Ref<0.0.11779.270031856.1478295555.230456>],
[{stdlib,"ERTS CXC 138 10","5.2.1"},
{kernel,"ERTS CXC 138 10","9.2.2"}]} (Timestamp: {1710,
847802,
479274})
[{stdlib,"ERTS CXC 138 10","5.2.1"},
{kernel,"ERTS CXC 138 10","9.2.2"}]
會產生四個追蹤事件
- 一個傳送事件 (
!
),用於將請求從目前程序傳送到application_controller
程序。 - 一個排程輸出事件 (
out
),當目前程序在receive
中等待回覆到達時排程輸出。 - 一個排程輸入事件 (
in
),當回覆到達時,目前程序排程輸入。 - 一個
receive
事件 (<<
),當目前程序從application_controller
程序擷取回覆時。
dbg:c/4
函數具有第四個引數,用於指定追蹤標誌。 以下是如何僅顯示訊息傳送和接收
2> dbg:c(application, which_applications, [], m).
(<0.96.0>) <0.45.0> ! {'$gen_call',{<0.96.0>,
[alias|
#Ref<0.0.12291.270031856.1478295555.230496>]},
which_applications}
(<0.96.0>) << {[alias|#Ref<0.0.12291.270031856.1478295555.230496>],
[{stdlib,"ERTS CXC 138 10","5.2.1"},
{kernel,"ERTS CXC 138 10","9.2.2"}]}
[{stdlib,"ERTS CXC 138 10","5.2.1"},
{kernel,"ERTS CXC 138 10","9.2.2"}]
從 shell 追蹤
從 shell 追蹤的另一種方式是明確啟動追蹤器,並在您想要追蹤的程序上設定您選擇的追蹤標誌。 例如,以下是如何追蹤訊息和程序事件
1> Pid = spawn(fun() -> receive {From,Msg} -> From ! Msg end end).
<0.90.0>
2> dbg:tracer().
{ok,<0.92.0>}
3> dbg:p(Pid, [m,procs]).
{ok,[{matched,nonode@nohost,1}]}
4> Pid ! {self(),hello}.
(<0.90.0>) << {<0.88.0>,hello}
{<0.88.0>,hello}
(<0.90.0>) <0.88.0> ! hello
(<0.90.0>) exit normal
5> flush().
Shell got hello
ok
為了追蹤函數呼叫,除了為程序啟用 call
追蹤標誌之外,還必須為要追蹤的函數設定追蹤模式。
範例
1> dbg:tracer().
{ok,<0.90.0>}
2> dbg:p(all, call).
{ok,[{matched,nonode@nohost,49}]}
3> dbg:tp(lists, last, 1, []).
{ok,[{matched,nonode@nohost,1}]}
4> lists:last([a,b,c,d,e]).
(<0.88.0>) call lists:last([a,b,c,d,e])
e
5> dbg:tp(lists, last, 1, [{'_',[],[{return_trace}]}]).
{ok,[{matched,nonode@nohost,1},{saved,1}]}
6> lists:last([a,b,c,d,e]).
(<0.88.0>) call lists:last([a,b,c,d,e])
(<0.88.0>) returned from lists:last/1 -> e
e
進階主題 - 與 seq_trace 結合使用
dbg
模組主要目標是透過 trace:process/4
函數進行追蹤。 有時希望以更精細的方式追蹤訊息,這可以使用 seq_trace
模組來完成。
seq_trace
實作循序追蹤 (在 AXE10 世界中已知,有時稱為「forlopp 追蹤」)。 dbg
可以解譯從 seq_trace
產生的訊息,並且可以使用相同類型的追蹤器函數。 seq_trace
訊息也可以傳送到追蹤埠口以進行進一步分析。
由於匹配規格可以開啟循序追蹤,因此結合 dbg
和 seq_trace
可能非常強大。 此簡短範例顯示了一個會話,其中循序追蹤用於追蹤 dbg
模組和追蹤本身
1> dbg:tracer().
{ok,<0.30.0>}
2> {ok, Tracer} = dbg:get_tracer().
{ok,<0.31.0>}
3> seq_trace:set_system_tracer(Tracer).
false
4> dbg:tp(dbg, get_tracer, 0, [{[],[],[{set_seq_token, send, true}]}]).
{ok,[{matched,nonode@nohost,1},{saved,1}]}
5> dbg:p(all,call).
{ok,[{matched,nonode@nohost,22}]}
6> dbg:get_tracer(), seq_trace:set_token([]).
(<0.25.0>) call dbg:get_tracer()
SeqTrace [0]: (<0.25.0>) <0.30.0> ! {<0.25.0>,get_tracer} [Serial: {2,4}]
SeqTrace [0]: (<0.30.0>) <0.25.0> ! {dbg,{ok,<0.31.0>}} [Serial: {4,5}]
{1,0,5,<0.30.0>,4}
此會話將 system_tracer 設定為與一般追蹤器程序相同的程序 (即 <0.31.0>),並將函數 dbg:get_tracer
的追蹤模式設定為具有設定循序權杖動作的模式。 當追蹤程序 (在此案例中追蹤所有程序) 呼叫函數時,程序會被權杖「汙染」,並且會為伺服器請求和回覆傳送 seq_trace
訊息。 呼叫之後的 seq_trace:set_token([])
會清除 seq_trace
權杖,這就是為什麼當答案透過 shell 傳播到主控台埠口時,不會傳送訊息。 否則,輸出會更吵雜。
注意事項
當在群組領導者程序 (I/O 程序) 上追蹤函數呼叫時,存在造成死鎖的風險。 如果群組領導者程序產生追蹤訊息,而追蹤器程序透過呼叫追蹤處理常式函數向同一個群組領導者傳送 I/O 請求,就會發生這種情況。 只有在追蹤處理常式使用 io
函數 (例如 format/2
) 列印到 tty 時才會發生問題。 請注意,當呼叫 dbg:p(all, call)
時,也會追蹤 IO 程序。 以下是一個範例
%% Using a default line editing shell
1> dbg:tracer(process, {fun(Msg,_) -> io:format("~p~n", [Msg]), 0 end, 0}).
{ok,<0.37.0>}
2> dbg:p(all, [call]).
{ok,[{matched,nonode@nohost,25}]}
3> dbg:tp(mymod,[{'_',[],[]}]).
{ok,[{matched,nonode@nohost,0},{saved,1}]}
4> mymod: % TAB pressed here
%% -- Deadlock --
以下是另一個範例
%% Using a shell without line editing (oldshell)
1> dbg:tracer(process).
{ok,<0.31.0>}
2> dbg:p(all, [call]).
{ok,[{matched,nonode@nohost,25}]}
3> dbg:tp(lists,[{'_',[],[]}]).
{ok,[{matched,nonode@nohost,0},{saved,1}]}
% -- Deadlock --
我們在第一個範例中發生死鎖的原因是,當按下 TAB 鍵以展開函數名稱時,群組領導者 (處理字元輸入) 會呼叫 mymod:module_info()
。 這會產生追蹤訊息,進而導致追蹤器程序透過呼叫 io:format/2
向群組領導者傳送 IO 請求。 我們最終會陷入死鎖。
在第二個範例中,我們使用預設的追蹤處理常式函數。 此處理常式會將 IO 請求傳送到 user
程序來列印到 tty。 當 Erlang 在 oldshell 模式下啟動時,shell 程序會將 user
作為其群組領導者,並且在此範例中追蹤器程序也會如此。 由於 user
會呼叫 lists
中的函數,因此只要傳送第一個 IO 請求,我們就會陷入死鎖。
以下是一些避免死鎖的建議
- 請勿追蹤追蹤器程序的群組領導者。 如果已為所有程序開啟追蹤,請呼叫
dbg:p(TracerGLPid, clear)
以停止追蹤群組領導者 (TracerGLPid
)。process_info(TracerPid, group_leader)
會告訴您這是哪個程序 (TracerPid
是從dbg:get_tracer/0
傳回)。 - 如果使用預設的追蹤處理常式函數,請勿追蹤
user
程序。 - 在您自己的追蹤處理常式函數中,請呼叫
erlang:display/1
,而不是io
函數,或者,如果user
不用作群組領導者,請列印到user
而不是預設的群組領導者。 範例:io:format(user, Str, Args)
。
摘要
函數
評估以設定的 Flags
中的追蹤標誌表示的 apply(Mod, Fun, Args)
運算式。
從追蹤節點清單中清除節點。
停用由 ModuleOrMFA
指定的一或多個函數的呼叫追蹤。
清除指定追蹤事件 (send
或 'receive'
) 的匹配規格,還原為追蹤所有觸發事件的預設值。
停用由 ModuleOrMFA
指定的一或多個函數的全域呼叫追蹤。
停用由 ModuleOrMFA
指定的一或多個函數的本機呼叫追蹤。
透過剖析轉換將函數呼叫中作為參數鍵入的常值函數轉換為匹配規格的虛擬函數。
傳回所有追蹤訊息傳送到的程序、埠口或追蹤器模組。
提供簡短線上說明的項目清單。
為 dbg
模組中的函式提供簡短的說明文字。
顯示所有追蹤的處理程序和埠的相關資訊。
在主控台上顯示追蹤節點的清單。
列出先前在會期中使用過的所有匹配規格。
將遠端節點 (Nodename
) 新增至執行追蹤的節點清單。
等同於 p(Item, [m])
。
根據 Flags
指定的值追蹤 Item
。
使用提供的會期執行 dbg
命令,如果提供了會期名稱,則在呼叫期間建立會期。
使用指定的 Name
建立新的 dbg
會期。
銷毀 dbg session/0
。
停止 dbg
伺服器,清除所有處理程序的追蹤旗標,清除所有函式的追蹤模式,清除傳送/接收的追蹤模式,關閉所有追蹤用戶端,並關閉所有追蹤埠。
關閉先前啟動的追蹤用戶端。
針對 ModuleOrMFA
指定的一個或多個匯出的函式啟用呼叫追蹤。
將匹配規格與追蹤事件 send
或 'receive'
建立關聯。
針對 ModuleOrMFA
指定的一個或多個函式啟用呼叫追蹤。
啟動一個追蹤用戶端,該用戶端讀取追蹤埠驅動程式建立的輸出 (請參閱 trace_port/2
),並以與 tracer/0
函式建立的追蹤程式處理程序大致相同的方式處理輸出。
此函式的作用與 trace_client/2
完全相同,但允許您編寫自己的處理程式函式。
建立一個追蹤埠產生函式,該函式適合做為 tracer/2
的第二個引數。
此函式用於在給定節點 (Nodename
) 上的作用中追蹤埠驅動程式執行控制操作。
在本地節點上啟動一個伺服器,該伺服器將成為所有追蹤訊息的接收者。
在本地節點上使用其他參數啟動追蹤程式伺服器。
此函式等同於 tracer/2
,但在指定的節點上執行動作。
類型
-type built_in_alias() :: x | c | cx.
-type match_desc() :: [match_info()].
-type match_spec() :: [{match_pattern(), [_], [_]}].
-opaque session()
-type tp_arity() :: arity() | '_'.
-type tp_function() :: atom() | '_'.
-type tp_id() :: pos_integer().
-type tp_match_spec() :: tp_id() | built_in_alias() | [] | match_spec().
-type tp_module() :: module() | '_'.
-type trace_wrap_file_size() :: non_neg_integer() | {time, WrapTime :: pos_integer()}.
-type trace_wrap_files_spec() :: {file:name_all(), wrap, Suffix :: string()} | {file:name_all(), wrap, Suffix :: string(), WrapSize :: trace_wrap_file_size()} | {file:name_all(), wrap, Suffix :: string(), WrapSize :: trace_wrap_file_size(), WrapCnt :: pos_integer()}.
函式
評估以設定的 Flags
中的追蹤標誌表示的 apply(Mod, Fun, Args)
運算式。
c
代表 call (呼叫)。
這是一種從 Erlang Shell 追蹤處理程序的便利方式。
-spec cn(Nodename) -> ok when Nodename :: node().
從追蹤節點清單中清除節點。
cn
代表 clear node (清除節點)。
後續呼叫 tp/2
和 p/2
時,不會考慮該節點,但已在該節點上啟用的追蹤將繼續有效。
傳回 ok
。此呼叫不會失敗。
-spec ctp() -> {ok, MatchDesc :: match_desc()} | {error, term()}.
等同於 ctp({'_', '_', '_'})
。
-spec ctp(Module | {Module, Function, Arity}) -> {ok, MatchDesc :: match_desc()} | {error, term()} when Module :: tp_module(), Function :: tp_function(), Arity :: tp_arity().
停用由 ModuleOrMFA
指定的一或多個函數的呼叫追蹤。
如果 ModuleOrMFA
是一個原子 (模組名稱),則此函式呼叫等同於 ctp({ModuleOrMFA, '_', '_'})
。
否則,ModuleOrMFA
應該是 {Module, Function, Arity}
。
ctp
代表 clear trace pattern (清除追蹤模式)。
ModuleOrMFA
的語意與 tp/2
或 tpl/2
中對應函式規格的語意相同。本機和全域呼叫追蹤都會停用。
傳回值會反映符合的函式數量,並如 tp/2
中所述建構,但不會傳回 {saved, N}
元組。
-spec ctp(Module :: tp_module(), Function :: tp_function()) -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec ctp(Module :: tp_module(), Function :: tp_function(), Arity :: tp_arity()) -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec ctpe(Event) -> {ok, MatchDesc} | {error, term()} when Event :: send | 'receive', MatchDesc :: [MatchNum], MatchNum :: {matched, node(), 1} | {matched, node(), 0, RPCError :: term()}.
清除指定追蹤事件 (send
或 'receive'
) 的匹配規格,還原為追蹤所有觸發事件的預設值。
ctpe
代表 clear trace pattern event (清除追蹤模式事件)。
-spec ctpg() -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec ctpg(Module | {Module, Function :: tp_function(), Arity :: tp_arity()}) -> {ok, MatchDesc :: term()} | {error, term()} when Module :: tp_module().
停用由 ModuleOrMFA
指定的一或多個函數的全域呼叫追蹤。
如果 ModuleOrMFA
是一個原子 (模組名稱),則此函式呼叫等同於 ctpg({ModuleOrMFA, '_', '_'})
。
否則,ModuleOrMFA
應該是 {Module, Function, Arity}
。
ctpg
代表 clear trace pattern global (清除全域追蹤模式)。
-spec ctpg(Module :: tp_module(), Function :: tp_function()) -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec ctpg(Module :: tp_module(), Function :: tp_function(), Arity :: tp_arity()) -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec ctpl() -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec ctpl(Module | {Module, Function :: tp_function(), Arity :: tp_arity()}) -> {ok, MatchDesc :: term()} | {error, term()} when Module :: tp_module().
停用由 ModuleOrMFA
指定的一或多個函數的本機呼叫追蹤。
如果 ModuleOrMFA
是一個原子 (模組名稱),則此函式呼叫等同於 ctpl({ModuleOrMFA, '_', '_'})
。
否則,ModuleOrMFA
應該是 {Module, Function, Arity}
。
ctpl
代表 clear trace pattern local (清除本機追蹤模式)。
-spec ctpl(Module :: tp_module(), Function :: tp_function()) -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec ctpl(Module :: tp_module(), Function :: tp_function(), Arity :: tp_arity()) -> {ok, MatchDesc :: match_desc()} | {error, term()}.
-spec dtp() -> ok.
忘記在呼叫 tp/2
期間儲存的所有匹配規格。
dtp
代表 delete trace patterns (刪除追蹤模式)。
在從檔案使用 rtp/1
還原其他匹配規格之前,移除所有已儲存的匹配規格會很有用。使用 dtp/1
刪除特定的已儲存匹配規格。
-spec dtp(N) -> ok when N :: tp_id().
忘記在呼叫 tp/2
期間儲存的特定匹配規格。
dtp
代表 delete trace pattern (刪除追蹤模式)。
-spec flush_trace_port() -> term().
-spec fun2ms(LiteralFun) -> MatchSpec when LiteralFun :: fun((term()) -> term()), MatchSpec :: match_spec().
透過剖析轉換將函數呼叫中作為參數鍵入的常值函數轉換為匹配規格的虛擬函數。
「文字」的意義是指 fun 需要以文字形式寫為函式呼叫的引數;它不能保存在變數中,然後再將變數傳遞給函式。此外,必須啟用剖析轉換模組 ms_transform
。啟用它的最簡單方法是將以下這一行新增至原始檔
-include_lib("stdlib/include/ms_transform.hrl").
如果未在原始檔中包含 ms_transform.hrl
,會導致執行階段錯誤,而不是編譯階段錯誤。
此函式也可以直接從 Erlang Shell 叫用,如以下範例所示。
fun 的標頭必須是符合清單的單一模式。該模式將用於比對呼叫的引數
範例:
1> dbg:fun2ms(fun([_,_]) -> true end).
[{['_','_'],[],[true]}]
2> dbg:fun2ms(fun(Args) when length(Args) > 6 -> true end).
[{'$1',[{'>',{length,'$1'},6}],[true]}]
第一個匹配規格在呼叫具有兩個引數的函式時符合。第二個匹配規格在呼叫具有超過 6 個引數的函式時符合。
範例:
1> dbg:fun2ms(fun(42) -> true end).
Error: dbg:fun2ms requires fun with single variable or list parameter
{error,transform_error}
2> dbg:fun2ms(fun([<<H,T/binary>>]) -> true end).
Error: fun head contains bit syntax matching of variable 'H', which cannot be translated into match_spec
{error,transform_error}
前面的兩個範例顯示當無法將 fun 轉換為匹配規格時會發生什麼情況。在第一個範例中,fun 標頭不可能符合清單。在第二個範例中,嘗試使用位元語法來剖析二進位,但目前匹配規格不支援此語法。
但是,請注意,可以比對文字二進位
1> dbg:fun2ms(fun([<<"abc">>]) -> true end).
[{[<<"abc">>],[],[true]}]
匹配規格支援 Erlang 支援的 保護運算式 的大部分子集,但不是全部。例如,目前不支援更新對應
1> dbg:fun2ms(fun([M]) when map_size(M#{a => b}) > 2 -> true end).
Error: the language element map (in guard) cannot be translated into match_spec
{error,transform_error}
但是,允許在保護中建立對應
1> dbg:fun2ms(fun([M]) when map_size(#{a => b}) > 2 -> true end).
[{['$1'],[{'>',{map_size,#{a => b}},2}],[true]}]
可以匯入環境中的變數,因此這會有效
1> X = 3.
3
2> dbg:fun2ms(fun([M,N]) when N > X -> return_trace() end).
[{['$1','$2'],[{'>','$2',{const,3}}],[{return_trace}]}]
導入的變數將會被替換為 const
表達式,這與 Erlang fun 的靜態作用域一致。
在 fun 的主體中,只允許使用 guard 表達式和呼叫追蹤專用的特殊函數。
範例:
1> dbg:fun2ms(fun([A]) when is_atom(A) -> return_trace() end).
[{['$1'],[{is_atom,'$1'}],[{return_trace}]}]
2> dbg:fun2ms(fun(_) -> erlang:garbage_collect() end).
Error: fun containing the remote function call 'erlang:garbage_collect/0' (called in body) cannot be translated into match_spec
{error,transform_error}
警告
如果 parse transform 沒有應用到呼叫
dbg:fun2ms/1
的模組,則在執行時會因badarg
例外而失敗。
更多資訊請參閱 STDLIB 中 ms_transform
模組的文件。
-spec get_tracer() -> term().
等同於 get_tracer(node())
。
-spec get_tracer(Nodename) -> {ok, Tracer} when Nodename :: atom(), Tracer :: port() | pid() | {module(), term()}.
傳回所有追蹤訊息傳送到的程序、埠口或追蹤器模組。
-spec h() -> ok.
提供簡短線上說明的項目清單。
h
代表 help (說明)。
-spec h(Item) -> ok when Item :: atom().
為 dbg
模組中的函式提供簡短的說明文字。
h
代表 help (說明)。
可以透過呼叫 dbg:h/0
來列出可用的項目。
-spec i() -> ok.
顯示所有追蹤的處理程序和埠的相關資訊。
i
代表 information (資訊)。
-spec ln() -> ok.
在主控台上顯示追蹤節點的清單。
ln
代表 list nodes (列出節點)。
-spec ltp() -> ok.
列出先前在會期中使用過的所有匹配規格。
ltp
代表 list trace patterns (列出追蹤模式)。
此函數會列出先前在呼叫 tp/2
和 tpl/2
時儲存的所有 match specification,以及所有內建的 match specification。這避免了重新輸入複雜的 match specification。請注意,如果呼叫 stop/0
,match specification 將會遺失。
Match specification 可以儲存在檔案中 (如果存在可讀寫的檔案系統),以便在稍後的偵錯階段中使用;請參閱 wtp/1
和 rtp/1
。
有三種內建的追蹤模式
exception_trace
,x
- 設定追蹤,顯示函數名稱、參數、回傳值和函數引發的例外。caller_trace
,c
- 設定追蹤,顯示函數名稱、參數,以及有關呼叫它的函數的資訊。caller_exception_trace
,cx
- 結合exception_trace
和caller_trace
。
以下範例說明如何使用內建的 match specification
1> dbg:tracer().
{ok,<0.90.0>}
2> dbg:tp(lists, seq, 2, cx).
{ok,[{matched,nonode@nohost,1},{saved,cx}]}
3> dbg:p(self(), call).
{ok,[{matched,nonode@nohost,1}]}
4> lists:seq(1, 5).
(<0.88.0>) call lists:seq(1,5) ({erl_eval,do_apply,7,{"erl_eval.erl",904}})
[1,2,3,4,5]
(<0.88.0>) returned from lists:seq/2 -> [1,2,3,4,5]
將遠端節點 (Nodename
) 新增至執行追蹤的節點清單。
n
代表 node (節點)。
dbg
伺服器會維護一個追蹤應執行所在節點的列表。每當呼叫 tp/2
或 p/2
時,它會在該列表中的所有節點 (包括本機節點) 上執行 (除了針對特定 pid/0
或 port/0
作為第一個參數的 p/2
之外,在這種情況下,命令僅在指定的程序或埠所在的節點上執行)。
呼叫此函數時,它會在遠端節點上啟動追蹤器程序,該程序會將所有追蹤訊息傳送到本機節點上的追蹤器程序 (透過 Erlang 分散式系統)。如果本機節點上沒有執行追蹤器程序,則會回傳錯誤原因 no_local_tracer
。本機節點上的追蹤器程序必須使用 tracer/0,2
函數啟動。
如果 Nodename
是本機節點,則會回傳錯誤原因 cant_add_local_node
。
如果在本機節點上執行追蹤埠 (請參閱 trace_port/2
),則無法使用追蹤器程序追蹤遠端節點。會回傳錯誤原因 cant_trace_remote_pid_to_local_port
。但是,可以使用 tracer/3
函數在遠端節點上啟動追蹤埠。
如果無法連線到節點 Nodename
,此函數也會回傳錯誤。
等同於 p(Item, [m])
。
-spec p(Item :: term(), Flags :: term()) -> {ok, MatchDesc} | {error, term()} when MatchDesc :: [MatchNum], MatchNum :: {matched, node(), integer()} | {matched, node(), 0, RPCError}, RPCError :: term().
根據 Flags
指定的值追蹤 Item
。
p
代表 process (程序)。
以下類型的數值允許作為 Item
pid/0
或port/0
- 追蹤對應的程序或埠。程序或埠可以是遠端程序或埠 (在另一個 Erlang 節點上)。節點必須在追蹤節點的列表中 (請參閱n/1
和tracer/3
)。all
- 追蹤系統中的所有程序和埠,以及之後建立的所有程序和埠。processes
- 追蹤系統中的所有程序,以及之後建立的所有程序。ports
- 追蹤系統中的所有埠,以及之後建立的所有埠。new
- 追蹤呼叫後建立的所有程序和埠。new_processes
- 追蹤呼叫後建立的所有程序。new_ports
- 追蹤呼叫後建立的所有埠。existing
- 追蹤所有現有的程序和埠。existing_processes
- 追蹤所有現有的程序。existing_ports
- 追蹤所有現有的埠。atom/0
- 追蹤具有對應註冊名稱的程序或埠。程序或埠可以在另一個 Erlang 節點上。節點必須在追蹤節點的列表中 (請參閱n/1
和tracer/3
)。integer/0
- 追蹤程序<0.Item.0>
。{X, Y, Z}
- 追蹤程序<X.Y.Z>
。string/0
- 如果Item
是從pid_to_list/1
回傳的字串 "<X.Y.Z>",則追蹤程序<X.Y.Z>
。
啟用代表程序群組的 Item
時,會在所有使用 n/1
或 tracer/3
函數新增的節點上啟用 Item
。
Flags
可以是單一原子或旗標的列表。可用的旗標如下:
s (send)
- 追蹤程序或埠傳送的訊息。r (receive)
- 追蹤程序或埠接收的訊息。m (messages)
- 追蹤程序或埠接收和傳送的訊息。c (call)
- 根據系統中設定的追蹤模式,追蹤程序的全域函數呼叫 (請參閱tp/2
)。p (procs)
- 追蹤與程序相關的事件。ports
- 追蹤與埠相關的事件。sos (set on spawn)
- 讓追蹤程序建立的所有程序繼承追蹤程序的追蹤旗標。sol (set on link)
- 每當追蹤程序連結到P2
時,讓另一個程序P2
繼承追蹤程序的追蹤旗標。sofs (set on first spawn)
- 這與sos
相同,但僅適用於追蹤程序產生的第一個程序。sofl (set on first link)
- 這與sol
相同,但僅適用於追蹤程序第一次呼叫link/1
時。all
- 設定除silent
以外的所有旗標。clear
- 清除所有旗標。
列表也可以包含 trace:process/4
和 trace:port/4
中允許的任何旗標。
此函數會回傳錯誤元組或 {ok, List}
元組。List
包含有關有多少個程序和埠符合的規格 (在單一 pid 的情況下,正好是 1 個)。符合的程序的規格是 {matched, Node, N}
。如果對遠端節點的遠端處理器呼叫 (使用 rpc
) 失敗,則會將 rpc
錯誤訊息作為元組中的第四個元素回傳,並且符合的程序數為 0。
從文字檔讀取匹配規格,該文字檔可能由 wtp/1
函式產生。
rtp
代表 read trace patterns (讀取追蹤模式)。
此函數會驗證所有 match specification 的語法是否正確。如果在任何 match specification 中發現任何錯誤,則不會將任何 match specification 新增到執行系統的已儲存 match specification 列表中。
檔案中的 match specification 會與目前的 match specification 合併,以便不會產生重複項目。請使用 ltp/0
來查看從檔案中分配給規格的編號。
此函數會回傳錯誤元組,可能是由於 I/O 問題 (例如檔案不存在或無法讀取) 或檔案格式問題。在後一種情況下,Reason
會以或多或少的文字格式提供,提示導致問題的原因。
使用提供的會期執行 dbg
命令,如果提供了會期名稱,則在呼叫期間建立會期。
使用提供的 fun 呼叫的任何 dbg
函數都將使用提供的 session/0
,而不是預設的 dbg
工作階段。這表示追蹤將與系統上的其他追蹤使用者隔離。
此函數會回傳 fun 回傳的詞彙。
範例:
1> S = dbg:session_create(my_session).
<0.91.0>
2> dbg:session(S, fun() -> dbg:tracer(), dbg:p(all,c), dbg:tp(lists,seq,x) end).
{ok,[{matched,nonode@nohost,2},{saved,x}]}
3> lists:seq(1, 10).
(<0.89.0>) call lists:seq(1,10)
(<0.89.0>) returned from lists:seq/2 -> [1,2,3,4,5,6,7,8,9,10]
[1,2,3,4,5,6,7,8,9,10]
4> dbg:session_destroy(S).
ok
session/0
的狀態會保留在 session/2
呼叫之間,因此在偵錯應用程式時,您可以多次呼叫 session/2
。
範例:
1> S = dbg:session_create(my_session).
<0.91.0>
%% Setup the initial traces
2> dbg:session(S, fun() -> dbg:tracer(), dbg:p(self(),c), dbg:tp(lists,seq,x) end).
{ok,[{matched,nonode@nohost,2},{saved,x}]}
3> lists:seq(1, 3).
(<0.89.0>) call lists:seq(1,3)
(<0.89.0>) returned from lists:seq/2 -> [1,2,3]
[1,2,3]
%% Add an additional trace pattern
4> dbg:session(S, fun() -> dbg:tpl(lists,seq_loop,x) end).
ok
5> lists:seq(1, 3).
(<0.89.0>) call lists:seq(1,3)
(<0.89.0>) call lists:seq_loop(3,3,[])
(<0.89.0>) call lists:seq_loop(1,1,[2,3])
(<0.89.0>) returned from lists:seq_loop/3 -> [1,2,3]
(<0.89.0>) returned from lists:seq_loop/3 -> [1,2,3]
(<0.89.0>) returned from lists:seq/2 -> [1,2,3]
[1,2,3]
6> dbg:session_destroy(S).
ok
注意
工作階段功能在 Erlang/OTP 27 中是實驗性的,並且在未來的版本中可能會變更,恕不另行通知。
使用指定的 Name
建立新的 dbg
會期。
此會話與呼叫程序連結,並且會
多個會話可以有相同的名稱。
注意
工作階段功能在 Erlang/OTP 27 中是實驗性的,並且在未來的版本中可能會變更,恕不另行通知。
-spec session_destroy(Session :: session()) -> ok.
銷毀 dbg session/0
。
這將會終止所有已啟動的程序,並銷毀 trace:session/0
。
-spec stop() -> ok.
停止 dbg
伺服器,清除所有處理程序的追蹤旗標,清除所有函式的追蹤模式,清除傳送/接收的追蹤模式,關閉所有追蹤用戶端,並關閉所有追蹤埠。
-spec stop_trace_client(Pid) -> ok when Pid :: pid().
關閉先前啟動的追蹤用戶端。
Pid
參數是從 trace_client/2
或 trace_client/3
呼叫返回的程序 ID。
-spec tp(Module | {Module, Function, Arity}, MatchSpec) -> {ok, match_desc()} | {error, term()} when Module :: tp_module(), Function :: tp_function(), Arity :: tp_arity(), MatchSpec :: tp_match_spec().
針對 ModuleOrMFA
指定的一個或多個匯出的函式啟用呼叫追蹤。
如果 ModuleOrMFA
是一個原子(模組名稱),則此函數呼叫等同於 tp({ModuleOrMFA, '_', '_'}, MatchSpec)
。
否則,ModuleOrMFA
應該是 {Module, Function, Arity}
。
tp
代表 trace pattern(追蹤模式)。
所有符合 {Module, Function, Arity}
參數的已匯出函數都會被納入考量,但比對規格可以進一步縮小產生追蹤訊息的函數呼叫集合。
關於 MatchSpec
參數的格式說明,請參閱Erlang 中的比對規格,其中說明了通用比對規格語言。最常用的通用比對規格可以作為內建別名找到;詳細資訊請參閱下方的 ltp/0
。
Tuple 的 Module、Function 和/或 Arity 部分可以指定為原子 '_'
,這是一個萬用字元,會比對所有模組、函數或元數。請注意,如果 Module
指定為 '_'
,則 Function
和 Arity
部分也必須指定為 '_'
。對於 Function
相對於 Arity
的情況也相同。
所有透過 n/1
或 tracer/3
新增的節點都會受到此呼叫的影響,如果 Module
不是 '_'
,則模組將會載入到所有節點上。
此函數會返回錯誤 tuple 或 {ok, List}
tuple。List
由符合的函數數量規格組成,其呈現方式與 p/2
的返回值中的程序和埠相同。
如果 MatchSpec
不是 []
,則返回值中可能會有 tuple {saved, N}
。整數 N
可以在後續對此函數的呼叫中使用,並且會作為給定表達式的「別名」。
如果比對規格無效,則會返回 {error, Errors}
tuple。Errors
是 tuple {error, string()}
的列表,其中字串是編譯錯誤的文字說明。例如
1> dbg:tp({dbg,ltp,0},[{[],[],[{message, two, arguments}, {noexist}]}]).
{error,
[{error,"Special form 'message' called with wrong number of
arguments in {message,two,arguments}."},
{error,"Function noexist/1 does_not_exist."}]}
-spec tp(Module :: tp_module(), Function :: tp_function(), MatchSpec :: tp_match_spec()) -> {ok, match_desc()} | {error, term()}.
-spec tp(Module :: tp_module(), Function :: tp_function(), Arity :: tp_arity(), MatchSpec :: tp_match_spec()) -> {ok, match_desc()} | {error, term()}.
-spec tpe(Event, MatchSpec) -> {ok, MatchDesc :: match_desc()} | {error, term()} when Event :: send | 'receive', MatchSpec :: tp_match_spec().
將匹配規格與追蹤事件 send
或 'receive'
建立關聯。
tpe
代表 trace pattern event(追蹤模式事件)。
預設情況下,如果為程序啟用追蹤,則會追蹤所有已執行的 send
和 'receive'
事件。可以使用比對規格,根據傳送者、接收者和/或訊息內容篩選追蹤的事件。
關於 MatchSpec
參數的格式說明,請參閱Erlang 中的比對規格,其中說明了通用比對規格語言。
對於 send
,比對是在列表 [Receiver, Msg]
上完成。Receiver
是接收者的程序或埠身分,而 Msg
是訊息 term。傳送程序的 pid 可以使用 guard 函數 self/0
存取。
對於 'receive'
,比對是在列表 [Node, Sender, Msg]
上完成。Node
是傳送者的節點名稱。Sender
是傳送者的程序或埠身分,如果傳送者未知(遠端傳送者可能就是這種情況),則為原子 undefined
。Msg
是訊息 term。接收程序的 pid 可以透過呼叫 self/0
來存取。
所有透過 n/1
或 tracer/3
新增的節點都會受到此呼叫的影響。
返回值與 tp/2
的返回值相同。比對到的事件數量永遠是 1,因為 tpe/2
不接受參數 Event
的任何萬用字元形式。
-spec tpl(Module | {Module, Function :: tp_function(), Arity :: tp_arity()}, MatchSpec :: tp_match_spec()) -> {ok, MatchDesc :: term()} | {error, term()} when Module :: tp_module().
針對 ModuleOrMFA
指定的一個或多個函式啟用呼叫追蹤。
如果 ModuleOrMFA
是一個原子(模組名稱),則此函數呼叫等同於 tpl({ModuleOrMFA, '_', '_'}, MatchSpec)
。
否則,ModuleOrMFA
應該是 {Module, Function, Arity}
。
tpl
代表 trace pattern local(追蹤模式本機)。
此函數的作用與 tp/2
相同,但會啟用對本機和已匯出函數的本機或遠端呼叫進行追蹤。
-spec tpl(Module :: tp_module(), Function :: tp_function(), MatchSpec :: tp_match_spec()) -> {ok, match_desc()} | {error, term()}.
-spec tpl(Module :: tp_module(), Function :: tp_function(), Arity :: tp_arity(), MatchSpec :: tp_match_spec()) -> {ok, match_desc()} | {error, term()}.
-spec trace_client(ip, IPClientPortSpec) -> pid() when IPClientPortSpec :: PortNumber | {Hostname, PortNumber}, PortNumber :: integer(), Hostname :: string(); (Type, Parameters) -> pid() when Type :: file | follow_file, Parameters :: Filename | WrapFilesSpec, Filename :: file:name_all(), WrapFilesSpec :: trace_wrap_files_spec().
啟動一個追蹤用戶端,該用戶端讀取追蹤埠驅動程式建立的輸出 (請參閱 trace_port/2
),並以與 tracer/0
函式建立的追蹤程式處理程序大致相同的方式處理輸出。
如果 Type
為 file
,則用戶端會讀取儲存在名為 Filename
或由 WrapFilesSpec
指定的檔案中的所有追蹤訊息(必須與建立追蹤時使用的相同),並讓預設處理函數在主控台上格式化訊息。這是一種解讀檔案追蹤埠驅動程式儲存在檔案中的資料的方式。
如果 Type
為 follow_file
,則用戶端的行為與 file
情況相同,但會持續嘗試從檔案中讀取(和處理)更多資料,直到被 stop_trace_client/1
停止。WrapFilesSpec
不允許作為此 Type
的第二個參數。
如果 Type
為 ip
,則用戶端會連線到主機 Hostname
上的 TCP/IP 埠 PortNumber
,並從該處讀取追蹤訊息,直到 TCP/IP 連線關閉。如果未指定 Hostname
,則假設為本機主機。
例如,可以讓追蹤訊息透過網路傳送到另一個 Erlang 節點(最好不是分散式),在該處進行格式化。
在節點 stack
上,有一個 Erlang 節點 ant@stack
。在 shell 中,輸入以下內容
ant@stack> dbg:tracer(port, dbg:trace_port(ip, 4711)).
<0.17.0>
ant@stack> dbg:p(self(), send).
{ok,1}
現在,所有追蹤訊息都會傳送到追蹤埠驅動程式,該驅動程式會依序偵聽 TCP/IP 埠 4711 上的連線。如果我們想在另一個節點(最好是在另一個主機上)上查看訊息,我們應該這樣做
1> dbg:trace_client(ip, {"stack", 4711}).
<0.42.0>
如果我們現在從節點 ant@stack
上的 shell 傳送訊息(所有從 shell 傳送的訊息都會被追蹤)
ant@stack> self() ! hello.
hello
下列內容將會出現在啟動追蹤用戶端的節點上的主控台中
(<0.23.0>) <0.23.0> ! hello
(<0.23.0>) <0.22.0> ! {shell_rep,<0.23.0>,{value,hello,[],[]}}
最後一行是因為 Erlang shell 中的內部訊息傳遞而產生的。pid 將會有所不同。
-spec trace_client(ip, IPClientPortSpec, HandlerSpec) -> pid() when IPClientPortSpec :: PortNumber | {Hostname, PortNumber}, PortNumber :: integer(), Hostname :: string(), HandlerSpec :: handler_spec(); (Type, Parameters, HandlerSpec) -> pid() when Type :: file | follow_file, Parameters :: Filename | WrapFilesSpec, Filename :: string() | [string()] | atom(), WrapFilesSpec :: trace_wrap_files_spec(), HandlerSpec :: handler_spec().
此函式的作用與 trace_client/2
完全相同,但允許您編寫自己的處理程式函式。
處理函數的運作方式大致與 tracer/2
中描述的相同,但也必須準備好處理 {drop, N}
形式的追蹤訊息,其中 N
是捨棄的訊息數量。只有在使用 ip
追蹤驅動程式時,才會出現此虛擬追蹤訊息。
對於追蹤類型 file
,追蹤結束時會出現虛擬追蹤訊息 end_of_trace
。在這種情況下,會忽略處理函數的返回值。
-spec trace_port(ip, IpPortSpec) -> fun(() -> port()) when IpPortSpec :: PortNumber | {PortNumber, QueSize}, PortNumber :: integer(), QueSize :: integer(); (file, Parameters) -> fun(() -> port()) when Parameters :: Filename | WrapFilesSpec, Filename :: file:name_all(), WrapFilesSpec :: trace_wrap_files_spec().
建立一個追蹤埠產生函式,該函式適合做為 tracer/2
的第二個引數。
範例
dbg:tracer(port, dbg:trace_port(ip, 4711)).
追蹤埠是一個 Erlang 埠,指向直接處理追蹤訊息的動態連結驅動程式,而無需將它們作為訊息傳送到 Erlang 程序的額外負擔。使用追蹤埠可以顯著降低追蹤帶來的額外負擔。
目前實作了兩個追蹤驅動程式:file
和 ip
追蹤驅動程式。
file
驅動程式會將所有追蹤訊息傳送到一個或多個二進位檔案中,然後可以使用 trace_client/2
函數從中擷取和處理這些訊息。
ip
驅動程式會開啟一個 TCP/IP 埠偵聽埠。當用戶端(最好透過在另一個 Erlang 節點上呼叫 trace_client/2
來啟動)連線時,所有追蹤訊息都會透過 IP 網路傳送,以便遠端用戶端進一步處理。
file
追蹤驅動程式需要一個檔案名稱或一個包裝檔案規格作為參數。檔案寫入時具有高度的緩衝,這就是為什麼在系統崩潰的情況下,無法保證所有檔案都已儲存的原因。
包裝檔案規格用於限制追蹤所消耗的磁碟空間。追蹤會寫入有限數量的檔案,每個檔案的大小有限。實際的檔案名稱為 Filename ++ SeqCnt ++ Suffix
,其中 SeqCnt
會以十進位字串的形式從 0
計數到 WrapCnt
,然後再從 0
開始循環。當寫入目前檔案的追蹤 term 使其長度超過 WrapSize
時,該檔案會關閉,如果此包裝追蹤中的檔案數量與 WrapCnt
一樣多,則會刪除最舊的檔案,並開啟新檔案以成為目前的檔案。因此,當包裝追蹤停止時,最多會有 WrapCnt
個追蹤檔案儲存,其大小至少為 WrapSize
(但不會大太多),但最後一個檔案甚至可能是空的。預設值為 WrapSize = 128*1024
和 WrapCnt = 8
。
檔案名稱中的 SeqCnt
值都在 0
到 WrapCnt
的範圍內,並且在循環序列中存在間隙。需要間隙來尋找追蹤的結尾。
如果將 WrapSize
指定為 {time, WrapTime}
,則目前的檔案會在開啟超過 WrapTime
毫秒時關閉,無論其是否為空。
ip
追蹤驅動程式有一個 QueSize
訊息的佇列,等待傳遞。如果驅動程式無法以執行階段系統產生的速度傳遞訊息,則會傳送一條特殊訊息,指出捨棄了多少訊息。該訊息將會以 tuple {drop, N}
的形式到達 trace_client/3
中指定的處理函數,其中 N
是捨棄的連續訊息數量。在大量追蹤的情況下,很可能會發生捨棄,如果沒有用戶端正在讀取追蹤訊息,則肯定會發生捨棄。QueSize
的預設值為 200。
-spec trace_port_control(Nodename :: node(), Operation :: term()) -> ok | {ok, Result :: term()} | {error, Reason :: term()}.
此函式用於在給定節點 (Nodename
) 上的作用中追蹤埠驅動程式執行控制操作。
允許哪些操作以及其返回值取決於使用的追蹤驅動程式。
如果操作成功,則返回 ok
或 {ok, Result}
,如果目前的追蹤器是一個程序,或是如果它是 不支援該操作的埠,則返回 {error, Reason}
。
Operation
的允許值如下
flush
- 此函數用於刷新追蹤埠驅動程式持有的內部緩衝區。目前只有file
追蹤驅動程式支援此操作。返回ok
。get_listen_port
- 返回{ok, IpPort}
,其中IpPort
是驅動程式監聽 socket 使用的 IP 連接埠號碼。只有ip
追蹤驅動程式支援此操作。
-spec tracer() -> {ok, pid()} | {error, already_started}.
在本地節點上啟動一個伺服器,該伺服器將成為所有追蹤訊息的接收者。
所有後續對 p/2
的呼叫都會導致訊息傳送到新啟動的追蹤伺服器。
以這種方式啟動的追蹤伺服器只會顯示 Erlang shell 中格式化的追蹤訊息(也就是使用 io:format/2
)。關於如何自訂追蹤訊息處理常式,請參閱 tracer/2
。
若要在遠端節點上啟動類似的追蹤器,請使用 n/1
。
-spec tracer(port, PortGenerator) -> {ok, pid()} | {error, Error :: term()} when PortGenerator :: fun(() -> port()); (process, HandlerSpec) -> {ok, pid()} | {error, Error :: term()} when HandlerSpec :: {HandlerFun, InitialData :: term()}, HandlerFun :: fun((Event :: term(), Data :: term()) -> NewData :: term()); (module, ModuleSpec) -> {ok, pid()} | {error, Error :: term()} when ModuleSpec :: fun(() -> {TracerModule, TracerState}) | {TracerModule, TracerState}, TracerModule :: atom(), TracerState :: term(); (file, Filename) -> {ok, pid()} | {error, Error :: term()} when Filename :: file:name_all().
在本地節點上使用其他參數啟動追蹤程式伺服器。
Type
表示應如何處理追蹤訊息
process
- 由接收程序處理port
- 由連接埠處理;請參閱trace_port/2
module
- 由追蹤器模組處理;請參閱erl_tracer
file
- 將其列印到檔案
如果 Type
是 process
,Data
應該是一個訊息處理常式函式 (HandlerSpec
)。對於每個追蹤訊息,都會呼叫處理常式函式 (應該是一個接受兩個參數的 fun
),第一個參數包含訊息本身,第二個參數包含上次呼叫該函式的返回值。HandlerSpec
的 InitialData
部分指定了第二個參數的初始值。 HandlerFun
可以選擇在被呼叫時採取任何適當的操作,並且可以通過返回它來保存下一次呼叫的狀態。
如果 Type
是 port
,則第二個參數應該是一個不帶參數的 fun,在呼叫時返回一個新開啟的追蹤連接埠。此類 fun 最好通過呼叫 trace_port/2
來產生。
如果 Type
是 module
,則 Data
應該是一個 tuple,描述用於追蹤的 erl_tracer
模組以及該追蹤器模組要使用的狀態,或是一個返回該類 tuple 的 fun。
如果 Type
是 file
,則 Data
應該是一個檔案名稱,指定所有追蹤將列印到的檔案。
如果返回錯誤,可能是因為追蹤伺服器已經在執行 ({error,already_started}
),或因為 HandlerFun
引發了例外。
若要在遠端節點上啟動類似的追蹤器,請使用 tracer/3
。
-spec tracer(Nodename :: node(), Type :: term(), Data :: term()) -> {ok, Nodename :: node()} | {error, Reason :: term()}.
此函式等同於 tracer/2
,但在指定的節點上執行動作。
追蹤器會在節點 (Nodename
) 上啟動,且該節點會新增到追蹤節點列表中。
注意
此函式與
n/1
不等效。雖然n/1
啟動一個將所有追蹤資訊重新導向到本地節點(即追蹤控制節點)上的程序追蹤器的程序追蹤器,但tracer/3
會啟動任何類型的追蹤器,而與追蹤控制節點上的追蹤器類型無關。
詳細資訊,請參閱 tracer/2
。
將會期期間儲存的所有匹配規格 (透過呼叫 tp/2
或 tpl/2
) 以及內建的匹配規格,儲存到名稱由 Name
指定的文字檔中。
wtp
代表 write trace patterns(寫入追蹤模式)。
該檔案的格式是文字格式,這表示可以使用文字編輯器進行編輯,然後使用 rtp/1
還原。
檔案中的每個比對規格都以句點 (.
) 結尾,並且可以手動將新的(語法正確的)比對規格新增到檔案中。
該函式返回 ok
,或一個錯誤 tuple,其中第二個元素表示寫入檔案失敗的原因。