RabbitMQの挙動の調べかた

Erlangのお勉強も兼ねて。

まず、Erlangをインストールする。

$ sudo apt-get install erlang

ソースコードを読むとき用の仕込みとして、.emascに以下のような記述を追加する。

(setq load-path (cons "/usr/lib/erlang/lib/tools-2.6.7/emacs " load-path))
(setq erlang-root-dir "/usr/lib/erlang")
(require 'erlang-start)
(add-hook 'erlang-mode-hook '(lambda () (gtags-mode 1)))

rabbitmq-serverのビルドはドキュメントにあるとおりにやればできた。

$ hg clone http://hg.rabbitmq.com/rabbitmq-codegen
$ hg clone http://hg.rabbitmq.com/rabbitmq-server
$ cd rabbitmq-server
$ make

exuberant-ctagsがErlangに対応していたので、ソース読み用にそれを利用する。

$ gtags --gtagslabel=exuberant-ctags

makeのrunターゲットを実行すると、serverが起動する。データファイルやログは/tmp下に出力される。

$ make run

起動したerlang shellで関数を実行することで、状態を確認できる。

1> regs().
...(省略)
rabbit                <0.103.0>    application_master:start_        45055    0
rabbit_alarm          <0.146.0>    gen_event:init_it/6                704    0
rabbit_alarm_sup      <0.145.0>    supervisor:rabbit_restart           99    0
rabbit_amqqueue_sup   <0.188.0>    supervisor2:init/1                  98    0
rabbit_direct_client_ <0.200.0>    supervisor2:init/1                  54    0
rabbit_disk_monitor   <0.150.0>    rabbit_disk_monitor:init/      2734286    0
rabbit_disk_monitor_s <0.149.0>    supervisor:rabbit_restart           99    0
rabbit_event          <0.142.0>    gen_event:init_it/6                609    0
rabbit_event_sup      <0.141.0>    supervisor:rabbit_restart           99    0
rabbit_guid           <0.174.0>    rabbit_guid:init/1                 110    0
rabbit_guid_sup       <0.173.0>    supervisor:rabbit_restart         1002    0
rabbit_log            <0.144.0>    rabbit_log:init/1                  851    0
...(省略)

トレースのためのモジュールを呼び出してみる。dbg:tpはトレース対象の指定で、モジュール、関数、アリティ、引数、返り値などのパターンを、match_specにしたがって指定できる。また、dbg:pはどのプロセスをトレース対象とするかの指定で、allだと全部。詳細はdbgのドキュメントで確認できる。

1> dbg:start().
{ok,<0.206.0>}

2> Tracer = dbg:tracer().
{ok,<0.206.0>}

3> Tracer.
{ok,<0.206.0>}

4> dbg:tp(rabbit_variable_queue, '_', []).
{ok,[{matched,rabbit@x121e,36}]}

5> dbg:p(all, c).

トレースを仕掛けた状態で、別コンソールからチュートリアルをダウンロードして実行してみる。

$ cd ~/srcs
$ git clone https://github.com/rabbitmq/rabbitmq-tutorials.git
$ cd rabbitmq-tutorials/erlang/
$ wget http://www.rabbitmq.com/releases/rabbitmq-erlang-client/v3.0.4/rabbit_common-3.0.4.ez
$ unzip rabbit_common-3.0.4.ez
$ ln -s rabbit_common-3.0.4 rabbit_common
$ wget http://www.rabbitmq.com/releases/rabbitmq-erlang-client/v3.0.4/amqp_client-3.0.4.ez
$ unzip amqp_client-3.0.4.ez
$ ln -s amqp_client-3.0.4 amqp_client

$ ./send.erl 
 [x] Sent 'Hello World!'

$ ./receive.erl 
 [*] Waiting for messages. To exit press CTRL+C
 [x] Received <<"Hello World!">>

トレースを仕掛けた方のコンソールを見ると、トレースした結果がわらわらと出力されている。

(<0.233.0>) call rabbit_variable_queue:init({amqqueue,{resource,<<"/">>,queue,<<"hello">>},
          false,false,none,[],<0.233.0>,[],[],undefined,[]},false,#Fun<rabbit_amqqueue_process.5.115664289>)
(<0.233.0>) call rabbit_variable_queue:drain_confirmed({vqstate,
    {0,{[],[]}},
    {0,{[],[]}},
    {delta,undefined,0,undefined},
    {0,{[],[]}},
    {0,{[],[]}},
    0,
    {0,nil},
    {0,nil},
    {qistate,"/tmp/rabbitmq-rabbit-mnesia/queues/850UOO636QPB9FAFP10MQ2OM",
        {{dict,0,16,16,8,80,48,
             {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
             {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}},
         []},
        undefined,0,65536,#Fun<rabbit_variable_queue.2.87551502>,
        {0,nil}},
    {undefined,
        {client_msstate,msg_store_transient,
            <<239,174,50,42,106,128,27,95,229,82,194,50,42,156,133,246>>,
            {dict,0,16,16,8,80,48,
                {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
                {{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}},
            {state,200769,"/tmp/rabbitmq-rabbit-mnesia/msg_store_transient"},
            rabbit_msg_store_ets_index,
            "/tmp/rabbitmq-rabbit-mnesia/msg_store_transient",<0.180.0>,
            204866,196665,208963,213060}},
    false,0,0,0,infinity,0,0,0,0,0,

トレースを止めて、設定した条件をクリアするためには以下を実行する。

> dbg:stop_clear().