在支持 DTrace 動(dòng)態(tài)跟蹤的平臺(tái)上,可以配置 PHP 打開(kāi) DTrace 靜態(tài)探針。
請(qǐng)參考操作系統(tǒng)文檔獲取啟用操作系統(tǒng) DTrace 支持的信息。 例如,在 Oracle Linux 系統(tǒng)上啟動(dòng) UEK3 內(nèi)核,并進(jìn)行如下操作:
# modprobe fasttrap
# chmod 666 /dev/dtrace/helper
除了 chmod
命令,您也可以使用 ACL 包規(guī)則來(lái)限制特定用戶對(duì)于設(shè)備的訪問(wèn)權(quán)限。
使用 --enable-dtrace
配置參數(shù)構(gòu)建 PHP:
# ./configure --enable-dtrace ...
# make
# make install
這樣就啟用了 PHP 核心的靜態(tài)探針。對(duì)于提供了自有探針的 PHP 擴(kuò)展需要分別構(gòu)建。
探針名稱 | 探針描述 | 探針參數(shù) |
---|---|---|
request-startup |
請(qǐng)求開(kāi)始時(shí)觸發(fā)。 | char *file, char *request_uri, char *request_method |
request-shutdown |
請(qǐng)求關(guān)閉時(shí)觸發(fā)。 | char *file, char *request_uri, char *request_method |
compile-file-entry |
腳本開(kāi)始編譯時(shí)觸發(fā)。 | char *compile_file, char *compile_file_translated |
compile-file-return |
腳本完成編譯時(shí)觸發(fā)。 | char *compile_file, char *compile_file_translated |
execute-entry |
操作數(shù)數(shù)組開(kāi)始執(zhí)行時(shí)觸發(fā)。例如:函數(shù)調(diào)用,文件包含以及生成器恢復(fù)時(shí)會(huì)被觸發(fā)。 | char *request_file, int lineno |
execute-return |
操作數(shù)數(shù)組執(zhí)行完畢之后觸發(fā)。 | char *request_file, int lineno |
function-entry |
PHP 引擎進(jìn)入 PHP 函數(shù)或者方法調(diào)用時(shí)觸發(fā)。 | char *function_name, char *request_file, int lineno, char *classname, char *scope |
function-return |
PHP 引擎從 PHP 函數(shù)或者方法調(diào)用返回后觸發(fā)。. | char *function_name, char *request_file, int lineno, char *classname, char *scope |
exception-thrown |
有異常拋出時(shí)觸發(fā)。 | char *classname |
exception-caught |
有異常被捕獲時(shí)觸發(fā)。 | char *classname |
error |
無(wú)論 error_reporting 的設(shè)定如何,在發(fā)生錯(cuò)誤時(shí)都會(huì)觸發(fā)。 | char *errormsg, char *request_file, int lineno |
PHP 擴(kuò)展可以擁有額外的靜態(tài)探針。
要列出 PHP 中可用的靜態(tài)探針,開(kāi)啟一個(gè) PHP 進(jìn)程,然后運(yùn)行:
# dtrace -l
輸出信息類似如下所示:
ID PROVIDER MODULE FUNCTION NAME [ . . . ] 4 php15271 php dtrace_compile_file compile-file-entry 5 php15271 php dtrace_compile_file compile-file-return 6 php15271 php zend_error error 7 php15271 php ZEND_CATCH_SPEC_CONST_CV_HANDLER exception-caught 8 php15271 php zend_throw_exception_internal exception-thrown 9 php15271 php dtrace_execute_ex execute-entry 10 php15271 php dtrace_execute_internal execute-entry 11 php15271 php dtrace_execute_ex execute-return 12 php15271 php dtrace_execute_internal execute-return 13 php15271 php dtrace_execute_ex function-entry 14 php15271 php dtrace_execute_ex function-return 15 php15271 php php_request_shutdown request-shutdown 16 php15271 php php_request_startup request-startup
Provider 一列由 php
和當(dāng)前進(jìn)程 id 的組成。
如果運(yùn)行的是 Apache web 服務(wù)器,那么模塊名稱可能是 libphp5.so, 并且可能會(huì)出現(xiàn)多塊信息,每個(gè)運(yùn)行中的 Apache 進(jìn)程對(duì)應(yīng)一個(gè)輸出塊。
Function Name 一列表示 Provider 對(duì)應(yīng)的 PHP 內(nèi)部 C 實(shí)現(xiàn)函數(shù)名稱。
如果沒(méi)有運(yùn)行任何 PHP 進(jìn)程,那么就不會(huì)顯示任何 PHP 探針。
下例展示了基本的 DTrace D 腳本。
示例 #1 all_probes.d for tracing all PHP Static Probes with DTrace
#!/usr/sbin/dtrace -Zs #pragma D option quiet php*:::compile-file-entry { printf("PHP compile-file-entry\n"); printf(" compile_file %s\n", copyinstr(arg0)); printf(" compile_file_translated %s\n", copyinstr(arg1)); } php*:::compile-file-return { printf("PHP compile-file-return\n"); printf(" compile_file %s\n", copyinstr(arg0)); printf(" compile_file_translated %s\n", copyinstr(arg1)); } php*:::error { printf("PHP error\n"); printf(" errormsg %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); } php*:::exception-caught { printf("PHP exception-caught\n"); printf(" classname %s\n", copyinstr(arg0)); } php*:::exception-thrown { printf("PHP exception-thrown\n"); printf(" classname %s\n", copyinstr(arg0)); } php*:::execute-entry { printf("PHP execute-entry\n"); printf(" request_file %s\n", copyinstr(arg0)); printf(" lineno %d\n", (int)arg1); } php*:::execute-return { printf("PHP execute-return\n"); printf(" request_file %s\n", copyinstr(arg0)); printf(" lineno %d\n", (int)arg1); } php*:::function-entry { printf("PHP function-entry\n"); printf(" function_name %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); printf(" classname %s\n", copyinstr(arg3)); printf(" scope %s\n", copyinstr(arg4)); } php*:::function-return { printf("PHP function-return\n"); printf(" function_name %s\n", copyinstr(arg0)); printf(" request_file %s\n", copyinstr(arg1)); printf(" lineno %d\n", (int)arg2); printf(" classname %s\n", copyinstr(arg3)); printf(" scope %s\n", copyinstr(arg4)); } php*:::request-shutdown { printf("PHP request-shutdown\n"); printf(" file %s\n", copyinstr(arg0)); printf(" request_uri %s\n", copyinstr(arg1)); printf(" request_method %s\n", copyinstr(arg2)); } php*:::request-startup { printf("PHP request-startup\n"); printf(" file %s\n", copyinstr(arg0)); printf(" request_uri %s\n", copyinstr(arg1)); printf(" request_method %s\n", copyinstr(arg2)); }
此腳本在 dtrace 命令中使用了 -Z
選項(xiàng)。
此選項(xiàng)保證即使在沒(méi)有任何 PHP 進(jìn)程運(yùn)行的時(shí)候腳本也能夠正確執(zhí)行。
如果省略了此選項(xiàng),當(dāng)沒(méi)有任何探針可監(jiān)控的時(shí)候,腳本會(huì)立即終止執(zhí)行。
在運(yùn)行此腳本的過(guò)程中,它將監(jiān)控全部 PHP 核心靜態(tài)探針。 運(yùn)行 D 腳本:
# ./all_probes.d
再運(yùn)行一個(gè) PHP 腳本或者 PHP 應(yīng)用,用來(lái)進(jìn)行監(jiān)控的 D 腳本會(huì)輸出每個(gè)探針被觸發(fā)時(shí)所攜帶的參數(shù)。
監(jiān)控完成之后,使用
^C
來(lái)終止 D 腳本的執(zhí)行。
在多 CPU 的主機(jī)上,探針的顯示順序可能不是連續(xù)的,這取決于哪顆 CPU 執(zhí)行探針以及多個(gè) CPU 之間的線程遷移情況。 可以通過(guò)顯示探針時(shí)間戳來(lái)減少混淆,例如:
php*:::function-entry { printf("%lld: PHP function-entry ", walltimestamp); [ . . .] }