strace は、プロセスが Linux カーネルに対して行う「システムコール」をリアルタイムで表示するコマンドです。「このコマンドがどのファイルを開いているのか」「なぜエラーが出るのか」といった疑問に、ログや設定ファイルを読むよりずっと直接的に答えてくれます。
私が Ubuntu 24.04 で実際に試してみると、echo hello という単純なコマンドでも 36 回ものシステムコールが走ることがわかりました。動的リンクや初期化処理が意外と多い、というのが正直な感想です。
本記事では Ubuntu 24.04 LTS の Docker コンテナで strace を実際に動かし、インストール方法から実用的なオプションまで実出力を交えて説明します。
この記事のポイント
apt install straceだけで使えます(Ubuntu 24.04 では strace 6.8 が入ります)strace -cでシステムコールの種類と回数を集計できます-e trace=openatなどのフィルタで、見たい情報だけ絞れます- 既存プロセスにアタッチするには
strace -p <PID>を使います - 出力が多すぎる場合は
-o ファイル名でファイルに書き出すと読みやすくなります
目次
- strace とは
- インストール
- 基本的な使い方
- システムコールをフィルタする(-e オプション)
- 集計モード(-c オプション)
- 時間計測(-T オプション)
- 出力をファイルに保存する(-o オプション)
- 実行中のプロセスにアタッチする(-p オプション)
- 実用シナリオ
- よくあるエラーと対処
- まとめ
strace とは
Linux ではプログラムがハードウェアやOSの機能(ファイルの読み書き・ネットワーク接続・プロセス生成など)を使うとき、必ずカーネルに「システムコール」として依頼します。strace はそのシステムコールを逐一表示するツールです。
デバッガ(gdb)がソースコードレベルで内部を見るのに対して、strace は バイナリがすでにある状態でもブラックボックスを覗ける という強みがあります。「設定ファイルのパスを間違えていてエラーが出る」「ライブラリが見つからない」といったトラブルは、strace でファイルアクセスを追うだけで一発でわかることが多いです。
インストール
手順1:パッケージを更新する
Hit:1 http://jp.archive.ubuntu.com/ubuntu noble InRelease
Reading package lists… Done
手順2:strace をインストールする
Reading state information… Done
The following NEW packages will be installed:
libunwind8 strace
Setting up strace (6.8-0ubuntu2) …
Ubuntu 24.04 では strace 6.8(パッケージ名 strace 6.8-0ubuntu2)がインストールされます。下図は実際のインストールログです。

手順3:バージョンを確認する
strace — version 6.8
Copyright (c) 1991-2024 The strace developers <https://strace.io>.
Optional features enabled: stack-trace=libunwind stack-demangle m32-mpers mx32-mpers

Ubuntu 22.04 では strace 5.16、Ubuntu 24.04 では strace 6.8 が入ります。バージョン間で出力形式は大きく変わりませんが、6.8 ではシステムコールの種別表示がより詳細になっています。下表は両バージョンを Docker で実際に確認した結果です。

基本的な使い方
もっとも基本的な使い方は、追跡したいコマンドの先頭に strace を付けるだけです。
execve(“/usr/bin/echo”, [“echo”, “hello”], 0x7ffe… /* 6 vars */) = 0
brk(NULL) = 0x55c3a1e5b000
openat(AT_FDCWD, “/etc/ld.so.cache”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libc.so.6”, O_RDONLY|O_CLOEXEC) = 3
…(中略)…
write(1, “hello\n”, 6hello) = 6
+++ exited with 0 +++
出力の読み方は、左から「システムコール名(引数)= 戻り値」という形式です。上の例では最後の write(1, "hello\n", 6) = 6 が実際に画面に文字を書いた行で、戻り値の 6 は書き込んだバイト数です。
注意
システムコールはかなりの量が出力されます。echo hello のような小さいコマンドでも 50 行以上になります。見たい情報だけ絞るには後述の -e フィルタを使うのがコツです。

システムコールをフィルタする(-e オプション)
-e trace=システムコール名 で、特定の種類のシステムコールだけに絞れます。これが実際の調査でいちばん使う機能です。
①ファイルアクセスだけ追う
openat(AT_FDCWD, “/etc/ld.so.cache”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libc.so.6”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/etc/hostname”, O_RDONLY) = 3
67164b0c7983
+++ exited with 0 +++
Ubuntu 24.04 で実測すると、cat /etc/hostname は以下の順番でファイルを開いていました:ld.so.cache(動的リンク設定)→ libc.so.6(C標準ライブラリ)→ 最後にやっと /etc/hostname 本体、という流れです。目的のファイルにたどり着く前に 2 回ライブラリを読み込んでいる、というのが直感的にわかります。

②書き込みだけ追う
write(1, “hello\n”, 6hello)
= 6
+++ exited with 0 +++
write だけに絞ると、1 行しか出ません。「echo hello が何をしているか」という問いの核心がここにあります。
③複数のシステムコールを同時に指定する
openat(AT_FDCWD, “/etc/ld.so.cache”, O_RDONLY|O_CLOEXEC) = 3
read(3, “\177ELF\2\1\1\0…”…, 832) = 832
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libselinux.so.1”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libc.so.6”, O_RDONLY|O_CLOEXEC) = 3
write(1, “/etc/hostname\n”, 14/etc/hostname)
+++ exited with 0 +++
カンマ区切りで複数のシステムコールを同時に追えます。ファイルを開いて・読んで・書く、という一連の流れが見えます。
集計モード(-c オプション)
-c を付けると、プロセスが終了した後にシステムコールの種類・回数・所要時間を一覧で表示します。「どのシステムコールが多いか」を把握するのに便利です。
hello
% time seconds usecs/call calls errors syscall
—— ———– ———– ——— ——— —————-
0.00 0.000000 0 8 mmap
0.00 0.000000 0 2 openat
0.00 0.000000 0 1 write
0.00 0.000000 0 1 execve
0.00 0.000000 0 1 1 access
—— ———– ———– ——— ——— —————-
100.00 0.000000 0 36 1 total
Ubuntu 24.04 で実測した結果、echo hello は合計 36 回のシステムコール を呼んでいました。そのうち mmap(メモリマッピング)が 8 回と最多で、動的リンカの処理が大半を占めています。実際の文字出力(write)は 1 回だけです。

時間計測(-T オプション)
-T を付けると、各システムコールの末尾にかかった時間(秒)が表示されます。パフォーマンス問題の特定に役立ちます。
openat(AT_FDCWD, “/etc/ld.so.cache”, O_RDONLY|O_CLOEXEC) = 3 <0.000004>
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libselinux.so.1”, O_RDONLY|O_CLOEXEC) = 3 <0.000004>
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libc.so.6”, O_RDONLY|O_CLOEXEC) = 3 <0.000003>
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libpcre2-8.so.0”, O_RDONLY|O_CLOEXEC) = 3 <0.000005>
openat(AT_FDCWD, “/proc/filesystems”, O_RDONLY|O_CLOEXEC) = 3 <0.000004>
/etc/hostname
+++ exited with 0 +++
行末の <0.000004> が所要時間(秒)です。いずれも数マイクロ秒と高速ですが、NFS マウントされたファイルシステムや低速ディスクでは read や write が数ミリ秒〜数十ミリ秒かかることもあり、そういった場合に -T が有効です。

出力をファイルに保存する(-o オプション)
strace の出力は stderr に出るため、通常は画面が出力で埋まります。-o でファイルに書き出すと後から読みやすくなります。
/etc/hostname
$ wc -l /tmp/trace.log
57 /tmp/trace.log
$ grep openat /tmp/trace.log
openat(AT_FDCWD, “/etc/ld.so.cache”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libselinux.so.1”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libc.so.6”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/lib/x86_64-linux-gnu/libpcre2-8.so.0”, O_RDONLY|O_CLOEXEC) = 3
openat(AT_FDCWD, “/proc/filesystems”, O_RDONLY|O_CLOEXEC) = 3
保存したログに grep を組み合わせると、「この設定ファイルを本当に読んでいるか」「どのパスで検索しているか」を素早く確認できます。
実行中のプロセスにアタッチする(-p オプション)
すでに動いているプロセスを調べるには -p <PID> を使います。デーモンやサービスのトレースに便利です。
[1] 4823
$ sudo strace -p 4823
strace: Process 4823 attached
restart_syscall(<… resuming interrupted syscall …>) = 0
nanosleep({tv_sec=97, tv_nsec=0}, NULL) = ? ERESTART_RESTARTBLOCK (Interrupted by signal)
^C (Ctrl+C で終了)
strace: Process 4823 detached
注意:sudo が必要
strace -p で他のユーザーのプロセスにアタッチするには sudo が必要です。自分が起動したプロセスなら sudo なしでアタッチできる場合もありますが、システムサービスは必ず sudo が要ります。
実用シナリオ
①「設定ファイルが読まれているか」を確認する
コマンドが期待通りに設定を読み込んでいるか疑問なとき、-e trace=openat で確認できます。
OpenSSH_9.6p1 Ubuntu-3ubuntu13.11, OpenSSL 3.0.13 30 Jan 2024
$ grep “/etc/ssh” /tmp/ssh_trace.log
openat(AT_FDCWD, “/etc/ssh/ssh_config”, O_RDONLY) = 3
/etc/ssh/ssh_config を実際に開いているのが確認できます。「設定を変えたのに反映されない」という場合、別のパスを読んでいる可能性があり、こうして確認できます。
②ネットワーク接続を追う
socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP) = 3
socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6) = 4
setsockopt(3, SOL_SOCKET, SO_MARK, [0], 4) = 0
connect(3, {sa_family=AF_INET, sin_port=htons(0), sin_addr=inet_addr(“8.8.8.8”)}, 16) = 0
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
trace=network はソケット・接続・送受信に関するシステムコールを一括でフィルタします。どこへ接続しているかを素早く確認できます。
③エラーの原因を探る
コマンドが「Permission denied」などのエラーで失敗するとき、strace でどのファイルやリソースへのアクセスが失敗したか特定できます。
openat(AT_FDCWD, “/etc/myapp/config.toml”, O_RDONLY) = -1 ENOENT (No such file or directory)
ENOENT(ファイルが見つからない)・EACCES(権限なし)・EPERM(操作が許可されていない)でgrepすると、エラーの箇所だけ取り出せます。
よくあるエラーと対処
strace: attach: ptrace(PTRACE_SEIZE): Operation not permitted
他のユーザーのプロセスにアタッチしようとすると出ます。sudo strace -p <PID> で実行してください。
strace: exec: Exec format error
スクリプトファイルに直接 strace をかけようとしたときに出ます。strace bash script.sh のように、インタープリタを指定して実行してください。
出力が多すぎて読めない
まず -e trace=openat や -e trace=network で絞り込み、-o /tmp/trace.log でファイルに書き出してから grep で検索するのがやりやすいです。
まとめ
よく使うオプションをまとめます。
| オプション | 意味 | 使いどころ |
|---|---|---|
strace コマンド |
すべてのシステムコールを表示 | とりあえず全体を把握したいとき |
-e trace=openat |
ファイルアクセスだけ表示 | 設定ファイルのパスを確認したいとき |
-e trace=network |
ネットワーク関連だけ表示 | 接続先やソケット操作を追うとき |
-c |
システムコールの統計を表示 | どのシステムコールが多いか把握したいとき |
-T |
各コールの実行時間を表示 | パフォーマンス問題の箇所を絞るとき |
-o ファイル |
トレース出力をファイルに保存 | 後から grep で絞り込みたいとき |
-p PID |
実行中のプロセスにアタッチ | デーモンやサービスを調査するとき |
-s N |
文字列の表示長を N バイトに変更 | デフォルト(32バイト)では内容が切れるとき |
straceはapt install straceで入ります(Ubuntu 24.04 では 6.8 がインストールされます)-e trace=openatでファイルアクセスだけ絞ると、設定ファイルの読み込みパスがすぐわかります-cの統計は「どのシステムコールが何回呼ばれているか」の全体像を掴むのに便利です- 出力が多いときは
-oでファイル保存 →grepで絞り込む流れが実用的です
トラブルシュートに困ったとき、ログに何も出ない場合や設定が反映されているか疑わしいとき、ぜひ strace を試してみてください。意外と早く原因が見つかります。
Linux をより深く活用したい方は、VPS を借りて実際にサーバーを動かしてみるのが近道です。



コメント