PHP kann auf Plattformen, die DTrace Dynamic Tracing unterstützen, mit statischen DTrace-Sonden konfiguriert werden.
Um die DTrace-Unterstützung des Betriebssystems zu aktivieren, siehe die externe plattformspezifische Dokumentation. Unter Oracle Linux muss zum Beispiel ein UEK3-Kernel gebootet und anschließend Folgendes ausgeführt werden:
# modprobe fasttrap
# chmod 666 /dev/dtrace/helper
Anstatt chmod
zu verwenden, kann stattdessen eine
ACL-Paketregel verwendet werden, um den Gerätezugriff auf einen bestimmten
Benutzer zu beschränken.
PHP mit dem Konfigurationsparameter --enable-dtrace
kompilieren:
# ./configure --enable-dtrace ...
# make
# make install
Dies aktiviert die statischen Sonden im Kern von PHP. Alle PHP-Erweiterungen, die ihre eigenen Sonden bereitstellen, müssen separat als dynamische Erweiterungen gebaut werden.
Name der Probe | Beschreibung der Probe | Parameter der Probe |
---|---|---|
request-startup |
Wird ausgelöst, wenn eine Anfrage beginnt. | char *file, char *request_uri, char *request_method |
request-shutdown |
Wird ausgelöst, wenn eine Anfrage endet. | char *file, char *request_uri, char *request_method |
compile-file-entry |
Wird ausgelöst, wenn die Kompilierung eines Skripts beginnt. | char *compile_file, char *compile_file_translated |
compile-file-return |
Wird ausgelöst, wenn die Kompilierung eines Skripts endet. | char *compile_file, char *compile_file_translated |
execute-entry |
Wird ausgelöst, wenn ein OpCode-Array ausgeführt wird, z. B. bei Funktionsaufrufen, Includes und wenn ein Generator fortfährt. | char *request_file, int lineno |
execute-return |
Wird nach der Ausführung eines OpCode-Arrays ausgelöst. | char *request_file, int lineno |
function-entry |
Wird ausgelöst, wenn die PHP-Engine in eine PHP-Funktion oder -Methode gelangt. | char *function_name, char *request_file, int lineno, char *classname, char *scope |
function-return |
Wird ausgelöst, wenn die PHP-Engine aus einer PHP-Funktion oder -Methode zurückkehrt. | char *function_name, char *request_file, int lineno, char *classname, char *scope |
exception-thrown |
Wird ausgelöst, wenn eine Exception ausgelöst wird. | char *classname |
exception-caught |
Wird ausgelöst, wenn eine Exception abgefangen wird. | char *classname |
error |
Wird ausgelöst, wenn ein Fehler auftritt, unabhängig von der error_reporting-Stufe. | char *errormsg, char *request_file, int lineno |
PHP-Erweiterungen verfügen möglicherweise über zusätzliche statische Sonden.
Um die verfügbaren Sonden aufzulisten, ist es nötig, einen PHP-Prozess zu starten und dann Folgendes auszuführen:
# dtrace -l
Die Ausgabe wird ungefähr so aussehen:
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
Die Werte der Spalte PROVIDER setzen sich aus php
und
der Prozess-ID des aktuell laufenden PHP-Prozesses zusammen.
Wenn der Apache-Webserver läuft, könnte der Modulname zum Beispiel libphp5.so sein, und es gäbe pro laufendem Apache-Prozess einen Auflistungs-Block.
Die Spalte FUNCTION verweist auf den Funktionsnamen der PHP-internen C-Implementierung, in der sich der jeweilige Provider befindet.
Wenn kein PHP-Prozess läuft, werden auch keine PHP-Sonden angezeigt.
Dieses Beispiel zeigt die grundlegenden Möglichkeiten der DTrace-Skriptsprache D.
Beispiel #1 all_probes.d für die Verfolgung aller statischen PHP-Sonden mit 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)); }
Dieses Skript verwendet dtrace mit der Option
-Z
, damit es auch dann ausgeführt werden kann, wenn
gerade kein PHP-Prozess läuft. Ohne diese Option würde das Skript sofort
beendet, weil es erkennt, dass keine der zu überwachenden Sonden vorhanden
ist.
Das Skript verfolgt während der gesamten Zeit, in der ein PHP-Skript läuft, alle statischen Sondenpunkte des PHP-Kerns.
# ./all_probes.d
Sobald nun ein PHP-Skript oder eine Anwendung ausgeführt wird, beginnt das überwachende D-Skript, alle Parameter der ausgelösten Sonden auszugeben.
Um die Überwachung abzuschließen, kann das D-Skript mittels CTRL+C beendet werden.
Auf Rechnern mit mehreren CPUs ist die Reihenfolge der Tests möglicherweise nicht sequentiell. Dies hängt davon ab, welche CPU die Sonden verarbeitet hat und wie die Threads zwischen den CPUs wechseln. Die Anzeige der Zeitstempel der Sonden hilft, Verwechslungen zu vermeiden, zum Beispiel:
php*:::function-entry { printf("%lld: PHP function-entry ", walltimestamp); [ . . .] }