LinuxディストリビューションにおいてカーネルがeBPFをサポートする場合、bpftraceユーティリティはPHPのDTraceプローブ(USDT)に対してSystemTapを必要とせず直接アタッチすることができます。
bpftraceをパッケージマネージャを利用してインストールします。例えばOracle Linux、RHELまたはFedoraの場合は
# dnf install bpftrace
# apt install bpftrace
下記の例ではターゲットとなるPHPバイナリのインストール先は /usr/bin/phpであると仮定しています。
同じUSDTプローブは同一のソースツリーからビルドされた他のSAPIでも利用可能であり、プローブのターゲットはApache module
(libphp.so)またはFastCGI Process Manager
バイナリ (php-fpm)となる場合もあります。必要に応じて適切なパスに置き換えや、
-pによるPID指定を行いアタッチしてください。
ターゲットバイナリでDTraceが有効になっていること、環境変数が適切に設定されていることを確認してください。 詳細はDTrace 静的プローブのために PHP を構成で参照できます。
PHPの静的プローブをリストするには以下のbpftraceコマンドを使用します。
# bpftrace -l 'usdt:/usr/bin/php:php:*'
出力はこのようになります。
usdt:/usr/bin/php:php:compile__file__entry usdt:/usr/bin/php:php:compile__file__return usdt:/usr/bin/php:php:error usdt:/usr/bin/php:php:exception__caught usdt:/usr/bin/php:php:exception__thrown usdt:/usr/bin/php:php:execute__entry usdt:/usr/bin/php:php:execute__return usdt:/usr/bin/php:php:function__entry usdt:/usr/bin/php:php:function__return usdt:/usr/bin/php:php:request__shutdown usdt:/usr/bin/php:php:request__startup
例1 bpftraceを使用してすべてのPHP静的プローブをトレースするall_probes.bt
#!/usr/bin/env bpftrace
usdt:/usr/bin/php:php:compile__file__entry
{
printf("Probe compile__file__entry\n");
printf(" compile_file %s\n", str(arg0));
printf(" compile_file_translated %s\n", str(arg1));
}
usdt:/usr/bin/php:php:compile__file__return
{
printf("Probe compile__file__return\n");
printf(" compile_file %s\n", str(arg0));
printf(" compile_file_translated %s\n", str(arg1));
}
usdt:/usr/bin/php:php:error
{
printf("Probe error\n");
printf(" errormsg %s\n", str(arg0));
printf(" request_file %s\n", str(arg1));
printf(" lineno %d\n", (int32)arg2);
}
usdt:/usr/bin/php:php:exception__caught
{
printf("Probe exception__caught\n");
printf(" classname %s\n", str(arg0));
}
usdt:/usr/bin/php:php:exception__thrown
{
printf("Probe exception__thrown\n");
printf(" classname %s\n", str(arg0));
}
usdt:/usr/bin/php:php:execute__entry
{
printf("Probe execute__entry\n");
printf(" request_file %s\n", str(arg0));
printf(" lineno %d\n", (int32)arg1);
}
usdt:/usr/bin/php:php:execute__return
{
printf("Probe execute__return\n");
printf(" request_file %s\n", str(arg0));
printf(" lineno %d\n", (int32)arg1);
}
usdt:/usr/bin/php:php:function__entry
{
printf("Probe function__entry\n");
printf(" function_name %s\n", str(arg0));
printf(" request_file %s\n", str(arg1));
printf(" lineno %d\n", (int32)arg2);
printf(" classname %s\n", str(arg3));
printf(" scope %s\n", str(arg4));
}
usdt:/usr/bin/php:php:function__return
{
printf("Probe function__return\n");
printf(" function_name %s\n", str(arg0));
printf(" request_file %s\n", str(arg1));
printf(" lineno %d\n", (int32)arg2);
printf(" classname %s\n", str(arg3));
printf(" scope %s\n", str(arg4));
}
usdt:/usr/bin/php:php:request__shutdown
{
printf("Probe request__shutdown\n");
printf(" file %s\n", str(arg0));
printf(" request_uri %s\n", str(arg1));
printf(" request_method %s\n", str(arg2));
}
usdt:/usr/bin/php:php:request__startup
{
printf("Probe request__startup\n");
printf(" file %s\n", str(arg0));
printf(" request_uri %s\n", str(arg1));
printf(" request_method %s\n", str(arg2));
}
上記のスクリプトはPHPのスクリプトの実行中のすべてのコアPHP静的プローブポイントをトレースします。bpftraceの実行にはroot権限が必要です。
# USE_ZEND_DTRACE=1 bpftrace -c '/usr/bin/php test.php' all_probes.bt
すでに実行中のPHPプロセス (例えば php-fpm ワーカー、または libphp.soをロードするapacheプロセス)はPIDを指定してアタッチできます。
# bpftrace -p $PID all_probes.bt
usdt: ターゲットパスは実行しているプロセスのバイナリにマッチする必要があります。
usdt:/usr/bin/php部分を
php-fpm バイナリまたは libphp.so などのパスに必要に応じて修正してください。