檢視原始碼 追蹤工具建構器
簡介
追蹤工具建構器是為單節點或分散式 Erlang 系統建立追蹤工具的基礎。它需要被追蹤節點上可用的 Runtime_Tools 應用程式。
以下是追蹤工具建構器的主要功能:
- 透過一個函式呼叫,在多個節點上開始追蹤到檔案埠。
- 將更多資訊寫入追蹤資訊檔案,該檔案在格式化期間會被讀取。
- 透過維護歷史緩衝區和處理組態檔案,來還原先前的組態。
- 為循序追蹤提供一些簡單的支援。
- 格式化二進位追蹤日誌,並合併來自多個節點的日誌。
追蹤工具建構器的目的是作為客製化追蹤工具的基礎,但它也可以直接從 Erlang shell 使用(它可以模擬 dbg
的行為,同時仍然提供有用的附加功能,例如比對規格捷徑)。追蹤工具建構器僅允許使用檔案埠追蹤器,因此若要使用其他類型的追蹤用戶端,最好直接使用 dbg
。
開始使用
模組 ttb
是追蹤工具建構器中所有函式的介面。
若要開始使用,您至少需要做的就是使用 ttb:tracer/0,1,2
啟動追蹤器,並使用 ttb:p/2
在您要追蹤的處理序上設定所需的追蹤旗標。
追蹤完成後,請使用 ttb:stop/0,1
停止追蹤器,並使用 ttb:format/1,2
格式化追蹤日誌(如果有的話)。
有用的函式
ttb:tracer/0,1,2
- 在每個要追蹤的節點上開啟追蹤埠。預設情況下,追蹤訊息會寫入遠端節點上的二進位檔案(二進位追蹤日誌)。ttb:p/2
- 指定要追蹤的處理序。在此呼叫中指定的追蹤旗標會指定要在每個處理序上追蹤的內容。如果您希望在不同的處理序上設定不同的追蹤旗標,可以多次呼叫此函式。ttb:tp/2,3,4
或ttb:tpl/2,3,4
- 如果您想要追蹤函式呼叫(也就是說,如果您在任何處理序上設定了追蹤旗標call
),您還必須使用ttb:tp/2,3,4
或ttb:tpl/2,3,4
在所需的函式上設定追蹤模式。只有當函式具有追蹤模式時才會被追蹤。追蹤模式會指定如何使用比對規格追蹤函式。比對規格在 ERTS 使用者指南 中描述。ttb:stop/0,1
- 停止所有節點上的追蹤,刪除所有追蹤模式,並刷新追蹤埠緩衝區。ttb:format/1/2
- 將二進位追蹤日誌轉換為可讀取的內容。預設情況下,ttb
會將每個追蹤訊息呈現為一行文字,但您也可以編寫自己的處理常式來對追蹤資訊進行更複雜的解釋。追蹤日誌也可以使用應用程式事件追蹤器 (ET) 以圖形方式呈現。如果選項
format
指定給ttb:stop/1
,則在停止ttb
時會自動完成格式化。
從 Erlang Shell 追蹤本機節點
以下的小模組用於後續範例
-module(m).
-export([f/0]).
f() ->
receive
From when is_pid(From) ->
Now = erlang:now(),
From ! {self(),Now}
end.
以下範例顯示了從 Erlang shell 使用 ttb
的基本用法。追蹤器的啟動和格式化都使用預設選項(但是提供了自訂提取目錄)。這會在新建立的目錄中產生一個名為 Node-ttb
的追蹤日誌,其中 Node
是節點名稱。預設處理常式會在 shell 中列印格式化的追蹤訊息
(tiger@durin)47> %% First I spawn a process running my test function
(tiger@durin)47> Pid = spawn(m,f,[]).
<0.125.0>
(tiger@durin)48>
(tiger@durin)48> %% Then I start a tracer...
(tiger@durin)48> ttb:tracer().
{ok,[tiger@durin]}
(tiger@durin)49>
(tiger@durin)49> %% and activate the new process for tracing
(tiger@durin)49> %% function calls and sent messages.
(tiger@durin)49> ttb:p(Pid,[call,send]).
{ok,[{<0.125.0>,[{matched,tiger@durin,1}]}]}
(tiger@durin)50>
(tiger@durin)50> %% Here I set a trace pattern on erlang:now/0
(tiger@durin)50> %% The trace pattern is a simple match spec
(tiger@durin)50> %% indicating that the return value should be
(tiger@durin)50> %% traced. Refer to the reference_manual for
(tiger@durin)50> %% the full list of match spec shortcuts
(tiger@durin)50> %% available.
(tiger@durin)51> ttb:tp(erlang,now,return).
{ok,[{matched,tiger@durin,1},{saved,1}]}
(tiger@durin)52>
(tiger@durin)52> %% I run my test (i.e. send a message to
(tiger@durin)52> %% my new process)
(tiger@durin)52> Pid ! self().
<0.72.0>
(tiger@durin)53>
(tiger@durin)53> %% And then I have to stop ttb in order to flush
(tiger@durin)53> %% the trace port buffer
(tiger@durin)53> ttb:stop([return, {fetch_dir, "fetch"}]).
{stopped, "fetch"}
(tiger@durin)54>
(tiger@durin)54> %% Finally I format my trace log
(tiger@durin)54> ttb:format("fetch").
({<0.125.0>,{m,f,0},tiger@durin}) call erlang:now()
({<0.125.0>,{m,f,0},tiger@durin}) returned from erlang:now/0 ->
{1031,133451,667611}
({<0.125.0>,{m,f,0},tiger@durin}) <0.72.0> !
{<0.125.0>,{1031,133451,667611}}
ok
建立您自己的工具
以下範例顯示了一個用於「偵錯追蹤」的簡單工具,也就是追蹤具有傳回值的函式呼叫
-module(mydebug).
-export([start/0,trc/1,stop/0,format/1]).
-export([print/4]).
%% Include ms_transform.hrl so that I can use dbg:fun2ms/2 to
%% generate match specifications.
-include_lib("stdlib/include/ms_transform.hrl").
%%% -------------Tool API-------------
%%% ----------------------------------
%%% Star the "mydebug" tool
start() ->
%% The options specify that the binary log shall be named
%% <Node>-debug_log and that the print/4 function in this
%% module shall be used as format handler
ttb:tracer(all,[{file,"debug_log"},{handler,{{?MODULE,print},0}}]),
%% All processes (existing and new) shall trace function calls
%% We want trace messages to be sorted upon format, which requires
%% timestamp flag. The flag is however enabled by default in ttb.
ttb:p(all,call).
%%% Set trace pattern on function(s)
trc(M) when is_atom(M) ->
trc({M,'_','_'});
trc({M,F}) when is_atom(M), is_atom(F) ->
trc({M,F,'_'});
trc({M,F,_A}=MFA) when is_atom(M), is_atom(F) ->
%% This match spec shortcut specifies that return values shall
%% be traced.
MatchSpec = dbg:fun2ms(fun(_) -> return_trace() end),
ttb:tpl(MFA,MatchSpec).
%%% Format a binary trace log
format(Dir) ->
ttb:format(Dir).
%%% Stop the "mydebug" tool
stop() ->
ttb:stop(return).
%%% --------Internal functions--------
%%% ----------------------------------
%%% Format handler
print(_Out,end_of_trace,_TI,N) ->
N;
print(Out,Trace,_TI,N) ->
do_print(Out,Trace,N),
N+1.
do_print(Out,{trace_ts,P,call,{M,F,A},Ts},N) ->
io:format(Out,
"~w: ~w, ~w:~n"
"Call : ~w:~w/~w~n"
"Arguments :~p~n~n",
[N,Ts,P,M,F,length(A),A]);
do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
io:format(Out,
"~w: ~w, ~w:~n"
"Return from : ~w:~w/~w~n"
"Return value :~p~n~n",
[N,Ts,P,M,F,A,R]).
為了區分使用此工具產生的追蹤日誌和其他日誌,在 tracer/2
中使用了選項 file
。因此,日誌會被提取到名為 ttb_upload_debug_log-YYYYMMDD-HHMMSS
的目錄中
透過在啟動追蹤器時使用選項 handler
,有關如何格式化檔案的資訊會儲存在追蹤資訊檔案 (.ti
) 中。這並非必要,因為它可以在格式化時指定。但是,如果您想要使用 ttb:stop/1
中的選項 format
自動格式化追蹤日誌,這可能會很有用。此外,您不需要任何二進位日誌內容的知識,就可以按照預期的方式格式化它。如果在啟動追蹤器和格式化時都指定了選項 handler
,則會使用格式化時指定的選項。
追蹤旗標 call
設定在所有處理序上。這表示任何使用命令 trc/1
啟動的函式都會在所有現有和新的處理序上追蹤。
針對遠端節點執行追蹤工具建構器
Observer 應用程式可能不一定在要追蹤的節點上可用(以下稱為「被追蹤節點」)。但是,只要滿足以下條件,追蹤工具建構器仍然可以從另一個節點執行(以下稱為「追蹤控制節點」)
- Observer 應用程式在追蹤控制節點上可用。
- Runtime_Tools 應用程式在追蹤控制節點和被追蹤節點上都可用。
如果要針對遠端節點使用追蹤工具建構器,強烈建議將追蹤控制節點啟動為隱藏。這樣,它就可以連接到被追蹤節點,而不會被它「看到」,也就是說,如果在被追蹤節點上呼叫 nodes/0
BIF,追蹤控制節點不會顯示。若要啟動隱藏節點,請將選項 -hidden
新增至 erl
命令,例如
% erl -sname trace_control -hidden
無磁碟節點
如果被追蹤節點是無磁碟的,則必須從具有磁碟存取的追蹤控制節點啟動 ttb
,並且必須將選項 file
指定給函式 tracer/2
,其值為 {local, File}
,例如
(trace_control@durin)1> ttb:tracer(mynode@diskless,
{file,{local,{wrap,"mytrace"}}}).
{ok,[mynode@diskless]}
更多追蹤選項
設定追蹤時,也可以啟動以下功能
- 時間限制追蹤
- 過載保護
- 自動恢復
dbg
模式
時間限制追蹤
有時啟用指定時間段的追蹤可能會很有幫助(例如,監控系統 24 小時或半秒)。可以使用選項 {timer, TimerSpec}
來完成此操作。如果 TimerSpec
的形式為 MSec
,則在使用 ttb:stop/0
後,追蹤會在 MSec
毫秒後停止。如果提供了更多選項 (TimerSpec = {MSec, Opts}
),則會改為使用 Opts
作為引數呼叫 ttb:stop/1
。
計時器會隨著 ttb:p/2
一起啟動,因此任何追蹤模式都必須預先設定。ttb:start_trace/4
總是在呼叫 ttb:p/2
之前設定所有模式。
以下範例顯示如何設定在 5 秒後自動停止和格式化的追蹤
(tiger@durin)1> ttb:start_trace([node()],
[{erlang, now,[]}],
{all, call},
[{timer, {5000, format}}]).
注意
由於網路和處理延遲,追蹤的期間是近似的。
過載保護
追蹤即時系統時,始終要特別注意不要因追蹤過於繁重而使節點過載。ttb
提供選項 overload
來解決此問題。
{overload, MSec, Module, Function}
指示 ttb
後端(Runtime_Tools 應用程式的一部分)每 MSec
毫秒執行一次過載檢查。如果檢查(名為 Module:Function(check)
)傳回 true
,則會在選取的節點上停用追蹤。
在一個節點上啟動的過載保護不會影響其他節點,在其他節點上,追蹤會照常繼續。ttb:stop/0
會從所有用戶端提取資料,包括在啟動過載保護之前收集的所有資料。
注意
一旦在其中一個被追蹤節點中啟動過載保護,就不允許變更追蹤詳細資訊(使用
ttb:p/2
和ttb:tp/tpl...
)。這是為了避免節點之間的追蹤設定不一致。
選項 overload
提供的 Module:Function
必須處理三個呼叫:init
、check
和 stop
。init
和 stop
允許檢查所需的一些設定和解除設定。過載檢查模組可能如下所示
-module(overload).
-export([check/1]).
check(init) ->
Pid = sophisticated_module:start(),
put(pid, Pid);
check(check) ->
get(pid) ! is_overloaded,
receive
Reply ->
Reply
after 5000 ->
true
end;
check(stop) ->
get(pid) ! stop.
注意
check
始終由同一個處理序呼叫,因此put
和get
是可行的。
自動恢復
節點可能會崩潰(可能是有錯誤的節點,因此會被追蹤)。使用 resume
在節點恢復時自動恢復對該節點的追蹤。當 Runtime_Tools
啟動時,失敗的節點會嘗試重新連接到追蹤控制節點。這表示 Runtime_Tools
必須包含在其他節點的啟動鏈中(如果沒有,您仍然可以透過手動啟動 Runtime_Tools
來恢復追蹤,也就是說,透過 RPC 呼叫)。
為了不遺失故障節點在當機前所儲存的資料,控制節點會在重新啟動追蹤之前嘗試擷取這些資料。此動作必須在允許的時間範圍內完成,否則會中止 (預設為 10 秒,但可以使用 {resume, MSec}
來變更)。以這種方式擷取的資料會與所有其他追蹤合併。
自動啟動功能需要在被追蹤的節點上儲存更多資料。預設情況下,資料會自動儲存到被追蹤節點目前工作目錄 (cwd) 中名為 "ttb_autostart.bin" 的檔案。使用者可以透過指定自己的模組來處理自動啟動資料的儲存和擷取 (即在無磁碟節點上),來變更此行為 (runtime_tools
的 ttb_autostart_module
環境變數)。關於 API 的資訊,請參閱模組 ttb
。以下範例顯示預設的處理器
-module(ttb_autostart).
-export([read_config/0,
write_config/1,
delete_config/0]).
-define(AUTOSTART_FILENAME, "ttb_autostart.bin").
delete_config() ->
file:delete(?AUTOSTART_FILENAME).
read_config() ->
case file:read_file(?AUTOSTART_FILENAME) of
{ok, Data} -> {ok, binary_to_term(Data)};
Error -> Error
end.
write_config(Data) ->
file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)).
注意
請記住,檔案追蹤埠預設會緩衝資料。如果節點當機,追蹤訊息不會清除到二進位記錄檔中。如果故障風險很高,最好每隔一段時間自動清除緩衝區。將
{flush, MSec}
作為ttb:tracer/2
的選項傳遞,會每MSec
毫秒清除所有緩衝區。
dbg 模式
選項 {shell, ShellType}
可讓 ttb
的操作類似於 dbg
。使用 {shell, true}
會在儲存所有追蹤訊息之前將其顯示在 Shell 中。{shell, only}
還會停用訊息儲存 (使工具的行為完全像 dbg
)。只有 IP 追蹤埠 ({trace, {local, File}}
) 才允許這樣做。
指令 ttb:tracer(dbg)
是純 dbg
模式 ({shell, only}
) 的快捷方式。
追蹤資訊和檔案 .ti
除了追蹤記錄檔之外,當 Trace Tool Builder 啟動時,還會建立一個擴展名為 .ti
的檔案。這就是追蹤資訊檔案。它是一個二進位檔案,其中包含程序資訊、使用的追蹤標誌、所屬節點的名稱,以及使用函數 ttb:write_trace_info/2
寫入的所有資訊。.ti
檔案在停止追蹤時總是會與其他記錄檔一起擷取。
除了程序資訊之外,追蹤資訊檔案中的所有內容都會在格式化時傳遞到處理器函數。參數 TI
是 {Key,ValueList}
元組的列表。金鑰 flags
、handler
、file
和 node
用於 ttb
直接寫入的資訊。
可以透過呼叫 ttb:write_trace_info/2
將資訊新增到追蹤資訊檔案。請注意,ValueList
始終是一個列表,如果您使用相同的 Key
多次呼叫 write_trace_info/2
,則每次都會使用新值擴展 ValueList
。
範例
ttb:write_trace_info(mykey,1)
在 TI
中產生 {mykey,[1]}
的項目。另一個呼叫 ttb:write_trace_info(mykey,2)
會將此項目變更為 {mykey,[1,2]}
。
環繞記錄
如果您想限制追蹤記錄的大小,可以使用環繞記錄。它的運作方式幾乎與循環緩衝區相同。您可以指定二進位記錄的最大數量和每個記錄的最大大小。ttb
接著會在每次記錄達到最大大小時建立新的二進位記錄。當達到最大記錄數時,會在建立新記錄之前刪除最舊的記錄。
注意
ttb
產生的資料總大小可能大於環繞規格所建議的大小。如果被追蹤的節點重新啟動且啟用自動恢復,則始終會儲存舊的環繞記錄,並建立新的記錄。
環繞記錄可以逐個或一次全部格式化。請參閱格式化。
格式化
格式化可以在停止 ttb
時自動完成 (請參閱 自動從所有節點收集和格式化記錄 一節),或透過呼叫函數 ttb:format/1,2
明確完成。
格式化是指讀取二進位記錄並以可讀的格式呈現。您可以使用 ttb
中的預設格式處理器,將每個追蹤訊息呈現為一行文字,或撰寫自己的處理器來對追蹤資訊進行更複雜的解釋。您也可以使用應用程式 ET 以圖形方式呈現追蹤記錄 (請參閱 使用事件追蹤器呈現追蹤記錄 一節)。
ttb:format/1,2
的第一個參數指定要格式化哪些二進位記錄。這通常是 ttb
在記錄擷取期間建立的目錄名稱。除非提供選項 disable_sort
,否則不同檔案中的記錄始終會根據追蹤中的時間戳記排序。
ttb:format/2
的第二個參數是選項列表,如下所示
out
- 指定寫入格式化文字的目的地。預設目的地為standard_io
,但也可以指定檔案名稱。handler
- 指定要使用的格式處理器。如果未指定此選項,則會使用啟動追蹤器時指定的選項handler
。如果啟動追蹤器時也未指定選項handler
,則會使用預設處理器,它會將每個追蹤訊息列印為文字行。disable_sort
- 表示不會根據時間戳記合併記錄,而是逐個處理檔案 (這可能會稍微快一點)。
格式處理器是一個接受四個參數的函數。會針對二進位記錄中的每個追蹤訊息呼叫此函數。一個只列印每個追蹤訊息的簡單範例如下
fun(Fd, Trace, _TraceInfo, State) ->
io:format(Fd, "Trace: ~p~n", [Trace]),
State
end.
在這裡,Fd
是目的地檔案的檔案描述符,或原子 standard_io
。_TraceInfo
包含來自追蹤資訊檔案的資訊 (請參閱追蹤資訊和檔案 .ti一節)。State
是格式處理器函數的狀態變數。變數 State
的初始值是在處理器選項中指定的,例如
ttb:format("tiger@durin-ttb", [{handler, {{Mod,Fun}, initial_state}}])
^^^^^^^^^^^^^
可以使用另一個格式處理器來計算垃圾收集器所花費的時間
fun(_Fd,{trace_ts,P,gc_start,_Info,StartTs},_TraceInfo,State) ->
[{P,StartTs}|State];
(Fd,{trace_ts,P,gc_end,_Info,EndTs},_TraceInfo,State) ->
{value,{P,StartTs}} = lists:keysearch(P,1,State),
Time = diff(StartTs,EndTs),
io:format("GC in process ~w: ~w milliseconds~n", [P,Time]),
State -- [{P,StartTs}]
end
這個格式處理器的更精細版本是 Observer 應用程式 src
目錄中包含的 multitrace.erl
模組中的函數 handle_gc/4
。
追蹤訊息會作為第二個參數 (Trace
) 傳遞。Trace
的可能值如下
erlang:trace/3
中描述的所有追蹤訊息- 如果使用 IP 追蹤器 (請參閱
dbg:trace_port/2
),則為{drop, N}
- 當處理完所有追蹤訊息時,會收到一次
end_of_trace
透過提供格式處理器 ttb:get_et_handler()
,您可以使用 ET 應用程式中的 et_viewer
以圖形方式呈現追蹤記錄 (請參閱使用事件追蹤器呈現追蹤記錄一節)。
您始終可以決定不格式化擷取目錄中包含的整個追蹤資料,而是分析單個檔案。若要這樣做,必須將單個檔案 (或檔案列表) 作為 format/1,2
的第一個參數傳遞。
環繞記錄可以逐個或一次全部格式化。若要格式化一組環繞記錄中的一個,請指定確切的檔案名稱。若要格式化整組環繞記錄,請指定名稱,並使用 *
取代環繞計數。
範例
開始追蹤
(tiger@durin)1> ttb:tracer(node(),{file,{wrap,"trace"}}).
{ok,[tiger@durin]}
(tiger@durin)2> ttb:p(...)
...
這會產生一組二進位記錄,例如
tiger@durin-trace.0.wrp
tiger@durin-trace.1.wrp
tiger@durin-trace.2.wrp
...
格式化整組記錄
1> ttb:format("tiger@durin-trace.*.wrp").
....
ok
2>
僅格式化第一個記錄
1> ttb:format("tiger@durin-trace.0.wrp").
....
ok
2>
若要合併來自兩個節點的所有環繞記錄
1> ttb:format(["tiger@durin-trace.*.wrp","lion@durin-trace.*.wrp"]).
....
ok
2>
使用事件追蹤器呈現追蹤記錄
有關事件追蹤器的詳細資訊,請參閱 ET 應用程式。
透過提供格式處理器 ttb:get_et_handler()
,您可以使用 ET 應用程式中的 et_viewer
以圖形方式呈現追蹤記錄。ttb
提供可以從 et_viewer
視窗中的 *篩選器* 選單中選取的篩選器。篩選器會根據它們呈現的參與者類型 (也就是說,序列圖中每條垂直線代表的內容) 來命名。參與者之間的互動會顯示為兩條垂直線之間的紅色箭頭,參與者內部的活動會顯示為參與者線條右側的藍色文字。
processes
篩選器是唯一顯示追蹤記錄中所有追蹤訊息的篩選器。序列圖中的每條垂直線都代表一個程序。Erlang 訊息、產生和連結/取消連結是程序之間典型的互動。函式呼叫、排程和垃圾收集是程序內典型的活動。processes
是預設篩選器。
其餘篩選器僅顯示函式呼叫和函式傳回。所有其他追蹤訊息都會被捨棄。為了充分利用這些篩選器,et_viewer
必須知道每個函式的呼叫者和傳回時間。可以使用追蹤時的 call
和 return_to
標誌來取得此資訊。請注意,標誌 return_to
僅適用於本機呼叫追蹤,也就是說,當追蹤模式設定為 ttb:tpl
時。
透過僅使用標誌 call
並在本機或全域函式呼叫上設定匹配規格,可以獲得相同的結果,如下所示
1> dbg:fun2ms(fun(_) -> return_trace(),message(caller()) end).
[{'_',[],[{return_trace},{message,{caller}}]}]
但是,必須謹慎執行此操作,因為匹配規格中的函式 {return_trace}
會破壞尾遞迴。
modules
過濾器會在循序圖中將每個模組顯示為一條垂直線。外部函式呼叫/返回會顯示為模組之間的互動,而內部函式呼叫/返回則會顯示為模組內的活動。
functions
過濾器會在循序圖中將每個函式顯示為一條垂直線。函式呼叫自身會顯示為函式內的活動,而所有其他函式呼叫則會顯示為函式之間的互動。
mods_and_procs
和 funcs_and_procs
過濾器分別等同於 modules
和 functions
過濾器,但每個模組或函式可以有多條垂直線,每個執行所在的處理程序各一條。
在以下範例中,會使用模組 foo
和 bar
-module(foo).
-export([start/0,go/0]).
start() ->
spawn(?MODULE, go, []).
go() ->
receive
stop ->
ok;
go ->
bar:f1(),
go()
end.
-module(bar).
-export([f1/0,f3/0]).
f1() ->
f2(),
ok.
f2() ->
spawn(?MODULE,f3,[]).
f3() ->
ok.
設定追蹤
(tiger@durin)1> %%First we retrieve the Pid to limit traced processes set
(tiger@durin)1> Pid = foo:start().
(tiger@durin)2> %%Now we set up tracing
(tiger@durin)2> ttb:tracer().
(tiger@durin)3> ttb:p(Pid, [call, return_to, procs, set_on_spawn]).
(tiger@durin)4> ttb:tpl(bar, []).
(tiger@durin)5> %%Invoke our test function and see output with et viewer
(tiger@durin)5> Pid ! go.
(tiger@durin)6> ttb:stop({format, {handler, ttb:get_et_handler()}}).
這會呈現類似以下的結果
請注意,函式 ttb:start_trace/4
可以作為協助,如下所示
(tiger@durin)1> Pid = foo:start().
(tiger@durin)2> ttb:start_trace([node()],
[{bar,[]}],
{Pid, [call, return_to, procs, set_on_spawn]}
{handler, ttb:get_et_handler()}).
(tiger@durin)3> Pid ! go.
(tiger@durin)4> ttb:stop(format).
自動從所有節點收集和格式化日誌
預設情況下,ttb:stop/1
會從所有節點擷取追蹤日誌和追蹤資訊檔案。日誌會儲存在追蹤控制節點的工作目錄下,名為 ttb_upload-Filename-Timestamp
的新目錄中。可以透過為 ttb:stop/1
提供選項 nofetch
來停用擷取。使用者可以透過傳遞選項 {fetch_dir, Dir}
來指定擷取目錄。
如果為 ttb:stop/1
指定選項 format
,則追蹤日誌會在停止追蹤後自動格式化。
歷史記錄和組態檔案
對於追蹤功能,可以使用 dbg
而不是 ttb
,來設定處理程序的追蹤旗標和呼叫追蹤的追蹤模式,也就是函式 p
、tp
、tpl
、ctp
、ctpl
和 ctpg
。ttb
為這些函式僅新增以下兩件事
- 所有呼叫都儲存在歷史記錄緩衝區中,可以重新呼叫並儲存在組態檔案中。這樣可以輕鬆設定相同的追蹤環境,例如,如果您想要比較兩個測試執行。也可以減少從 Erlang Shell 使用
ttb
時的輸入量。 - 為最常見的匹配規格提供快捷方式(以便不強制您持續使用
dbg:fun2ms
)。
使用 ttb:list_history/0
來檢視歷史記錄緩衝區的內容,並使用 ttb:run_history/1
重新執行其中一個項目。
歷史記錄緩衝區的主要目的是建立組態檔案的可能性。儲存在歷史記錄緩衝區中的任何函式都可以寫入組態檔案,並用於隨時透過單一函式呼叫建立特定的組態。
組態檔案是透過 ttb:write_config/2,3
建立或延伸的。組態檔案是二進位檔案,因此只能使用 ttb
提供的函式讀取和寫入。
可以透過呼叫 ttb:write_config(ConfigFile,all)
將歷史記錄緩衝區的完整內容寫入組態檔案。可以透過呼叫 ttb:write_config(ConfigFile,NumList)
來寫入從歷史記錄選取的項目,其中 NumList
是一個整數列表,指向要寫入的歷史記錄項目。此外,當呼叫 ttb:stop/0,1
時,歷史記錄緩衝區會始終傾印至 ttb_last_config
。
也可以透過呼叫函式 ttb:write_config(ConfigFile,ConfigList)
將使用者定義的項目寫入組態檔案,其中 ConfigList
是 {Module,Function,Args}
的列表。
當呼叫 write_config/2
時,任何現有的檔案 ConfigFile
都會被刪除並建立新檔案。可以使用選項 append
將內容新增至現有組態檔案的末尾,例如 ttb:write_config(ConfigFile,What,[append])
。
範例
檢視歷史記錄緩衝區的內容
(tiger@durin)191> ttb:tracer().
{ok,[tiger@durin]}
(tiger@durin)192> ttb:p(self(),[garbage_collection,call]).
{ok,{[<0.1244.0>],[garbage_collection,call]}}
(tiger@durin)193> ttb:tp(ets,new,2,[]).
{ok,[{matched,1}]}
(tiger@durin)194> ttb:list_history().
[{1,{ttb,tracer,[tiger@durin,[]]}},
{2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}},
{3,{ttb,tp,[ets,new,2,[]]}}]
執行歷史記錄緩衝區中的項目
(tiger@durin)195> ttb:ctp(ets,new,2).
{ok,[{matched,1}]}
(tiger@durin)196> ttb:list_history().
[{1,{ttb,tracer,[tiger@durin,[]]}},
{2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}},
{3,{ttb,tp,[ets,new,2,[]]}},
{4,{ttb,ctp,[ets,new,2]}}]
(tiger@durin)197> ttb:run_history(3).
ttb:tp(ets,new,2,[]) ->
{ok,[{matched,1}]}
將歷史記錄緩衝區的內容寫入組態檔案
(tiger@durin)198> ttb:write_config("myconfig",all).
ok
(tiger@durin)199> ttb:list_config("myconfig").
[{1,{ttb,tracer,[tiger@durin,[]]}},
{2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}},
{3,{ttb,tp,[ets,new,2,[]]}},
{4,{ttb,ctp,[ets,new,2]}},
{5,{ttb,tp,[ets,new,2,[]]}}]
延伸現有的組態
(tiger@durin)200> ttb:write_config("myconfig",[{ttb,tp,[ets,delete,1,[]]}],
[append]).
ok
(tiger@durin)201> ttb:list_config("myconfig").
[{1,{ttb,tracer,[tiger@durin,[]]}},
{2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}},
{3,{ttb,tp,[ets,new,2,[]]}},
{4,{ttb,ctp,[ets,new,2]}},
{5,{ttb,tp,[ets,new,2,[]]}},
{6,{ttb,tp,[ets,delete,1,[]]}}]
在停止 Trace Tool Builder 後返回先前的組態
(tiger@durin)202> ttb:stop().
ok
(tiger@durin)203> ttb:run_config("myconfig").
ttb:tracer(tiger@durin,[]) ->
{ok,[tiger@durin]}
ttb:p(<0.1244.0>,[garbage_collection,call]) ->
{ok,{[<0.1244.0>],[garbage_collection,call]}}
ttb:tp(ets,new,2,[]) ->
{ok,[{matched,1}]}
ttb:ctp(ets,new,2) ->
{ok,[{matched,1}]}
ttb:tp(ets,new,2,[]) ->
{ok,[{matched,1}]}
ttb:tp(ets,delete,1,[]) ->
{ok,[{matched,1}]}
ok
將歷史記錄緩衝區中選取的項目寫入組態檔案
(tiger@durin)204> ttb:list_history().
[{1,{ttb,tracer,[tiger@durin,[]]}},
{2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}},
{3,{ttb,tp,[ets,new,2,[]]}},
{4,{ttb,ctp,[ets,new,2]}},
{5,{ttb,tp,[ets,new,2,[]]}},
{6,{ttb,tp,[ets,delete,1,[]]}}]
(tiger@durin)205> ttb:write_config("myconfig",[1,2,3,6]).
ok
(tiger@durin)206> ttb:list_config("myconfig").
[{1,{ttb,tracer,[tiger@durin,[]]}},
{2,{ttb,p,[<0.1244.0>,[garbage_collection,call]]}},
{3,{ttb,tp,[ets,new,2,[]]}},
{4,{ttb,tp,[ets,delete,1,[]]}}]
(tiger@durin)207>
循序追蹤
若要瞭解循序追蹤是什麼以及如何使用它,請參閱 seq_trace
的參考手冊。
Trace Tool Builder 提供的循序追蹤支援包括以下內容
- 啟動系統追蹤器。當使用
ttb:tracer/0,1,2
啟動追蹤埠時,會自動完成此動作。 - 建立會啟用循序追蹤的匹配規格。
啟動循序追蹤需要使用函式 ttb:tracer/0,1,2
啟動追蹤器。然後可以使用以下任一方式啟動循序追蹤
- 透過使用
ttb:seq_trigger_ms/0,1
建立的匹配規格觸發函式。 - 直接使用模組
seq_trace
。
範例 1
在以下範例中,函式 dbg:get_tracer/0
會作為循序追蹤的觸發器
(tiger@durin)110> ttb:tracer().
{ok,[tiger@durin]}
(tiger@durin)111> ttb:p(self(),call).
{ok,{[<0.158.0>],[call]}}
(tiger@durin)112> ttb:tp(dbg,get_tracer,0,ttb:seq_trigger_ms(send)).
{ok,[{matched,1},{saved,1}]}
(tiger@durin)113> dbg:get_tracer(), seq_trace:reset_trace().
true
(tiger@durin)114> ttb:stop(format).
({<0.158.0>,{shell,evaluator,3},tiger@durin}) call dbg:get_tracer()
SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin})
{<0.237.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}}
[Serial: {0,1}]
SeqTrace [0]: ({<0.237.0>,dbg,tiger@durin})
{<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.222>}}
[Serial: {1,2}]
ok
(tiger@durin)116>
範例 2
如果觸發函式不是直接從 Shell 呼叫,而是隱含在較大的系統中,則使用觸發器啟動循序追蹤會更有用。當從 Shell 呼叫函式時,直接啟動循序追蹤會更簡單,例如,如下所示
(tiger@durin)116> ttb:tracer().
{ok,[tiger@durin]}
(tiger@durin)117> seq_trace:set_token(send,true), dbg:get_tracer(),
seq_trace:reset_trace().
true
(tiger@durin)118> ttb:stop(format).
SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin})
{<0.246.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}}
[Serial: {0,1}]
SeqTrace [0]: ({<0.246.0>,dbg,tiger@durin})
{<0.158.0>,{shell,evaluator,3},tiger@durin} ! {dbg,{ok,#Port<0.229>}}
[Serial: {1,2}]
ok
(tiger@durin)120>
在先前的兩個範例中,seq_trace:reset_trace/0
會在追蹤函式之後立即重設追蹤 Token,以避免因為 Erlang Shell 中的輸出而產生許多追蹤訊息。
除了 set_system_tracer/1
之外,在以 ttb:tracer/0,1,2
啟動追蹤埠後,可以使用模組 seq_trace
中的所有函式。
多用途追蹤工具
Observer 應用程式的 src
目錄中的模組 multitrace
提供了一個小型工具,其中有三個可能的追蹤設定。追蹤訊息會寫入二進位檔案,可以使用函式 multitrace:format/1,2
進行格式化
multitrace:debug(What)
- 在所有處理程序上啟動呼叫追蹤,並追蹤指定的函式。使用的格式處理常式是multitrace:handle_debug/4
,它會列印每個呼叫和返回。What
必須是要追蹤的項目或項目列表,格式指定為{Module,Function,Arity}
、{Module,Function}
或僅Module
。multitrace:gc(Procs)
- 追蹤指定處理程序的記憶體回收。使用的格式處理常式是multitrace:handle_gc/4
,它會列印每次記憶體回收的開始、停止和花費的時間。multitrace:schedule(Procs)
- 追蹤指定處理程序的排入和排程。使用的格式處理常式是multitrace:handle_schedule/4
,它會列印每次排入和排程,以及處理程序、時間戳記和目前函式。它還會列印每個追蹤處理程序在排程中花費的總時間。