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 + -
显示快捷键?