<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html xmlns:fn="http://www.w3.org/2005/02/xpath-functions"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" href="../../../../doc/otp_doc.css" type="text/css"> <title>Erlang -- Advanced examples</title> </head> <body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000"><div id="container"> <script id="js" type="text/javascript" language="JavaScript" src="../../../../doc/js/flipmenu/flipmenu.js"></script><script id="js2" type="text/javascript" src="../../../../doc/js/erlresolvelinks.js"></script><script language="JavaScript" type="text/javascript"> <!-- function getWinHeight() { var myHeight = 0; if( typeof( window.innerHeight ) == 'number' ) { //Non-IE myHeight = window.innerHeight; } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) { //IE 6+ in 'standards compliant mode' myHeight = document.documentElement.clientHeight; } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) { //IE 4 compatible myHeight = document.body.clientHeight; } return myHeight; } function setscrollpos() { var objf=document.getElementById('loadscrollpos'); document.getElementById("leftnav").scrollTop = objf.offsetTop - getWinHeight()/2; } function addEvent(obj, evType, fn){ if (obj.addEventListener){ obj.addEventListener(evType, fn, true); return true; } else if (obj.attachEvent){ var r = obj.attachEvent("on"+evType, fn); return r; } else { return false; } } addEvent(window, 'load', setscrollpos); //--></script><div id="leftnav"><div class="innertube"> <img alt="Erlang logo" src="../../../../doc/erlang-logo.png"><br><small><a href="users_guide.html">User's Guide</a><br><a href="index.html">Reference Manual</a><br><a href="release_notes.html">Release Notes</a><br><a href="../pdf/et-1.4.4.2.pdf">PDF</a><br><a href="../../../../doc/index.html">Top</a></small><p><strong>Event Tracer (ET)</strong><br><strong>User's Guide</strong><br><small>Version 1.4.4.2</small></p> <br><a href="javascript:openAllFlips()">Expand All</a><br><a href="javascript:closeAllFlips()">Contract All</a><p><small><strong>Chapters</strong></small></p> <ul class="flipMenu" imagepath="../../../../doc/js/flipmenu"> <li id="no" title="Introduction" expanded="false">Introduction<ul> <li><a href="et_intro.html"> Top of chapter </a></li> <li title="Scope and Purpose"><a href="et_intro.html#id64170">Scope and Purpose</a></li> <li title="Prerequisites"><a href="et_intro.html#id61234">Prerequisites</a></li> <li title="About This Manual"><a href="et_intro.html#id61059">About This Manual</a></li> <li title="Where to Find More Information"><a href="et_intro.html#id60052">Where to Find More Information</a></li> </ul> </li> <li id="no" title="Tutorial" expanded="false">Tutorial<ul> <li><a href="et_tutorial.html"> Top of chapter </a></li> <li title="Visualizing Message Sequence Charts"><a href="et_tutorial.html#id60778">Visualizing Message Sequence Charts</a></li> <li title="Four Modules"><a href="et_tutorial.html#id57439">Four Modules</a></li> <li title="The Event Tracer Interface"><a href="et_tutorial.html#id61823">The Event Tracer Interface</a></li> <li title="The Collector and Viewer"><a href="et_tutorial.html#id56971">The Collector and Viewer</a></li> <li title="The Selector"><a href="et_tutorial.html#id58113">The Selector</a></li> <li title="How To Put It Together"><a href="et_tutorial.html#id62590">How To Put It Together</a></li> </ul> </li> <li id="no" title="Description" expanded="false">Description<ul> <li><a href="et_desc.html"> Top of chapter </a></li> <li title="Overview"><a href="et_desc.html#id62437">Overview</a></li> <li title="Filters and dictionary"><a href="et_desc.html#id63954">Filters and dictionary</a></li> <li title="Trace clients"><a href="et_desc.html#id63394">Trace clients</a></li> <li title="Global tracing"><a href="et_desc.html#id63541">Global tracing</a></li> <li title="Viewer window"><a href="et_desc.html#id63682">Viewer window</a></li> <li title="Configuration"><a href="et_desc.html#id65519">Configuration</a></li> <li title="Contents viewer window"><a href="et_desc.html#id65550">Contents viewer window</a></li> </ul> </li> <li id="loadscrollpos" title="Advanced examples" expanded="true">Advanced examples<ul> <li><a href="et_examples.html"> Top of chapter </a></li> <li title="A simulated Mnesia transaction"><a href="et_examples.html#id65821">A simulated Mnesia transaction</a></li> <li title="Some convenient functions used in the Mnesia transaction example"><a href="et_examples.html#id65930">Some convenient functions used in the Mnesia transaction example</a></li> <li title="Erlang trace of a real Mnesia transaction"><a href="et_examples.html#id66086">Erlang trace of a real Mnesia transaction</a></li> <li title="Erlang trace of Megaco startup"><a href="et_examples.html#id66211">Erlang trace of Megaco startup</a></li> </ul> </li> </ul> </div></div> <div id="content"> <div class="innertube"> <h1>4 Advanced examples</h1> <h3><a name="id65821">4.1 A simulated Mnesia transaction</a></h3> <p>The Erlang code for running the simulated <span class="code">Mnesia</span> transaction example in the previous chapter is included in the <span class="code">et/examples/et_demo.erl</span> file:</p> <p></p> <div class="example"><pre> sim_trans() -> sim_trans([]). sim_trans(ExtraOptions) -> Options = [{dict_insert, {filter, mgr_actors}, fun mgr_actors/1}], {ok, Viewer} = et_viewer:start_link(Options ++ ExtraOptions), Collector = et_viewer:get_collector_pid(Viewer), et_collector:report_event(Collector, 60, my_shell, mnesia_tm, start_outer, "Start outer transaction"), et_collector:report_event(Collector, 40, mnesia_tm, my_shell, new_tid, "New transaction id is 4711"), et_collector:report_event(Collector, 20, my_shell, mnesia_locker, try_write_lock, "Acquire write lock for {my_tab, key}"), et_collector:report_event(Collector, 10, mnesia_locker, my_shell, granted, "You got the write lock for {my_tab, key}"), et_collector:report_event(Collector, 60, my_shell, do_commit, "Perform transaction commit"), et_collector:report_event(Collector, 40, my_shell, mnesia_locker, release_tid, "Release all locks for transaction 4711"), et_collector:report_event(Collector, 60, my_shell, mnesia_tm, delete_transaction, "End of outer transaction"), et_collector:report_event(Collector, 20, my_shell, end_outer, "Transaction returned {atomic, ok}"), {collector, Collector}. </pre></div> <p></p> <div class="example"><pre> mgr_actors(E) when is_record(E, event) -> Actor = fun(A) -> case A of mnesia_tm -> trans_mgr; mnesia_locker -> lock_mgr; _ -> A end end, {true, E#event{from = Actor(E#event.from), to = Actor(E#event.to), contents = [{orig_from, E#event.from}, {orig_to, E#event.to}, {orig_contents, E#event.contents}]}}.</pre></div> <p>If you invoke the <span class="code">et_demo:sim_trans()</span> function, a <span class="code">Viewer</span> window will pop up and the sequence trace will be almost the same as if the following <span class="code">Mnesia</span> transaction would have been run:</p> <p></p> <div class="example"><pre> mnesia:transaction(fun() -> mnesia:write({my_tab, key, val}) end).</pre></div> <p>And the viewer window will look like:</p> <p></p> <div class="example"><pre> Erlang R13B03 (erts-5.7.4) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false] Eshell V5.7.4 (abort with ^G) 1> {ok, Viewer} = et_viewer:start([]). {ok,<0.40.0>;} 2> et_demo:sim_trans(). {ok,{table_handle,<0.45.0>,24596,trace_ts, #Fun<et_collector.0.62831470>}}</pre></div> <p></p> <img alt="IMAGE MISSING" src="sim_trans.png"><br> <em>Figure 4.1: A simulated <span class="code">Mnesia</span> transaction which writes one record</em> <h3><a name="id65930">4.2 Some convenient functions used in the Mnesia transaction example</a></h3> <p>The <span class="code">module_as_actor</span> filter converts the <span class="code">Event Records</span> so the module names becomes actors and the invoked functions becomes labels. If the information about who the caller was it will be displayed as an arrow directed from the caller to the callee. The <span class="code">[{message, {caller}}, {return_trace}]</span> options to <span class="code">dbg:tpl/2</span> function will imply the necessary information in the Erlang traces. Here follows the <span class="code">module_as_actor</span> filter:</p> <p></p> <div class="example"><pre> module_as_actor(E) when is_record(E, event) -> case lists:keysearch(mfa, 1, E#event.contents) of {value, {mfa, {M, F, _A}}} -> case lists:keysearch(pam_result, 1, E#event.contents) of {value, {pam_result, {M2, _F2, _A2}}} -> {true, E#event{label = F, from = M2, to = M}}; _ -> {true, E#event{label = F, from = M, to = M}} end; _ -> false end.</pre></div> <p>The <span class="code">plain_process_info</span> filter does not alter the <span class="code">Event Records</span>. It merely ensures that the event not related to processes are skipped:</p> <p></p> <div class="example"><pre> plain_process_info(E) when is_record(E, event) -> case E#event.label of send -> true; send_to_non_existing_process -> true; 'receive' -> true; spawn -> true; exit -> true; link -> true; unlink -> true; getting_linked -> true; {seq_send, _Label} -> true; {seq_receive, _Label} -> true; {seq_print, _Label} -> true; {drop, _N} -> true; _ -> false end.</pre></div> <p>The <span class="code">plain_process_info_nolink</span> filter does not alter the <span class="code">Event Records</span>. It do makes use of the <span class="code">plain_process_info</span> , but do also ensure that the process info related to linking and unlinking is skipped:</p> <p></p> <div class="example"><pre> plain_process_info_nolink(E) when is_record(E, event) -> (E#event.label /= link) and (E#event.label /= unlink) and (E#event.label /= getting_linked) and plain_process_info(E). </pre></div> <p>In order to simplify the startup of an <span class="code">et_viewer</span> process with the filters mentioned above, plus some others (that also are found in <span class="code">et/examples/et_demo.erl</span> src/et_collector.erl the <span class="code">et_demo:start/0,1</span> functions can be used:</p> <p></p> <div class="example"><pre> start() -> start([]). start(ExtraOptions) -> Options = [{trace_global, true}, {parent_pid, undefined}, {max_actors, infinity}, {max_events, 1000}, {active_filter, module_as_actor}], et_viewer:start_link(filters() ++ Options ++ ExtraOptions).</pre></div> <p>A simple one-liner starts the tool:</p> <div class="example"><pre> erl -pa ../examples -s et_demo</pre></div> <p>The filters are included by the following parameters:</p> <p></p> <div class="example"><pre> filters() -> [{dict_insert, {filter, module_as_actor}, fun module_as_actor/1}, {dict_insert, {filter, plain_process_info}, fun plain_process_info/1}, {dict_insert, {filter, plain_process_info_nolink}, fun plain_process_info_nolink/1}, {dict_insert, {filter, named_process_info}, fun named_process_info/1}, {dict_insert, {filter, named_process_info_nolink}, fun named_process_info_nolink/1}, {dict_insert, {filter, node_process_info}, fun node_process_info/1}, {dict_insert, {filter, node_process_info_nolink}, fun node_process_info_nolink/1}, {dict_insert, {filter, application_as_actor}, fun application_as_actor/1} ].</pre></div> <h3><a name="id66086">4.3 Erlang trace of a real Mnesia transaction</a></h3> <p>The following piece of code <span class="code">et_demo:trace_mnesia/0</span> activates call tracing of both local and external function calls for all modules in the <span class="code">Mnesia</span> application. The call traces are configured cover all processes (both existing and those that are spawned in the future) and include timestamps for trace data. It do also activate tracing of process related events for <span class="code">Mnesia</span>'s static processes plus the calling process (that is your shell). Please, observe that the <span class="code">whereis/1</span> call in the following code requires that both the traced <span class="code">Mnesia</span> application and the <span class="code">et_viewer</span> is running on the same node:</p> <p></p> <div class="example"><pre> trace_mnesia() -> Modules = mnesia:ms(), Spec = [{message, {caller}}, {return_trace}], Flags = [send, 'receive', procs, timestamp], dbg:p(all, [call, timestamp]), [dbg:tpl(M, [{'_', [], Spec}]) || M <- Modules], LocallyRunningServers = [M || M <- Modules, whereis(M) /= undefined], [dbg:p(whereis(RS), Flags) || RS <- LocallyRunningServers], dbg:p(self(), Flags), LocallyRunningServers.</pre></div> <p>The <span class="code">et_demo:live_trans/0</span> function starts the global <span class="code">Collector</span>, starts a <span class="code">Viewer</span>, starts <span class="code">Mnesia</span>, creates a local table, activates tracing (as described above) and registers the shell process is as 'my_shell' for clarity. Finally a simple <span class="code">Mnesia</span> transaction that writes a single record is run:</p> <p></p> <div class="example"><pre> live_trans() -> live_trans([]). live_trans(ExtraOptions) -> Options = [{title, "Mnesia tracer"}, {hide_actions, true}, {active_filter, named_process_info_nolink}], et_demo:start(Options ++ ExtraOptions), mnesia:start(), mnesia:create_table(my_tab, [{ram_copies, [node()]}]), et_demo:trace_mnesia(), register(my_shell, self()), mnesia:transaction(fun() -> mnesia:write({my_tab, key, val}) end).</pre></div> <p>Now we run the <span class="code">et_demo:live_trans/0</span> function:</p> <p></p> <div class="example"><pre> erl -pa ../examples Erlang R13B03 (erts-5.7.4) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false] Eshell V5.7.4 (abort with ^G) 1> et_demo:live_trans(). {atomic,ok}</pre></div> <p>Please, explore the different filters in order to see how the traced transaction can be seen from different point of views:</p> <p></p> <img alt="IMAGE MISSING" src="live_trans.png"><br> <em>Figure 4.2: A real <span class="code">Mnesia</span> transaction which writes one record</em> <h3><a name="id66211">4.4 Erlang trace of Megaco startup</a></h3> <p>The <span class="code">Event Tracer (ET)</span> tool was initially written in order to demonstrate how messages where sent over the <span class="code">Megaco</span> protocol. This were back in the old days before the standard bodies of <span class="code">IETF</span> and <span class="code">ITU</span> had approved <span class="code">Megaco</span> (also called <span class="code">H.248</span>) as an international standard.</p> <p>In the <span class="code">Megaco</span> application of Erlang/OTP, the code is carefully instrumented with calls to <span class="code">et:trace_me/5</span>. For each call a detail level is given in order to enable dynamic control of the trace level in a simple manner.</p> <p>The <span class="code">megaco_filter</span> module implements a customized filter for <span class="code">Megaco</span> messages. It does also make use of <span class="code">trace_global</span> combined with usage of the <span class="code">trace_pattern</span>:</p> <p></p> <div class="example"><pre> -module(megaco_filter). -export([start/0]). start() -> Options = [{event_order, event_ts}, {scale, 3}, {max_actors, infinity}, {trace_pattern, {megaco, max}}, {trace_global, true}, {dict_insert, {filter, megaco_filter}, fun filter/1}, {active_filter, megaco_filter}, {title, "Megaco tracer - Erlang/OTP"}], et_viewer:start(Options).</pre></div> <p>First we start an Erlang node with a global <span class="code">Collector</span> and its <span class="code">Viewer</span>.</p> <p></p> <div class="example"><pre> erl -sname observer Erlang R13B03 (erts-5.7.4) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false] Eshell V5.7.4 (abort with ^G) (observer@falco)1> megaco_filter:start(). {ok,<0.48.0>}</pre></div> <p>Secondly we start another Erlang node which we connect the observer node, before we start the application that we want to trace. In this case we start a Media Gateway Controller that listens for both TCP and UDP on the text and binary ports for Megaco:</p> <p></p> <div class="example"><pre> erl -sname mgc -pa ../../megaco/examples/simple Erlang R13B03 (erts-5.7.4) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false] Eshell V5.7.4 (abort with ^G) (mgc@falco)1> net:ping(observer@falco). pong (mgc@falco)2> megaco:start(). ok (mgc@falco)3> megaco_simple_mgc:start(). {ok,[{ok,2944, {megaco_receive_handle,{deviceName,"controller"}, megaco_pretty_text_encoder,[],megaco_tcp,dynamic}}, {ok,2944, {megaco_receive_handle,{deviceName,"controller"}, megaco_pretty_text_encoder,[],megaco_udp,dynamic}}, {ok,2945, {megaco_receive_handle,{deviceName,"controller"}, megaco_binary_encoder,[],megaco_tcp,dynamic}}, {ok,2945, {megaco_receive_handle,{deviceName,"controller"}, megaco_binary_encoder,[],megaco_udp,dynamic}}]}</pre></div> <p>And finally we start an Erlang node for the Media Gateways and connect to the observer node. Each Media Gateway connects to the controller and sends an initial Service Change message. The controller accepts the gateways and sends a reply to each one using the same transport mechanism and message encoding according to the preference of each gateway. That is all combinations of TCP/IP transport, UDP/IP transport, text encoding and ASN.1 BER encoding:</p> <p></p> <div class="example"><pre> Erlang R13B03 (erts-5.7.4) [64-bit] [smp:4:4] [rq:4] [async-threads:0] [kernel-poll:false] Eshell V5.7.4 (abort with ^G) (mg@falco)1> net:ping(observer@falco). pong (mg@falco)2> megaco_simple_mg:start(). [{{deviceName,"gateway_tt"}, {error,{start_user,megaco_not_started}}}, {{deviceName,"gateway_tb"}, {error,{start_user,megaco_not_started}}}, {{deviceName,"gateway_ut"}, {error,{start_user,megaco_not_started}}}, {{deviceName,"gateway_ub"}, {error,{start_user,megaco_not_started}}}] (mg@falco)3> megaco:start(). ok (mg@falco)4> megaco_simple_mg:start(). [{{deviceName,"gateway_tt"}, {1, {ok,[{'ActionReply',0,asn1_NOVALUE,asn1_NOVALUE, [{serviceChangeReply, {'ServiceChangeReply', [{megaco_term_id,false,["root"]}], {serviceChangeResParms, {'ServiceChangeResParm', {deviceName,"controller"}, asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, asn1_NOVALUE}}}}]}]}}}, {{deviceName,"gateway_tb"}, {1, {ok,[{'ActionReply',0,asn1_NOVALUE,asn1_NOVALUE, [{serviceChangeReply, {'ServiceChangeReply', [{megaco_term_id,false,["root"]}], {serviceChangeResParms, {'ServiceChangeResParm', {deviceName,"controller"}, asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, asn1_NOVALUE}}}}]}]}}}, {{deviceName,"gateway_ut"}, {1, {ok,[{'ActionReply',0,asn1_NOVALUE,asn1_NOVALUE, [{serviceChangeReply, {'ServiceChangeReply', [{megaco_term_id,false,["root"]}], {serviceChangeResParms, {'ServiceChangeResParm', {deviceName,"controller"}, asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE, asn1_NOVALUE}}}}]}]}}}, {{deviceName,"gateway_ub"}, {1, {ok,[{'ActionReply',0,asn1_NOVALUE,asn1_NOVALUE, [{serviceChangeReply, {'ServiceChangeReply', [{megaco_term_id,false,["root"]}], {serviceChangeResParms, {'ServiceChangeResParm', {deviceName,"controller"}, asn1_NOVALUE,asn1_NOVALUE, asn1_NOVALUE,...}}}}]}]}}}]</pre></div> <p>The <span class="code">Megaco</span> adopted viewer looks like this, when we have clicked on the <strong>[gateway_tt]</strong> actor name in order to only display the events regarding that actor:</p> <p></p> <img alt="IMAGE MISSING" src="megaco_tracer.png"><br> <em>Figure 4.3: The viewer adopted for Megaco</em> <p>A pretty printed <span class="code">Megaco</span> message looks like this:</p> <p></p> <img alt="IMAGE MISSING" src="megaco_filter.png"><br> <em>Figure 4.4: A textual <span class="code">Megaco</span> message</em> <p>And the corresponding internal form for the same <span class="code">Megaco</span> message looks like this:</p> <p></p> <img alt="IMAGE MISSING" src="megaco_collector.png"><br> <em>Figure 4.5: The internal form of a <span class="code">Megaco</span> message</em> </div> <div class="footer"> <hr> <p>Copyright © 2002-2012 Ericsson AB. All Rights Reserved.</p> </div> </div> </div></body> </html>