ttb.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,001 行 · 第 1/2 页
ERL
1,001 行
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%% %% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See%% the License for the specific language governing rights and limitations%% under the License.%% %% The Initial Developer of the Original Code is Ericsson Utvecklings AB.%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings%% AB. All Rights Reserved.''%% %% $Id$%%-module(ttb).-author('siri@erix.ericsson.se').%% API-export([tracer/0,tracer/1,tracer/2,p/2,stop/0,stop/1]).-export([tp/2, tp/3, tp/4, ctp/0, ctp/1, ctp/2, ctp/3, tpl/2, tpl/3, tpl/4, ctpl/0, ctpl/1, ctpl/2, ctpl/3, ctpg/0, ctpg/1, ctpg/2, ctpg/3]).-export([seq_trigger_ms/0,seq_trigger_ms/1]).-export([write_trace_info/2]).-export([write_config/2,write_config/3,run_config/1,run_config/2,list_config/1]).-export([list_history/0,run_history/1]).-export([format/1,format/2]).%% For debugging-export([dump_ti/1]).-include_lib("kernel/include/file.hrl").-define(meta_time,5000).-define(history_table,ttb_history_table).-define(seq_trace_flags,[send,'receive',print,timestamp]).-define(upload_dir,"ttb_upload").-ifdef(debug).-define(get_status,;get_status -> erlang:display(dict:to_list(NodeInfo)),loop(NodeInfo)).-else.-define(get_status,).-endif.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Open a trace port on all given nodes and create the meta data filetracer() -> tracer(node()).tracer(Nodes) -> tracer(Nodes,[]).tracer(Nodes,Opt) -> start(), store(tracer,[Nodes,Opt]), {PI,Client,Traci} = opt(Opt), do_tracer(Nodes,PI,Client,Traci).do_tracer(Nodes0,PI,Client,Traci) -> Nodes = nods(Nodes0), Clients = clients(Nodes,Client), do_tracer(Clients,PI,Traci).do_tracer(Clients,PI,Traci) -> {ClientSucc,Succ} = lists:foldl( fun({N,{local,File},TF},{CS,S}) -> [_Sname,Host] = string:tokens(atom_to_list(N),"@"), case catch dbg:tracer(N,port,dbg:trace_port(ip,0)) of {ok,N} -> {ok,Port} = dbg:trace_port_control(N,get_listen_port), {ok,T} = dbg:get_tracer(N), rpc:call(N,seq_trace,set_system_tracer,[T]), dbg:trace_client(ip,{Host,Port}, {fun ip_to_file/2,{file,File}}), {[{N,{local,File,Port},TF}|CS], [N|S]}; Other -> display_warning(N,{cannot_open_ip_trace_port, Host, Other}), {CS, S} end; ({N,C,_}=Client,{CS,S}) -> case catch dbg:tracer(N,port,dbg:trace_port(file,C)) of {ok,N} -> {ok,T} = dbg:get_tracer(N), rpc:call(N,seq_trace,set_system_tracer,[T]), {[Client|CS], [N|S]}; Other -> display_warning(N,Other), {CS,S} end end, {[],[]}, Clients), case Succ of [] -> {ok,Succ}; _list -> write_info(ClientSucc,PI,Traci), {ok,Succ} end.opt(Opt) -> opt(Opt,{true,?MODULE,[]}).opt([{process_info,PI}|O],{_,Client,Traci}) -> opt(O,{PI,Client,Traci});opt([{file,Client}|O],{PI,_,Traci}) -> opt(O,{PI,Client,Traci});opt([{handler,Handler}|O],{PI,Client,Traci}) -> opt(O,{PI,Client,[{handler,Handler}|Traci]});opt([],Opt) -> Opt.nods(all) -> Nodes1 = remove_active([node()|nodes()]), remove_faulty_runtime_tools_vsn(Nodes1);nods(Node) when is_atom(Node) -> nods([Node]);nods(Nodes) when is_list(Nodes) -> Nodes1 = remove_active(Nodes), Nodes2 = remove_noexist(Nodes1), remove_faulty_runtime_tools_vsn(Nodes2).remove_active(Nodes) -> Active = get_nodes(), lists:filter( fun(N) -> case lists:member(N,Active) of false -> true; true -> display_warning(N,already_started), false end end, Nodes).remove_noexist(Nodes) -> lists:filter( fun(N) when N=:=node() -> true; (N) -> case net_adm:ping(N) of pong -> true; pang -> display_warning(N,no_connection), false end end, Nodes).remove_faulty_runtime_tools_vsn(Nodes) -> lists:filter( fun(N) -> case rpc:call(N,observer_backend,vsn,[]) of {ok,Vsn} -> check_vsn(N,Vsn); _Error -> display_warning(N,faulty_vsn_of_runtime_tools), false end end,Nodes).check_vsn(_Node,_Vsn) -> true.%check_vsn(Node,_Vsn) -> % display_warning(Node,faulty_vsn_of_runtime_tools),% false.clients(Nodes, {wrap,Name}) -> F = fun(Node) -> TraceFile = name(Node,Name), {Node,{TraceFile++".",wrap,".wrp"},TraceFile} end, lists:map(F,Nodes);clients(Nodes, {wrap,Name,Size,Count}) -> F = fun(Node) -> TraceFile = name(Node,Name), {Node,{TraceFile++".",wrap,".wrp",Size,Count},TraceFile} end, lists:map(F,Nodes);clients(Nodes, {local,RealClient}) -> WrapClients = clients(Nodes,RealClient), F = fun({Node,Client,TraceFile}) -> {Node,{local,Client},TraceFile} end, lists:map(F,WrapClients);clients(Nodes, Name) -> F = fun(Node) -> TraceFile = name(Node,Name), {Node,TraceFile,TraceFile} end, lists:map(F,Nodes). name(Node,Filename) -> Dir = filename:dirname(Filename), File = filename:basename(Filename), filename:join(Dir,atom_to_list(Node) ++ "-" ++ File).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Handling of config filestore(Func,Args) -> Last = case ets:last(?history_table) of '$end_of_table' -> 0; Int when is_integer(Int) -> Int end, ets:insert(?history_table,{Last+1,{?MODULE,Func,Args}}).list_history() -> %% the check is only to see if the tool is started. case ets:info(?history_table) of undefined -> {error, not_running}; _info -> ets:tab2list(?history_table) end.run_history([H|T]) -> case run_history(H) of ok -> run_history(T); {error,not_found} -> {error,{not_found,H}} end;run_history([]) -> ok;run_history(N) -> case catch ets:lookup(?history_table,N) of [{N,{M,F,A}}] -> print_func(M,F,A), R = apply(M,F,A), print_result(R); _ -> {error, not_found} end. write_config(ConfigFile,all) -> write_config(ConfigFile,['_']);write_config(ConfigFile,Config) -> write_config(ConfigFile,Config,[]).write_config(ConfigFile,all,Opt) -> write_config(ConfigFile,['_'],Opt);write_config(ConfigFile,Nums,Opt) when is_list(Nums), is_integer(hd(Nums)); Nums=:=['_'] -> F = fun(N) -> ets:select(?history_table, [{{N,'$1'},[],['$1']}]) end, Config = lists:append(lists:map(F,Nums)), do_write_config(ConfigFile,Config,Opt);write_config(ConfigFile,Config,Opt) when is_list(Config) -> case check_config(Config,[]) of {ok,Config1} -> do_write_config(ConfigFile,Config1,Opt); Error -> Error end.do_write_config(ConfigFile,Config,Opt) -> case Opt of [append] -> ok; [] -> file:delete(ConfigFile) end, write_binary(ConfigFile,Config).check_config([{?MODULE=Mod,Func,Args}|Rest],Acc) -> %% Check only in this module, since other modules might not %% be loaded at the time of creating the config file. case erlang:function_exported(Mod,Func,length(Args)) of true -> check_config(Rest,[{Mod,Func,Args}|Acc]); false -> {error, {not_exported,{Mod,Func,Args}}} end;check_config([{Mod,Func,Args}|Rest],Acc) -> check_config(Rest,[{Mod,Func,Args}|Acc]);check_config([],Acc) -> {ok,lists:reverse(Acc)};check_config([Other|_Rest],_Acc) -> {error,{illegal_config,Other}}.list_config(ConfigFile) -> case file:read_file(ConfigFile) of {ok,B} -> read_config(B,[],1); Error -> Error end. read_config(<<>>,Acc,_N) -> lists:reverse(Acc);read_config(B,Acc,N) -> {{M,F,A},Rest} = get_term(B), read_config(Rest,[{N,{M,F,A}}|Acc],N+1).run_config(ConfigFile) -> case list_config(ConfigFile) of Config when is_list(Config) -> lists:foreach(fun({_,{M,F,A}}) -> print_func(M,F,A), R = apply(M,F,A), print_result(R) end, Config); Error -> Error end.run_config(ConfigFile,N) -> case list_config(ConfigFile) of Config when is_list(Config) -> case lists:keysearch(N,1,Config) of {value,{N,{M,F,A}}} -> print_func(M,F,A), apply(M,F,A); false -> {error, not_found} end; Error -> Error end. print_func(M,F,A) -> Args = arg_list(A,[]), io:format("~w:~w(~s) ->~n",[M,F,Args]).print_result(R) -> io:format("~p~n~n",[R]).arg_list([],[]) -> "";arg_list([A1],Acc) -> Acc++io_lib:format("~w",[A1]);arg_list([A1|A],Acc) -> arg_list(A,Acc++io_lib:format("~w,",[A1])).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Set trace flags on processesp(Procs0,Flags0) -> store(p,[Procs0,Flags0]), no_store_p(Procs0,Flags0).no_store_p(Procs0,Flags0) -> case transform_flags(to_list(Flags0)) of {error,Reason} -> {error,Reason}; Flags -> Procs = procs(Procs0), case lists:foldl(fun(P,{PMatched,Ps}) -> case dbg:p(P,Flags) of {ok,Matched} -> {[{P,Matched}|PMatched],[P|Ps]}; {error,Reason} -> display_warning(P,Reason), {PMatched,Ps} end end,{[],[]},Procs) of {[],[]} -> {error, no_match}; {SuccMatched,Succ} -> no_store_write_trace_info(flags,{Succ,Flags}), {ok,SuccMatched} end end.transform_flags([clear]) -> [clear];transform_flags(Flags) -> dbg:transform_flags(Flags).procs(Procs) when is_list(Procs) -> lists:foldl(fun(P,Acc) -> proc(P)++Acc end,[],Procs);procs(Proc) -> proc(Proc).proc(Procs) when Procs=:=all; Procs=:=existing; Procs=:=new -> [Procs];proc(Name) when is_atom(Name) -> [Name]; % can be registered on this node or other nodeproc(Pid) when is_pid(Pid) -> [Pid];proc({global,Name}) -> case global:whereis_name(Name) of Pid when is_pid(Pid) -> [Pid]; undefined -> [] end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Trace patterntp(A,B) -> store(tp,[A,B]), dbg:tp(A,B).tp(A,B,C) -> store(tp,[A,B,C]), dbg:tp(A,B,C).tp(A,B,C,D) -> store(tp,[A,B,C,D]), dbg:tp(A,B,C,D).tpl(A,B) -> store(tpl,[A,B]), dbg:tpl(A,B).tpl(A,B,C) -> store(tpl,[A,B,C]), dbg:tpl(A,B,C).tpl(A,B,C,D) -> store(tpl,[A,B,C,D]), dbg:tpl(A,B,C,D).ctp() -> store(ctp,[]), dbg:ctp().ctp(A) -> store(ctp,[A]), dbg:ctp(A).ctp(A,B) -> store(ctp,[A,B]), dbg:ctp(A,B).ctp(A,B,C) -> store(ctp,[A,B,C]), dbg:ctp(A,B,C).ctpl() -> store(ctpl,[]), dbg:ctpl().ctpl(A) -> store(ctpl,[A]), dbg:ctpl(A).ctpl(A,B) -> store(ctpl,[A,B]), dbg:ctpl(A,B).ctpl(A,B,C) -> store(ctpl,[A,B,C]), dbg:ctpl(A,B,C).ctpg() -> store(ctpg,[]), dbg:ctpg().ctpg(A) -> store(ctpg,[A]), dbg:ctpg(A).ctpg(A,B) -> store(ctpg,[A,B]), dbg:ctpg(A,B).ctpg(A,B,C) -> store(ctpg,[A,B,C]), dbg:ctpg(A,B,C).%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Support for sequential traceseq_trigger_ms() -> seq_trigger_ms(all).seq_trigger_ms(all) -> seq_trigger_ms(?seq_trace_flags);seq_trigger_ms(Flag) when is_atom(Flag) -> seq_trigger_ms([Flag],[]);seq_trigger_ms(Flags) -> seq_trigger_ms(Flags,[]).seq_trigger_ms([Flag|Flags],Body) -> case lists:member(Flag,?seq_trace_flags) of true -> seq_trigger_ms(Flags,[{set_seq_token,Flag,true}|Body]); false -> {error,{illegal_flag,Flag}} end;seq_trigger_ms([],Body) -> [{'_',[],Body}].%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Write information to the .ti filewrite_trace_info(Key,What) -> store(write_trace_info,[Key,What]), no_store_write_trace_info(Key,What).no_store_write_trace_info(Key,What) -> case whereis(?MODULE) of undefined -> ok; Pid when is_pid(Pid) -> ?MODULE ! {write_trace_info,Key,What} end, ok.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Stop tracing on all nodesstop() -> stop([]).stop(Opts) -> Fetch = stop_opts(Opts), case whereis(?MODULE) of undefined -> ok; Pid when is_pid(Pid) -> ?MODULE ! {stop,Fetch,self()}, receive {?MODULE,stopped} -> ok end end, stopped.stop_opts(Opts) -> case lists:member(format,Opts) of true -> format; % format implies fetch false -> case lists:member(fetch,Opts) of true -> fetch; false -> nofetch end end.%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Process implementationstart() -> case whereis(?MODULE) of undefined -> Parent = self(), Pid = spawn(fun() -> init(Parent) end), receive {started,Pid} -> ok end; Pid when is_pid(Pid) -> ok end.init(Parent) -> register(?MODULE,self()), ets:new(?history_table,[ordered_set,named_table,public]), Parent ! {started,self()}, loop(dict:new()).loop(NodeInfo) -> receive
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?