読者です 読者をやめる 読者になる 読者になる

すがブロ

sugamasaoのhatenablogだよ

OSXでもstraceしたい?よろしい、ならばdtrussだ

strace便利ですよね。最近もnginxがどのファイル開いてるのか調べるのに使いました。ただ、OSXだとそれに準ずるコマンドってないのかなーと勝手に諦めていたのですが、ありましたね。

dtruss

straceと同じように sudo dtruss -p プロセスIDシステムコールを確認できる。

例えば、nginxで確認してみよう。

$  ps -ef | grep nginx
  501 31223     1   0  6:22PM ??         0:00.00 nginx: master process nginx
  501 31224 31223   0  6:22PM ??         0:00.00 nginx: worker process
  501 31935 31725   0  8:07PM ttys005    0:00.00 grep nginx

ワーカーを見れば良いので、 31224 にアタッチしてみよう。

$ sudo dtruss -p 31224

おもむろにWebページにアクセスしてみる。

SYSCALL(args)            = return
kevent(0x8, 0x7F91DD005C00, 0x1)                 = 1 0
recvfrom(0x3, 0x7F91DD005400, 0x400)             = 469 0
stat64("/usr/local/Cellar/nginx/1.6.2/html/index.html\0", 0x7FFF5DEEF148, 0x400)                 = 0 0
open("/usr/local/Cellar/nginx/1.6.2/html/index.html\0", 0x4, 0x0)                = 10 0
fstat64(0xA, 0x7FFF5DEEEF08, 0x0)                = 0 0
writev(0x3, 0x7FFF5DEEE9D0, 0x1)                 = 179 0
write(0x4, "127.0.0.1 - - [31/Dec/2014:20:08:35 +0900] \"GET / HTTP/1.1\" 304 0 \"-\" \"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36\"\n\0", 0xC1)              = 193 0
close(0xA)               = 0 0
access("/etc/localtime\0", 0x4, 0x0)             = 0 0
open_nocancel("/etc/localtime\0", 0x0, 0x0)              = 9 0
fstat64(0x9, 0x7FFF5DEEBFC0, 0x0)                = 0 0
read_nocancel(0x9, "TZif\0", 0x2A64)             = 126 0
close_nocancel(0x9)              = 0 0
accept(0x6, 0x7FFF5DEEF430, 0x7FFF5DEEF42C)              = 9 0

標準エラーを標準出力にリダイレクトすればgrepもできるので、ここらへんもstraceと同じですね。

$  sudo dtruss -p 31224 2>&1 | grep open
open_nocancel("/etc/localtime\0", 0x0, 0x0)              = 10 0
open("/usr/local/Cellar/nginx/1.6.2/html/index.html\0", 0x4, 0x0)                = 10 0

ちなみに、Homebrewでインストールしたnginxの何が何だか分からない問題

この検証にあたり、適当なプロセスとしてnginx動かそうと思いました。で、Homebrewでインストールしてみたのですが、どのポートで動いてるかとかぜんぜんよくわからなかったので調べてみましたのメモ(lsofの使い方いつも忘れるのだった)。

ちなみに、起動は単に nginx と打つだけで良い。 lsofはプロセス名で検索することができるので、今回はnginxを指定して調べる。この場合、-cオプションを使用する。さらに、-P オプションを使用することでポート番号を生のまま(数値で)表示するオプションを追加している。

$ lsof -c nginx -P | grep LISTEN
nginx   32055 sugamasao    6u    IPv4 0xed732b31079edf33       0t0      TCP *:8080 (LISTEN)
nginx   32056 sugamasao    6u    IPv4 0xed732b31079edf33       0t0      TCP *:8080 (LISTEN)

こうすると、どうやらLISTENしているのは8080ポートらしいということがわかる。

-Pを指定しない場合、こんな感じになってService Nameとやらの値に変換するようになっている(生データをデフォルトにしてほしいなぁ)。

$ lsof -c nginx | grep LISTEN
nginx   32055 sugamasao    6u    IPv4 0xed732b31079edf33       0t0      TCP *:http-alt (LISTEN)
nginx   32056 sugamasao    6u    IPv4 0xed732b31079edf33       0t0      TCP *:http-alt (LISTEN)

っていうか、まともにlsofの結果見るとオープンしてるファイルとかもわかるし結構良いですね、、、。

オマケ

Homebrewでインストールされたnginxが使うconfの場所がパッとわからなくてこんな感じで確認しました(こういう使い方もできるよ、ということで一つ)。

masterプロセス、あるいはプロセス名自体でdtrussでアタッチして、nginx -s reloadで設定ファイルを読み直すことで、どこのファイルを参照しているかを確認できた。

$ sudo dtruss -n nginx 2>&1 | grep conf

こうしてから別ターミナルで nginx -s reloadするとこんな感じのログが表示されていた。

32880/0x641a4:  stat64("/usr/lib/system/libsystem_configuration.dylib\0", 0x7FFF54E3E9F8, 0x2)           = 0 0
32055/0x6168e:  open("/usr/local/etc/nginx/nginx.conf\0", 0x0, 0x0)              = 4 0
32880/0x641a4:  read_nocancel(0x4, "#\n# OpenSSL example configuration file.\n# This is mostly being used for generation of certificate requests.\n#\n\n# This definition stops the following lines choking if HOME isn't\n# defined.\nHOME\t\t\t= .\nRANDFILE\t\t= $ENV::HOME/.rnd\n\n# Extra OBJECT IDENTIFIER in", 0x1000)               = 4096 0
32880/0x641a4:  open("/usr/local/etc/nginx/nginx.conf\0", 0x0, 0x0)              = 4 0

内容を確認してみると、どうやら /usr/local/etc/nginx/nginx.confっぽいなってのがわかった。便利〜〜