%% ``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$
%%
%% Author: Ann-Marie L�f, [email protected]
%% Lennart �hman, [email protected]
%%
%% Description: API module for the inviso system.
%% Inviso consists of a control component and possibly one or more runtime
%% components. This module is simply the API to the inviso system. All normal
%% calls goes through the control component.
%% ------------------------------------------------------------------------------
-module(inviso).
%% ------------------------------------------------------------------------------
%% Exported API functions.
%% ------------------------------------------------------------------------------
-export([start/0, start/1,
add_node/1, add_node/2, add_node_if_ref/1, add_node_if_ref/2,
add_nodes/2, add_nodes/3, add_nodes_if_ref/2, add_nodes_if_ref/3,
change_options/1, change_options/2,
init_tracing/1, init_tracing/2,
stop_tracing/0, stop_tracing/1,
clear/0, clear/1, clear/2,
flush/0,flush/1,
stop/0, stop_nodes/0, stop_nodes/1, stop_all/0,
tp/1,tp/2,tp/4,tp/5,tp/6,
tpl/1,tpl/2,tpl/4,tpl/5,tpl/6,
tpm_localnames/0,tpm_localnames/1,tpm_globalnames/0,tpm_globalnames/1,
init_tpm/4,init_tpm/5,init_tpm/7,init_tpm/8,
tpm/4,tpm/5,tpm/6,tpm/8,tpm/9,
tpm_tracer/4,tpm_tracer/5,tpm_tracer/6,tpm_tracer/8,tpm_tracer/9,
tpm_ms/5,tpm_ms/6,
tpm_ms_tracer/5,tpm_ms_tracer/6,
ctpm_ms/4,ctpm_ms/5,ctpm/3,ctpm/4,
ctpm_localnames/0,ctpm_localnames/1,ctpm_globalnames/0,ctpm_globalnames/1,
ctp/1,ctp/2,ctp/3,ctp/4,
ctpl/1,ctpl/2,ctpl/3,ctpl/4,
tf/1, tf/2, tf/3,
ctf/1, ctf/2, ctf/3,
ctp_all/0, ctp_all/1, ctf_all/0, ctf_all/1,
suspend/1, suspend/2,
cancel_suspension/0, cancel_suspension/1,
get_status/0, get_status/1,
get_tracerdata/0, get_tracerdata/1,
list_logs/0, list_logs/1,
fetch_log/2, fetch_log/3, fetch_log/4,
delete_log/0, delete_log/1, delete_log/2,
subscribe/0, subscribe/1,
unsubscribe/0, unsubscribe/1]).
%% debuging inviso
-export([state/0, state/1]).
%% ------------------------------------------------------------------------------
%% Macros used in this module.
%% ------------------------------------------------------------------------------
-define(CONTROLLER,inviso_c).
%% Some function calls to runtime components may take long time, we must wait
%% longer than the standard timeout for a reply from the control component.
-define(CALL_TIMEOUT,60000).
%% ------------------------------------------------------------------------------
%% =============================================================================
%% CONTROL COMPONENT API FUNCTIONS.
%% =============================================================================
%% start()={ok,pid()}|{error,Reason}
%% start(Options)={ok,pid()}|{error,Reason}
%% Options=[Option,...], the options will be default options to runtime components
%% later started. See add_node about available options.
%% There are also options consumed by the control component:
%% Option={subscribe,pid()}
%%
%% Starts a control component process on the local node. A control component must
%% be started before runtime components can be started manually.
start() ->
gen_server:start({local,?CONTROLLER},?CONTROLLER,{self(),[]},[]).
start(Options) ->
gen_server:start({local,?CONTROLLER},?CONTROLLER,{self(),Options},[]).
%% -----------------------------------------------------------------------------
%% add_node(Reference)=NodeResult|{error, Reason}
%% add_node(Reference,Options)=NodeResult|{error, Reason}
%% Reference=PreviousReference = term(),
%% Options=[Option,...],
%% Option={dependency,Dep}
%% Dep=integer()|'infinity'; The timeout before the runtime component will
%% terminate if abandoned by this control component.
%% Option={overload,Overload}; controls how and how often overload checks shall
%% be performed. Instead of specifying a tuple, the atom 'overload' can be
%% specified to state no loadcheck. The result will actually be the same
%% if 'infinity' is used as intervall. It is sometimes necessary to
%% initialize the overlaod check. This can be done with InitMFA. The
%% loadchecker must then also be removed by using a RemoveMFA.
%% Overload=Iterval (int() in milliseconds) |
%% {LoadMF,Interval}|{LoadMF,Interval,InitMFA,RemoveMFA}
%% LoadMF={Mod,Func}
%% InitMFA,RemoveMFA={Mod,Func,ArgList}|void
%% If just Interval is used, it means using a default overload check.
%% NodeResult={ok,NAns}|{error,Reason}
%% NAns=new|{adopted,State,Status,PreviousReference}|already_added
%% Status = running | {suspended, SReason}
%%
%% Starts or tries to connect to an existing runtime component at the local
%% node, regardless if the system is distributed or not.
%% Options will override any default options specified at start-up of the
%% control component.
add_node(Reference) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],[],Reference,any_ref},?CALL_TIMEOUT).
add_node(Reference,Options) when is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],Options,Reference,any_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% add_node(Reference)=NodeResult|{error,{wrong_reference,OtherRef}}|{error,Reason}
%% add_node(Reference,Options)=NodeResult|{error,{wrong_reference,OtherRef}}|
%% {error,Reason}
%%
%% As add_node/1,/2 but will only connect to an already existing runtime component
%% if its reference is the same as the one given as argument.
add_node_if_ref(Reference) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],[],Reference,if_ref},?CALL_TIMEOUT).
add_node_if_ref(Reference,Options) when is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,[node()],Options,Reference,if_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% add_nodes(Nodes,Reference)={ok,NodeResults}|{error,Reason}
%% add_nodes(Nodes,Reference,Options)={ok,NodeResults}|{error,Reason}
%% Nodes=[Node,...],
%% NodeResults=[{Node,NodeResult},...]
%%
%% As add_node/1,/2 but for the nodes specified in Nodes.
%% It is possible but not intended to use this function in a non-distributed
%% system. By speicifying node() as the node where the runtime component shall
%% be started. The return value will then follow the rules of non distributed
%% returnvalues and not have a node indicator.
add_nodes(Nodes,Reference) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,[],Reference,any_ref},?CALL_TIMEOUT).
add_nodes(Nodes,Reference,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,Options,Reference,any_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% add_nodes_if_ref(Nodes,Reference)={ok,NodeResults}|{error,Reason}
%% add_nodes_if_ref(Nodes,Reference,Options)={ok,NodeResults}|{error,Reason}
%%
%% As add_nodes/2,/3 but will only connect to an already existing runtime component
%% if its reference is the same as the one given as argument.
add_nodes_if_ref(Nodes,Reference) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,[],Reference,if_ref},?CALL_TIMEOUT).
add_nodes_if_ref(Nodes,Reference,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{add_nodes,Nodes,Options,Reference,if_ref},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% change_options(Options)={ok,NodeResults}|NodeResult|{error,Reason}
%% change_options(Nodes,Options)={ok,NodeResults}|{error,Reason}
%% Nodes=[Node,...],
%% Options= see add_node and add_nodes on available options.
%%
%% Change options on all or specified Nodes. This may result in for instance
%% reinitialization of overloadcheck.
change_options(Options) when is_list(Options) ->
gen_server:call(?CONTROLLER,{change_options,all,Options},?CALL_TIMEOUT).
change_options(Nodes,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{change_options,Nodes,Options},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% init_tracing(TracerData)={ok,[{Node,NodeResult}]} | NodeResult | {error,Reason}
%% init_tracing(TracerList)={ok,[{Node,NodeResult}]} | {error,Reason}
%% init_tracing(Nodes,TracerData)={ok,[{Node,NodeResult}]}|{error,Reason}
%% TracerData = [{trace,LogTD} [,{ti,TiTD}]}] | LogTD
%% LogTD = {HandlerFun,Data} | collector | {relayer,pid()} |
%% {relayer,CollectingNode} | {ip,IPPortParameters} |
%% {file,FilePortParameters}
%% TiTD = {file,FileName} | {file,FileName,TiMFA}
%% TiMFA = {Module,Function,ArgumentList} initiating a private loopdata
%% inside the meta-tracer.
%% TracerList = [{Node,TracerData}],
%% IPPortParameters = Portno | {Portno, Qsiz}
%% Qsiz =
%% FilePortParameters = {Filename, wrap, Tail, {time, WrapTime}, WrapCnt} |
%% {FileName, wrap, Tail, WrapSize, WrapCnt} |
%% {FileName, wrap, Tail, WrapSize} |
%% {FileName, wrap, Tail} | FileName
%% Tail =/= ""
%% HandlerFun is a function taking 2 arguments.
%% Nodes = [node()],
%% CollectingNode = pid() | node(),
%% NodeResult = {ok,LogResults} | {error, NReason}
%% LogResults=[LogResult,...]
%% LogResult={trace_log,LogRes} | {ti_log,LogRes}
%% LogRes=ok|{error,Reason}
%%
%% Starts tracing on the nodes specified. If just providing a TracerData tracing
%% will be initiated on all our nodes. If it is the non distributed case, that
%% means only on the local non distributed node.
%%
%% {HandlerFun,Data}
%% Will use the runtime components own process as tracer and handle all
%% incomming trace message using HandlerFun.
%% {relayer,CollectingNode}
%% The runtime component addressed will act tracer and relay all incomming trace
%% messages to Node or Pid, if CollectingNode is not a traced node connected
%% to the controll component, the init_tracing call will return an error.
%% Note that {relayer, Node} only is syntactical sugar for
%% {relayer, rpc:call(Node,erlang,whereis,[inviso_rt])}
%% collector
%% The runtime component is used as tracer or collector of relayed
%% trace messages using the default handler writing them to io.
%% ip | file - will open a trace-port on Node using PortParameters
init_tracing(TracerDataList) ->
gen_server:call(?CONTROLLER,{init_tracing,TracerDataList},?CALL_TIMEOUT).
init_tracing(Nodes,TracerData) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{init_tracing,Nodes,TracerData},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% stop_tracing(Nodes)={ok,NodeResults}|{error,Reason}
%% stop_tracing()={ok,NodeResults}|NodeResult
%% Nodes=[Node,...],
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,State}|{error,Reason}
%% State=new|idle
%% Stops tracing on all or specified Nodes. Flushes trace buffert,
%% closes trace port and removes all trace flags and meta-patterns.
%% The nodes are called in parallel.
stop_tracing() ->
gen_server:call(?CONTROLLER,{stop_tracing,all},?CALL_TIMEOUT).
stop_tracing(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{stop_tracing,Nodes},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% clear()={ok,NodeResults}|NodeResult
%% clear(Nodes,Options)={ok,NodeResults}|{error,Reason}
%% clear(Options)={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...],
%% Options=[Option,...],
%% Option=keep_trace_patterns|keep_log_files
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,{new,Status}}|{error,Reason}
%% Status=running|{suspended,SReason}
%%
%% Stops all tracing including removing meta-trace patterns. If the node is tracing
%% or idle, logs belonging to the current tracerdata are removed. Hence the node
%% is returned to state 'new'. Note that node can still be suspended.
clear() ->
gen_server:call(?CONTROLLER,{clear,all,[]},?CALL_TIMEOUT).
clear(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{clear,Nodes,[]},?CALL_TIMEOUT).
clear(Nodes,Options) when is_list(Nodes),is_list(Options) ->
gen_server:call(?CONTROLLER,{clear,Nodes,Options},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% flush()={ok,NodeResults} | NodeResult
%% flush(Nodes)={ok,NodeResults}
%% Nodes=[Node,...]
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok | {error,Reason}
%% Sends a flush request to the trace-port driver on the nodes in Nodes.
%% There will be an error for nodes that are not tracing. It is not an error to
%% try to flush runtime components not using a trace-port.
flush() ->
gen_server:call(?CONTROLLER,{flush,all},?CALL_TIMEOUT).
flush(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{flush,Nodes},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% stop()=shutdown
%%
%% Stops the controll component. Runtime components are left as is. They will
%% behave according to their dependency values.
stop() ->
case catch gen_server:call(?CONTROLLER,stop,?CALL_TIMEOUT) of
shutdown ->
shutdown;
{'EXIT',{noproc,_}} ->
shutdown;
{'EXIT',Reason} ->
exit(Reason)
end.
%% -----------------------------------------------------------------------------
%% stop_nodes()={ok,NodeResults}|NodeResult
%% stop_nodes(Nodes)={ok,NodeResults}|{error,Reason}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason}
%%
%% Stops runtime component on Nodes. stop_nodes/0 will if the control component
%% is running on a distributed node stop all runtime components. And if running
%% on a non distributed node, stop the local and only runtime component.
stop_nodes() ->
gen_server:call(?CONTROLLER,{stop_nodes,all},?CALL_TIMEOUT).
stop_nodes(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{stop_nodes,Nodes},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% stop_all()={ok,NodeResults}|NodeResult
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason}
%%
%% A combination of stop/0 and stop_nodes/0.
stop_all() ->
gen_server:call(?CONTROLLER, stop_all,?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% tp(Nodes,Module,Function,Arity,MatchSpec,Opts)={ok,NodeResults}|{error,Reason}
%% tp(Nodes,Module,Function,Arity,MatchSpec)={ok,NodeResults}|{error,Reason}
%% tp(Module,Function,Arity,MatchSpec)={ok,NodeResults}|NodeResult|{error,Reason}
%% tp(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
%% tp(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...]
%% Module,Function=atom() | '_'
%% Arity=integer() | '_'
%% MatchSpec=true|false|[]| matchspec()
%% PatternList=[Pattern,...],
%% Pattern={Module,Function,Arity,MatchSpec,Opts},
%% Opts=[Opt,...]
%% Opt='only_loaded'; means that the runtime component shall not try to load
%% a module should it not already be present in the runtime system.
%% NodeResults=[NodeResult,...]
%% NodeResult={ok,[Ans]}|{error,Reason},
%% Ans=integer()|{error,Reason}
%%
%% Set trace pattern (global) on specified or all Nodes. The integer replied
%% if the call was successfully describes the matched number of functions.
%% The functions without a Nodes argument means all nodes, in a non-distributed
%% environment it means the local node.
%% When calling several nodes, the nodes are called in parallel.
tp(Nodes,Module,Function,Arity,MatchSpec,Opts) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,Opts}],[global]).
tp(Nodes,Module,Function,Arity,MatchSpec) when is_list(Nodes) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,[]}],[global]);
tp(Module,Function,Arity,MatchSpec,Opts) when is_atom(Module) ->
trace_pattern(all,[{Module,Function,Arity,MatchSpec,Opts}],[global]).
tp(Module,Function,Arity,MatchSpec) ->
trace_pattern(all,[{Module,Function,Arity,MatchSpec,[]}],[global]).
tp(Nodes,PatternList) ->
trace_pattern(Nodes,PatternList,[global]).
tp(PatternList) ->
trace_pattern(all,PatternList,[global]).
%% -----------------------------------------------------------------------------
%% tpl(Nodes,Module,Function,Arity,MatchSpec)={ok,NodeResults}|{error,Reason}
%% tpl(Module,Function,Arity,MatchSpec)={ok,NodeResults}|NodeResult|{error,Reason}
%% tpl(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
%% tpl(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
%% see tp/X for description.
%%
%% Set trace pattern (local) on specified or all Nodes. The integer replied
%% if the command was successfully describes the matched number of functions.
%% The functions without a Nodes argument means all nodes, in a non-distributed
%% environment it means the local node.
%% When calling several nodes, the nodes are called in parallel.
tpl(Nodes,Module,Function,Arity,MatchSpec,Opts) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,Opts}],[local]).
tpl(Nodes,Module,Function,Arity,MatchSpec) when is_list(Nodes) ->
trace_pattern(Nodes,[{Module,Function,Arity,MatchSpec,[]}],[local]);
tpl(Module,Function,Arity,MatchSpec,Opts) when is_atom(Module) ->
trace_pattern(all,[{Module,Function,Arity,MatchSpec,Opts}],[local]).
tpl(Module,Function,Arity,MatchSpec) ->
trace_pattern(all,[{Module,Function,Arity,MatchSpec,[]}],[local]).
tpl(Nodes, PatternList) ->
trace_pattern(Nodes,PatternList,[local]).
tpl(PatternList) ->
trace_pattern(all,PatternList,[local]).
%% -----------------------------------------------------------------------------
%% ctp(Nodes,Module,Function,Arity)={ok,NodeResults}|{error,Reason}
%% ctp(Module,Function,Arity)={ok,NodeResults}|NodeResult|{error,Reason}
%% ctp(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
%% ctp(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
%% PatternList=[{Mod,Func,Arity},...]
%% see tp/X for other argument descriptions.
%%
%% Clear trace pattern (global) on specified or all Nodes. The integer replied
%% if the call was successfully describes the matched number of functions.
%% The functions without a Nodes argument means all nodes, in a non-distributed
%% environment it means the local node.
%% When calling several nodes, the nodes are called in parallel.
ctp(Nodes,Module,Function,Arity) ->
trace_pattern(Nodes,[{Module,Function,Arity,false,[only_loaded]}],[global]).
ctp(Module,Function,Arity) ->
trace_pattern(all,[{Module,Function,Arity,false,[only_loaded]}],[global]).
ctp(Nodes,PatternList) when is_list(PatternList) ->
trace_pattern(Nodes,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[global]).
ctp(PatternList) when is_list(PatternList) ->
trace_pattern(all,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[global]).
%% -----------------------------------------------------------------------------
%% ctpl(Nodes,Module,Function,Arity)={ok,NodeResults}|{error,Reason}
%% ctpl(Module,Function,Arity)={ok,NodeResults}|NodeResult|{error,Reason}
%% ctpl(Nodes,PatternList)={ok,NodeResults}|{error,Reason}
%% ctpl(PatternList)={ok,NodeResults}|NodeResult|{error,Reason}
%% see ctp/X for argument description.
%%
%% Clear trace pattern (local) on specified or all Nodes. The integer replied
%% if the call was successfully describes the matched number of functions.
%% The functions without a Nodes argument means all nodes, in a non-distributed
%% environment it means the local node.
%% When calling several nodes, the nodes are called in parallel.
ctpl(Nodes,Module,Function,Arity) ->
trace_pattern(Nodes,[{Module,Function,Arity,false,[only_loaded]}],[local]).
ctpl(Module,Function,Arity) ->
trace_pattern(all,[{Module,Function,Arity,false,[only_loaded]}],[local]).
ctpl(Nodes,PatternList) when is_list(PatternList) ->
trace_pattern(Nodes,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[local]).
ctpl(PatternList) when is_list(PatternList) ->
trace_pattern(all,
lists:map(fun({M,F,A})->{M,F,A,false,[only_loaded]} end,PatternList),
[local]).
%% -----------------------------------------------------------------------------
%% Help function doing the control component calling for all tp/X, tpl/X, ctp/X
%% and ctpl/X functions.
trace_pattern(Nodes,Patterns,FlagList) ->
gen_server:call(?CONTROLLER, {trace_pattern, Nodes, Patterns, FlagList},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% -----------------------------------------------------------------------------
%% tf(Nodes,PidSpec,FlagList)={ok,NodeResults}|{error,Reason}
%% tf(PidSpec,FlagList)={ok,NodeResults}|NodeResult|{error,Reason}
%% tf(Nodes,TraceConfList)={ok,NodeResults}|{error,Reason}
%% tf(NodeTraceConfList)={ok,NodeResults}|{error,Reason}
%% tf(TraceConfList)={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...],
%% NodeTraceConfList=[{Node,TraceConfList}]
%% TraceConfList=[{PidSpec,FlagList},...],
%% FlagList=[Flags],
%% PidSpec=all|new|existing|pid()|locally_registered_name()
%% Flags= all process trace flags allowed.
%% NodeResult={ok,[Ans]}|{error,Reason},
%% Ans=integer() | {error,Reason}
%%
%% Set process trace flags on processes on all or specified Nodes. The integer
%% return if the call was successfully describes the matched number of processes.
%% The functions without a Nodes argument means all nodes, in a non-distributed
%% environment it means the local node.
%% There are many combinations which does not make musch scense. For instance
%% specifying a certain pid at all nodes. Or an empty TraceConfList for all
%% nodes.
%% When calling several nodes, the nodes are called in parallel.
tf(Nodes,PidSpec,FlagList) when is_list(Nodes),is_list(FlagList) ->
trace_flags(Nodes,[{PidSpec, FlagList}],true).
tf(Nodes,TraceConfList) when is_list(Nodes),is_list(TraceConfList) ->
trace_flags(Nodes,TraceConfList,true);
tf(PidSpec,FlagList) when is_list(FlagList) ->
trace_flags(all,[{PidSpec,FlagList}],true).
tf(ArgList) when is_list(ArgList) -> % This one has triple functionality!
case ArgList of
[{_Process,Flags}|_] when is_list(Flags),is_atom(hd(Flags))-> % A call to all nodes.
trace_flags(all,ArgList,true);
[{_Node,TraceConfList}|_] when is_list(TraceConfList),is_tuple(hd(TraceConfList)) ->
trace_flags(ArgList,true);
[{_Node,_TraceConfList,_How}|_] ->
trace_flags(ArgList);
[] -> % Stupid but allowed.
trace_flags(all,ArgList,true) % Actually doesn't matter which we choose.
end.
%% -----------------------------------------------------------------------------
%% ctf(Nodes,PidSpec,FlagList)={ok,NodeResults}|{error,Reason}
%% ctf(PidSpec,FlagList)={ok,NodeResults}|NodeResult|{error,Reason}
%% ctf(Nodes,TraceConfList)={ok,NodeResults}|{error,Reason}
%% ctf(TraceConfList)={ok,NodeResults}|NodeResult|{error,Reason}
%% see tf/X for arguments.
%%
%% Clear process trace flags on all or specified Nodes. The integer replied
%% if the command was successfully describes the matched number of processes.
%% The functions without a Nodes argument means all nodes, in a non-distributed
%% environment it means the local node.
%% When calling several nodes, the nodes are called in parallel.
ctf(Nodes,PidSpec,FlagList) when is_list(Nodes),is_list(FlagList) ->
trace_flags(Nodes,[{PidSpec,FlagList}],false).
ctf(Nodes,TraceConfList) when is_list(Nodes),is_list(TraceConfList) ->
trace_flags(Nodes,TraceConfList,false);
ctf(PidSpec,FlagList) when is_list(FlagList) ->
trace_flags(all,[{PidSpec,FlagList}],false).
ctf(TraceConfList) when is_list(TraceConfList) ->
trace_flags(all,TraceConfList,false).
%% -----------------------------------------------------------------------------
%% ctf_all(Nodes)={ok,NodeResults}|{error,Reason}
%% ctf_all()={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...],
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason},
%%
%% Clears all trace flags on all or specified nodes. Just for convenience.
ctf_all() ->
gen_server:call(?CONTROLLER,{trace_flags,all,[{all,[all]}],false},?CALL_TIMEOUT).
ctf_all(Nodes) ->
gen_server:call(?CONTROLLER,{trace_flags,Nodes,[{all,[all]}],false},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% Help function to tf/X and ctf/X making the call to the control component.
trace_flags(Nodes, TraceConfList, How) ->
gen_server:call(?CONTROLLER, {trace_flags, Nodes, TraceConfList, How},?CALL_TIMEOUT).
trace_flags(NodeTraceConfList,How) ->
gen_server:call(?CONTROLLER,{trace_flags,NodeTraceConfList,How},?CALL_TIMEOUT).
trace_flags(NodeTraceConfListHow) ->
gen_server:call(?CONTROLLER,{trace_flags,NodeTraceConfListHow},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% -----------------------------------------------------------------------------
%% tpm_localnames()={ok,NodeResults}|NodeResult|{error,Reason}
%% tpm_localnames(Nodes)={ok,NodeResults}|{error,Reason}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,N}|{error,Reason}, Note that N can only be 0 or 1.
%%
%% Quick version for setting meta-trace patterns on erlang:register/2. It uses
%% a default CallFunc and ReturnFunc in the meta-tracer server.
%% The main purpose of this function is to create ti-log entries for printing
%% the aliases for process instead of their process identities.
tpm_localnames() ->
tpm_localnames(all).
tpm_localnames(Nodes) ->
gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{local_register,[]}},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% tpm_globalnames()={ok,NodeResults}|NodeResult|{error,Reason}
%% tpm_globalnames(Nodes)={ok,NodeResults}|{error,Reason}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={SubResult,SubResult}
%% SubResult={ok,N}|{error,Reason}, Note that N can only be 0 or 1.
%% As tpm_locanames/0,/1 but for registering names with global. Note that this
%% actually involves setting meta trace patterns on two functions in global.
tpm_globalnames() ->
tpm_globalnames(all).
tpm_globalnames(Nodes) ->
gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{global_register,[]}},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% init_tpm(Mod,Func,Arity,CallFunc)={ok,NodeResults}|NodeResult|{error,Reason}
%% init_tpm(Nodes,Mod,Func,Arity,CallFunc)={ok,NodeResults}|{error,Reason}
%% init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
%% {ok,NodeResults}|NodeResult|{error,Reason}
%% init_tpm(Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
%% {ok,NodeResults}|{error,Reason}
%%
%% Mod,Func=Pointing out the function which shall be meta traced, atom().
%% Arity=As above, integer().
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason}
%%
%% InitFunc,RemoveFunc={Module,Function}|fun(), functions being called when
%% to initialize the public loopdata structure, and to reset it.
%% InitFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD,Output}
%% Supposed to initialize whatever needs to be done before
%% handling any incoming meta-trace message for the Mod:Func/Arity.
%% RemoveFunc(Mod,Func,Arity,PublLD)->{ok,NewPublLD}
%% Called when meta tracing of Mod:Func/Arity is stopped. It is supposed
%% to clear datastructures away from the PublLD.
%% Initializes the public loopdata for this function. Note that we can not use wildcards
%% here (even if it is perfectly legal in Erlang). It also sets the CallFunc and
%% ReturnFunc for the meta traced function. The function is hence ready to be
%% meta traced with either tpm/5 or tpm_ms/5.
%% When calling several nodes, the nodes are called in parallel.
init_tpm(Mod,Func,Arity,CallFunc) ->
init_tpm(all,Mod,Func,Arity,CallFunc).
init_tpm(Nodes,Mod,Func,Arity,CallFunc) ->
gen_server:call(?CONTROLLER,
{meta_pattern,
Nodes,
{init_tpm,
[Mod,Func,Arity,CallFunc]}},
?CALL_TIMEOUT).
init_tpm(Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
init_tpm(all,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc).
init_tpm(Nodes,Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
gen_server:call(?CONTROLLER,
{meta_pattern,
Nodes,
{init_tpm,
[Mod,Func,Arity,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}},
?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% tpm(Mod,Func,Arity,MS)={ok,NodeResults}|NodeResult|{error,Reason}
%% tpm(Nodes,Mod,Func,Arity,MS)={ok,NodeResults}|{error,Reason}
%% tpm(Mod,Func,Arity,MS,CallFunc)={ok,NodeResults}|NodeResults|{error,Reason}
%% tpm(Nodes,Mod,Func,Arity,MS,CallFunc)={ok,NodeResults}|{error,Reason}
%% tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
%% {ok,NodeResults}|NodeResults|{error,Reason}
%% tpm(Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc)=
%% {ok,NodeResults}|{error,Reason}
%%
%% Mod,Func=atom() and not '_'.
%% Arity=integer()
%% MS=list(), matchspecification.
%% Nodes=List of nodenames.
%% InitFunc,CallFunc,ReturnFunc,RemoveFunc={Module,Function}|fun(),
%% functions being called when these functions are called by the meta trace
%% server at certain events.
%% CallFunc(CallingPid,ActualArgList,PublLD)->{ok,NewPrivLD,Output}
%% ReturnFunc(CallingPid,ReturnValue,PublLD)->{ok,NewPrivLD,Output}
%% When a call respectively return_from trace message arrives for the meta
%% traced function, the corresponding function is called.
%% The ReturnFunc must handle the fact that a return_from message arrives
%% for a call which was never noticed. This because the message queue of the
%% meta tracer may have been emptied.
%%
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,N}|{error,Reason}, Note that N can only be 0 or 1.
%%
%% Activates meta-tracing in the inviso_rt_meta tracer. Except when using tpm/6,/8
%% and /9 the function must first have been initiated using init_tpm. If running
%% a non distributed system the variants without Node shall be used. If running
%% in a distributed environment, without Node means all our nodes.
%% When calling several nodes, the nodes are called in parallel.
tpm(Mod,Func,Arity,MS) ->
tpm(all,Mod,Func,Arity,MS).
tpm(Nodes,Mod,Func,Arity,MS) when is_integer(Arity) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm,[Mod,Func,Arity,MS]}});
tpm(Mod,Func,Arity,MS,CallFunc) when is_integer(Arity) ->
tpm(all,Mod,Func,Arity,MS,CallFunc).
tpm(Nodes,Mod,Func,Arity,MS,CallFunc) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm,[Mod,Func,Arity,MS,CallFunc]}}).
tpm(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
tpm(all,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc).
tpm(Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
gen_server:call(?CONTROLLER,
{meta_pattern,
Nodes,
{tpm,
[Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}},
?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% Same as tpm/X but the meta tracer will append {tracer,Tracer} to any enable
%% list in a trace body action term.
tpm_tracer(Mod,Func,Arity,MS) ->
tpm_tracer(all,Mod,Func,Arity,MS).
tpm_tracer(Nodes,Mod,Func,Arity,MS) when is_integer(Arity) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm_tracer,[Mod,Func,Arity,MS]}},
?CALL_TIMEOUT);
tpm_tracer(Mod,Func,Arity,MS,CallFunc) when is_integer(Arity) ->
tpm_tracer(all,Mod,Func,Arity,MS,CallFunc).
tpm_tracer(Nodes,Mod,Func,Arity,MS,CallFunc) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm_tracer,[Mod,Func,Arity,MS,CallFunc]}}).
tpm_tracer(Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
tpm_tracer(all,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc).
tpm_tracer(Nodes,Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc) ->
gen_server:call(?CONTROLLER,
{meta_pattern,
Nodes,
{tpm_tracer,
[Mod,Func,Arity,MS,InitFunc,CallFunc,ReturnFunc,RemoveFunc]}},
?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% tpm_ms(Mod,Func,Arity,MSname,MS)={ok,NodeResults}|NodeResult|{error,Reason}
%% tpm_ms(Nodes,Mod,Func,Arity,MSname,MS)={ok,NodeResults}|{error,Reason}
%% Nodes= List of all nodes where the function shall be carried out.
%% Mod,Func=Pointing out the function to which we shall add a match-spec., atom().
%% Arity=As above, integer().
%% MSname=A name to be used if this MS shall be removed later. term().
%% MatchSpec=List of match specification, Remember {return_trace}
%% if expecting return_from messages.
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,1}|{ok,0}|{error,Reason} where {ok,1} indicates that
%% setting the matchspecification for the function succeeded.
%%
%% This function adds a list of match-specs to the already existing ones. It
%% uses an internal database to keep track of existing match-specs. If the
%% match-spec does not result in any meta traced functions (for whatever reason),
%% the MS is not saved in the database. The previously known match-specs are
%% not removed.
%% The function must previously have been initiated in order for this function
%% to add a match-spec.
%% When calling several nodes, the nodes are called in parallel.
tpm_ms(Mod,Func,Arity,MSname,MS) ->
tpm_ms(all,Mod,Func,Arity,MSname,MS).
tpm_ms(Nodes,Mod,Func,Arity,MSname,MS) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm_ms,[Mod,Func,Arity,MSname,MS]}},
?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% Same as tpm_ms/5, /6 but the meta tracer will append {tracer,Tracer} to any enable
%% list in a trace body action term.
tpm_ms_tracer(Mod,Func,Arity,MSname,MS) ->
tpm_ms_tracer(all,Mod,Func,Arity,MSname,MS).
tpm_ms_tracer(Nodes,Mod,Func,Arity,MSname,MS) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{tpm_ms_tracer,[Mod,Func,Arity,MSname,MS]}},
?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% ctpm_ms(Mod,Func,Arity,MSname)={ok,NodeResults}|NodeResult|{error,Reason}
%% ctpm_ms(Nodes,Mod,Func,Arity,MSname)={ok,NodeResults}|{error,Reason}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason}
%%
%% Removes a named match-spec from the meta traced function. Note that it never
%% is a fault to remove an MS. Not even from a function which is non existant.
%% When calling several nodes, the nodes are called in parallel.
ctpm_ms(Mod,Func,Arity,MSname) ->
ctpm_ms(all,Mod,Func,Arity,MSname).
ctpm_ms(Nodes,Mod,Func,Arity,MSname) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{ctpm_ms,[Mod,Func,Arity,MSname]}},
?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% ctpm(Mod,Func,Arity)={ok,NodeResults}|NodeResult|{error,Reason}
%% ctpm(Node,Mod,Func,Arity)={ok,NodeResults}|{error,Reason}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason}
%%
%% Removes the meta trace pattern for the function, means stops generating output
%% for this function. The public LD may be cleared by the previously entered
%% RemoveFunc.
%% When calling several nodes, the nodes are called in parallel.
ctpm(Mod,Func,Arity) ->
ctpm(all,Mod,Func,Arity).
ctpm(Nodes,Mod,Func,Arity) ->
gen_server:call(?CONTROLLER,
{meta_pattern,Nodes,{ctpm,[Mod,Func,Arity]}},
?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% ctpm_localnames()={ok,NodeResults}|NodeResult|{error,Reason}
%% ctpm_localnames(Nodes)={ok,NodeResults}|{error,Reason}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason}
%%
%% Removes meta-trace pattern for erlang:register/2, previously set by tpm_localnames.
%% When calling several nodes, the nodes are called in parallel.
ctpm_localnames() ->
ctpm_localnames(all).
ctpm_localnames(Nodes) ->
gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{remove_local_register,[]}},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% ctpm_localnames()={ok,NodeResults}|NodeResult|{error,Reason}
%% ctpm_localnames(Nodes)={ok,NodeResults}|{error,Reason}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={SubResult,Subresult}
%% SubResult=ok|{error,Reason}
%%
%% Removes meta-trace pattern for the register functions in global. Note that there
%% are two of them.
%% When calling several nodes, the nodes are called in parallel.
ctpm_globalnames() ->
ctpm_globalnames(all).
ctpm_globalnames(Nodes) ->
gen_server:call(?CONTROLLER,{meta_pattern,Nodes,{remove_global_register,[]}},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% ctp_all(Nodes)={ok,NodeResults}|{error,Reason}
%% ctp_all()={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...],
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason},
%%
%% Clears all both global and local trace patterns on all or specified nodes.
%% Does not effect meta patterns.
ctp_all() ->
gen_server:call(?CONTROLLER,{ctp_all,all},?CALL_TIMEOUT).
ctp_all(Nodes) ->
gen_server:call(?CONTROLLER,{ctp_all,Nodes},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% suspend(Nodes,Reason)={ok,NodeResults}|{error,Reason}
%% suspend(Reason)={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node],
%% Reason=term(); supposed to describe the reason why suspended.
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason},
%%
%% Suspend all or specified Nodes with reason Reason. Suspend means that all
%% process trace flags are removed and all meta-patterns.
suspend(Nodes, Reason) ->
gen_server:call(?CONTROLLER,{suspend,Reason,Nodes},?CALL_TIMEOUT).
suspend(Reason) ->
gen_server:call(?CONTROLLER,{suspend,Reason,all},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% cancel_suspension(Nodes)={ok,NodeResults}|{error,Reason}
%% cancel_suspension()={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...],
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult=ok|{error,Reason},
%% Cancel suspension on all or specified Nodes. Note that this does not imply
%% that "business" is resumed as before. You must reactivate flags and meta-patter
%% your self.
cancel_suspension(Nodes) ->
gen_server:call(?CONTROLLER,{cancel_suspension,Nodes},?CALL_TIMEOUT).
cancel_suspension() ->
gen_server:call(?CONTROLLER,{cancel_suspension,all},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% get_status(Nodes)={ok,NodeResults}|{error,Reason}
%% get_status()={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...],
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,{State,Status}}|{error,Reason},
%% State=new|idle|tracing
%% Status=running|{suspended,SReason}
%%
%% Get Status form all or specified runtime components.
get_status(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{get_status,Nodes},?CALL_TIMEOUT).
get_status() ->
gen_server:call(?CONTROLLER,{get_status,all},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% get_tracerdata()={ok,NodeResults}|NodeResult|{error,Reason}
%% get_tracerdata(Nodes)={ok,NodeResults}|{error,Reason}
%% Nodes=[Node,...],
%% NodeResult={ok,NResult}|{error,Reason},
%% NResult=TracerData|no_tracerdata
%% TracerData will be exactly as it was specified when doing init_tracing.
%%
%% Get TracerData form all or specified runtime components.
get_tracerdata() ->
gen_server:call(?CONTROLLER,{get_tracerdata,all},?CALL_TIMEOUT).
get_tracerdata(Nodes) when is_list(Nodes) ->
gen_server:call(?CONTROLLER,{get_tracerdata,Nodes},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% list_logs(TracerData)={ok,NodeResults}|NodeResult|{error,Reason}
%% list_logs(NodeList)={ok,NodeResults}|{error,Reason}
%% list_logs()={ok,NodeResults}|NodeResult|{error,Reason}
%% TracerData see init_tracing/1/2
%% NodeList=[NodeSpec,...]
%% NodeSpec=Node|{Node,TracerData}
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,FileList}|{ok,no_log}|{error,Reason}
%% FileList=[FileType,...], one or more of different types.
%% FileType={trace_log,Dir,Files}|{ti_log,Dir,Files}
%% Files=[FileNameWithOutPath,...]
%%
%% Ask local or specified runtime components for now existing logs given
%% TracerData. If TracerData is left out, the runtime components TracerData,
%% if existing, will be used instead.
list_logs() ->
gen_server:call(?CONTROLLER,list_logs,?CALL_TIMEOUT).
list_logs(TracerDataOrNodesList) when is_list(TracerDataOrNodesList) ->
gen_server:call(?CONTROLLER,{list_logs,TracerDataOrNodesList},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% fetch_log(LogSpecList,DestDir,Prefix)={ok,NodeResults}|{error,not_distributed}|
%% {error,Reason}
%% fetch_log(DestDir,Prefix)={ok,NodeResults}|{error,not_distributed}|
%% {error,Reason}
%% fetch_log(ToNode,DestDir,Prefix)=
%% fetch_log(ToNode,LogSpecList,DestDir,Prefix)=
%% DestDir=string(), to where the fetched files shall be placed.
%% Prefix=string(), prefix on locally saved fetched files.
%% LogSpecList=[LogSpec,...],
%% LogSpec={Node,FileSpecList}|Node|{Node,TracerData}
%% TracerData=see init_tracing/1/2
%% FileSpecList=[{trace_log,Dir,FileList},{ti_log,Dir,FileList}]
%% where each tuple-item is optional.
%% FileList=[RemoteFileName,...]
%% ToNode=atom()
%% NodeResult={Conclusion,ResultFileSpec}|no_log|{error,NReason}
%% Conclusion=complete|incomplete
%% ResultFileSpec=[{trace_log,FileResults},{ti_log,FileResults}]
%% FileResults=[FileResult,...]
%% FileResult={ok,FileName}|{error,FReason}
%% NReason=own_node|Reason
%% FReason = {file_open,{posix(),FileName}} |
%% {file_open,{posix(),RemoteFileName}}
%% {file_open,{posix(),[DestDir,Prefix,RemoteFileName]}}
%% {file_write,{posix(),FileName}} |
%% {truncated,FileName}
%% {truncated,{Reason,FileName}}
%% posix() - an atom which is named from the Posix error codes used in
%% Unix, and in the runtime libraries of most C compilers.
%% See module file in Kernel Reference manual.
%%
%% Copies logfiles over distributed erlang to ToNode. This
%% function can only be used in a distributed system.
%% The resulting transfered files will have the prefix Prefix and will be
%% located in DestDir.
%% Note that the client process using this function will wait until all files
%% are moved. The job can be cancelled, causing any already copied files to be
%% removed, by simply terminating the waiting client process.
fetch_log(DestDir,Prefix) when is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,node(),all,DestDir,Prefix},infinity).
fetch_log(ToNode,DestDir,Prefix) when is_atom(ToNode),is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,ToNode,all,DestDir,Prefix},infinity);
fetch_log(LogSpecList,DestDir,Prefix) when is_list(LogSpecList),is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,node(),LogSpecList,DestDir,Prefix},infinity).
fetch_log(ToNode,LogSpecList,DestDir,Prefix)
when is_atom(ToNode),is_list(LogSpecList),is_list(DestDir),is_list(Prefix) ->
gen_server:call(?CONTROLLER,{fetch_log,ToNode,LogSpecList,DestDir,Prefix},infinity).
%% ------------------------------------------------------------------------------
%% delete_log(Nodes,TracerData)={ok,NodeResults}|{error,Reason}
%% delete_log(NodeSpecList)={ok,NodeResults}|{error,Reason}
%% delete_log(Spec)={ok,NodeResults}|NodeResult|{error,Reason}
%% delete_log(TracerData)={ok,NodeResults}|NodeResult|{error,Reason}
%% delete_log()={ok,NodeResults}|NodeResult|{error,Reason}
%% Nodes=[Node,...],
%% NodeSpecList=[{Node,Spec},...]
%% Spec=[AbsPathFileName,...]|LogSpecs
%% LogSpecs=[LogSpec,...]
%% LogSpec={trace_log,Dir,[FileNameWithoutPath,...]}|
%% {ti_log,Dir,[FileNameWithoutPath,...]}
%% TracerData = see init_tracing/1/2
%% NodeResults=[{Node,NodeResult},...]
%% NodeResult={ok,no_log}|{ok,LogInfos}|{ok,FileInfos}
%% LogInfos=[LogInfo,...]
%% LogInfo={trace_log,FileInfos}|{ti_log,FileInfos}
%% FileInfos=[FileInfo,...]
%% FileInfo={ok,FileName}|{error,Reason} whether FileName contains
%% full path or not depends on if AbsPathFileName or LogSpec was
%% used when specifying the files.
%%
%% Deletes listed files or files corresponding to TracerData from specified
%% or all Nodes. If no TracerData or list of files is specified in the call the
%% TracerData at Node will be used to identify log files to delete.
delete_log() ->
gen_server:call(?CONTROLLER,{delete_log,all},?CALL_TIMEOUT).
delete_log(What) ->
gen_server:call(?CONTROLLER,{delete_log,What},?CALL_TIMEOUT).
delete_log(Nodes,Spec) ->
gen_server:call(?CONTROLLER,{delete_log,Nodes,Spec},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% subscribe()= same as subscribe(self())
%% subscribe(Pid)=ok|{error,Reason}
%% Pid=pid(),
%% Reason =
%% Add Pid or self() to event sending list. Note that it is possible to add a
%% pid several times and that the Pid then will receive several event messages.
%% All events will be sent to all subscribers in the event sending list.
%% Event={inviso_event,ControllerPid,erlang:localtime(),Msg},
%% Msg=
%% {connected, Node, {Tag, {State, Status}}}
%% {disconnected, Node, not_applicable}
%% {state_change, Node, {State, Status}}
%% {port_down, Node, Reason}
%% Node = node() | local_runtime (when running in a non-distributed
%% environment)
subscribe() ->
gen_server:call(?CONTROLLER,{subscribe,self()},?CALL_TIMEOUT).
subscribe(Pid) ->
gen_server:call(?CONTROLLER,{subscribe,Pid},?CALL_TIMEOUT).
%% -----------------------------------------------------------------------------
%% unsubscribe()= same as unsubscribe(self())
%% unsubscribe(Pid)=ok
%% Pid=pid(),
%%
%% Remove, if present, first occurrence of Pid or self() from event sending
%% list. Note that it is not an error to remove a non existing subscription.
unsubscribe() ->
gen_server:call(?CONTROLLER,{unsubscribe,self()},?CALL_TIMEOUT).
unsubscribe(Pid) ->
gen_server:call(?CONTROLLER,{unsubscribe,Pid},?CALL_TIMEOUT).
%% ------------------------------------------------------------------------------
%% debuging the controller
%% ----------------------------------------------------------------------------
state() ->
?CONTROLLER ! state.
%% debuging the runtime component
state(Node) ->
?CONTROLLER ! {state, Node}.
%%% end of file