はじめに
開発チームから「作ったアプリをサーバーにデプロイしたんだけど、起動しないから見て」と依頼が来ました。
とりあえず実行してみます。
./my_awesome_app
(一瞬で終了。画面には何も表示されない。)
「どんなエラーが出てるの?」とログファイル( /var/log 配下やアプリの独自ログ)を探しますが、ログファイルそのものが作られていません。
「えっ、完全に無言で死んだんだけど…どうやって直せばいいの?」
開発者に聞いても「僕のMacでは動きますよ(怒)」と言われる始末。(知るか)
エラーメッセージという「手がかり」が無い密室殺人事件。インフラエンジニアの胃が最も痛くなる瞬間です。
こんな時、プロセスの「心の声(システムへの要求)」を直接盗聴できるチートアイテムがあります。それが strace です。(ストレスに対処するstraceと覚えましょう)
アプリはOS(カーネル)にお願いしないと何もできない
そもそも、アプリというものは「単独」では何一つ具体的な操作ができません。
ファイルを読む、画面に文字を出す、ネットワークに繋ぐ…これらすべては、巨大で強固な金庫番である OSのカーネル(核) に対して「お願いします、これをやらせてください」と依頼(システムコール)することで成り立っています。
strace は、「アプリがカーネルに対してどんな依頼をし、カーネルからどう断られたのか」を全て傍受する通信傍受システム(聴診器)です。
聴診器を当てて、死因を突き止める
無言で死ぬアプリに、strace を当てて起動してみましょう。
strace ./my_awesome_app
すると、MATRIXのスクリーンセーバーのように、謎の文字列が画面を猛スピードで埋め尽くします!(最初は絶対にビビります)
ですが、見るべきポイントはただ一つ。最後(死ぬ直前)の数行です。
... (前略) ...
openat(AT_FDCWD, "/etc/my_awesome_app/config.json", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
write(2, "Fatal error: ", 13) = -1 EPIPE (Broken pipe)
exit_group(1) = ?
+++ exited with 1 +++
見えましたか?
openat(ファイルを開きたいという依頼)に対して、カーネルが -1 ENOENT (そんなファイルもディレクトリも無いよ) と冷たく突き返しています。
「アプリは /etc 配下の config.json を読もうとして、ファイルが存在しなくてパニックになって死んでいた」 のです。ログファイルすら作れなかったのは、設定ファイルを読めなかったからです。
もう一つのよくある死因:権限不足(EACCES)
openat(AT_FDCWD, "/var/log/my_awesome_app.log", O_WRONLY|O_CREAT) = -1 EACCES (Permission denied)
これも一瞬で犯人がわかりますね。「ログファイルを作りたい」という依頼が、EACCES(パーミッション拒否) で弾かれています。ディレクトリの権限を直せば一発解決です。
OSに魔法はない。すべては記録されている
strace の出力結果は、最初は難解な呪文に見えます。しかし、彼らは「事実」しか語りません。
「アプリは嘘をつく(エラーを隠す、間違ったログを吐く)が、システムコールは嘘をつかない」。
この絶対的な真理に気づいた時、あなたのデバッグ能力は次元を一つ超えます。「原因不明」というブラックボックスを実力でこじ開ける快感、ぜひ味わってみてください。