%% ---
%%  Excerpted from "Programming Erlang",
%%  published by The Pragmatic Bookshelf.
%%  Copyrights apply to this code. It may not be used to create training material,
%%  courses, books, articles, and the like. Contact us if you are in doubt.
%%  We make no guarantees that this code is fit for any purpose.
%%  Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information.
%%  
%%  日本語版の『プログラミングErlang』、およびサンプルコードについては、
%%   http://ssl.ohmsha.co.jp/cgi-bin/menu.cgi?ISBN=978-4-274-06714-3 を確認してください。
%% ---
-module(tracer_test).

-include_lib("stdlib/include/ms_transform.hrl").
-compile(export_all).

%% www.otp.org/doc/man/ms_transform.html


test1() ->
    dbg:tracer(),
    dbg:tpl(tracer_test,fib,'_',
	    dbg:fun2ms(fun(_) -> return_trace() end)),
    dbg:p(all,[c]),
    tracer_test:fib(4).



test2() ->
    trace_module(tracer_test, fun() -> fib(4) end).

fib(0) -> 1;
fib(1) -> 1;
fib(N) -> fib(N-1) + fib(N-2).

	

trace_module(Mod, StartFun) ->
    %% トレースを行うプロセスを生成する
    spawn(fun() -> trace_module1(Mod, StartFun) end).

trace_module1(Mod, StartFun) ->
    %% 次の行の意味: Modにおけるすべての関数呼び出しや
    %%             戻り値をトレースする
    erlang:trace_pattern({Mod, '_','_'},  
			 [{'_',[],[{return_trace}]}], 
			 [local]),
    %% トレースを行うための関数を生成する
    S = self(),
    Pid = spawn(fun() -> do_trace(S, StartFun) end),
    %% トレースの準備をする。プロセスPidのトレースを開始
    %% するようにシステムに指示する
    erlang:trace(Pid, true, [call,procs]),
    %% Pidに処理を開始するように伝える
    Pid ! {self(), start},
    trace_loop().

%% do_traceはParentに指示されたらStartFun()を評価する
do_trace(Parent, StartFun) ->
    receive
	{Parent, start} ->
	    StartFun()
    end.

%% trace_loopは関数呼び出しと戻り値を表示する
trace_loop() ->
    receive
	{trace,_,call, X} ->
	    io:format("Call: ~p~n",[X]),
	    trace_loop();
	{trace,_,return_from, Call, Ret} ->
	    io:format("Return From: ~p => ~p~n",[Call, Ret]),
	    trace_loop();
	Other ->
	    %% 対象外のメッセージを受け取ったら表示する
	    io:format("Other = ~p~n",[Other]),
	    trace_loop()
    end.


    
