遥かへのスピードランナー

シリコンバレーでAndroidアプリの開発してます。コンピュータービジョン・3D・アルゴリズム界隈にもたまに出現します。

Firefoxの内部動作を理解する方法1-デバッグログを出力する

FireMobileSimulatorも含めたFirefoxアドオンの今後の開発の可能性を探る為に、Firefoxの内部動作をもう少し詳しく知りたいなあと思ってたんですが、ソースを読んでみても、細かいところは分かっても、全体を通してどう動いているかがどうにも分かりません。。
しかし、Firefoxを含む各種MozillaプロダクトにはNSPRという便利なモジュールが組み込まれていて、再ビルドなどを行うことなしにデバッグログをファイルに出力させることができるということを最近知りました。
このログを追えば、そのプロダクトのだいたいの動きを知ることができます。

NSPRモジュールのログ出力方法

NSPRモジュールの使い方は簡単で、Windowsの環境変数でNSPR_LOG_MODULESとNSPR_LOG_FILEを指定してFirefoxを起動するだけです。

それぞれの環境変数の説明は以下の通り。

NSPR_LOG_MODULES

「モジュール名:ログレベル」をカンマ区切りで指定します。
すべてを網羅できているか保証はないのですが、ここにモジュール名とソースファイル名の対応付けがあります。
ログレベルは0から5までの数値を指定します。それぞれの数値の意味は以下の通り。

Level Meaning
0 no logging output
1 informational messages
2 error messages
3 warning messages
4 debug messages
5 all messages

たとえば、NSPR_LOG_MODULES=ALL:5と指定するとすべてのモジュールのすべてのメッセージがログファイルに出力されますし、NSPR_LOG_MODULES=nsHttp:1と指定すると、HTTPリクエスト・レスポンスに関係するInformationログが出力されます。

NSPR_LOG_FILE

ログファイル名を指定します。相対パスでも絶対パスでもOKです。

実際にやってみる

上記をふまえて、以下のようなFirefox起動batファイルを用意しておくと便利です。
[debugrun-firefox.bat]

set NSPR_LOG_MODULES=ALL:5
set NSPR_LOG_FILE=firefox.log
c:
cd "\logs"
"C:\workspace\mozilla\ff-opt\dist\bin\firefox.exe"

これで起動するとC:\logs以下に以下のようなログファイルが出力されます。
[firefox.logより抜粋]

0[af2800]: nsHttpHandler::NewURI
0[af2800]: Creating nsStandardURL @365cf38
0[af2800]: nsStandardURL::SetSpec [spec=http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/]
0[af2800]:  spec      = http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/
0[af2800]:  port      = -1
0[af2800]:  scheme    = (0,4)
0[af2800]:  authority = (7,15)
0[af2800]:  username  = (7,-1)
0[af2800]:  password  = (7,-1)
0[af2800]:  hostname  = (7,15)
0[af2800]:  path      = (22,35)
0[af2800]:  filepath  = (22,35)
0[af2800]:  directory = (22,35)
0[af2800]:  basename  = (57,0)
0[af2800]:  extension = (57,-1)
0[af2800]:  param     = (22,-1)
0[af2800]:  query     = (22,-1)
0[af2800]:  ref       = (22,-1)
0[af2800]: Destroying nsStandardURL @365cf38
0[af2800]: nsHttpHandler::NewURI
0[af2800]: Creating nsStandardURL @365cf38
0[af2800]: nsStandardURL::SetSpec [spec=http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/]
0[af2800]:  spec      = http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/
0[af2800]:  port      = -1
0[af2800]:  scheme    = (0,4)
0[af2800]:  authority = (7,15)
0[af2800]:  username  = (7,-1)
0[af2800]:  password  = (7,-1)
0[af2800]:  hostname  = (7,15)
0[af2800]:  path      = (22,35)
0[af2800]:  filepath  = (22,35)
0[af2800]:  directory = (22,35)
0[af2800]:  basename  = (57,0)
0[af2800]:  extension = (57,-1)
0[af2800]:  param     = (22,-1)
0[af2800]:  query     = (22,-1)
0[af2800]:  ref       = (22,-1)
0[af2800]: nsDocShell[362cfa0]: loading http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/ with flags 0x00000000
0[af2800]: DOCSHELL 362cfa0 InternalLoad http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/
0[af2800]: Content Policy: ShouldLoad: <http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/> <Ref:None> result=ACCEPT
0[af2800]: DocLoader:362cfa0: Stop() called
0[af2800]: nsHttpHandler::NewChannel
0[af2800]: nsHttpHandler::NewProxiedChannel [proxyInfo=0]
0[af2800]: Creating nsHttpChannel @36ee008
0[af2800]: nsHttpChannel::Init [this=36ee008]
0[af2800]: host=www.mozilla.org port=-1
0[af2800]: uri=http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/
0[af2800]: Creating nsHttpConnectionInfo @365d120
0[af2800]: nsHttpHandler::AddStandardRequestHeaders
0[af2800]: nsURILoader::OpenURI for http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/
0[af2800]: [0x36ee768] nsDocumentOpenInfo::Open
0[af2800]: nsHttpChannel::AsyncOpen [this=36ee008]
0[af2800]: ===== COOKIE SENT =====
0[af2800]: request URL: http://www.mozilla.org/projects/firefox/2.0.0.9/whatsnew/

どうでしょう?HTTPリクエストがどうできて、どう送られるかというのがソースの動きとしてよくわかります。
ただ、中にはこれでも満足できない、もっと深いところまで知りたい、という人もいるかも知れません。
そういう場合は、自分でビルドしてみることをおすすめします。
ビルド方法についてはまた別のエントリで。