## PHP mit DTrace verwenden

PHP kann auf Plattformen, die DTrace Dynamic Tracing unterstützen, mit statischen DTrace-Sonden konfiguriert werden.

### PHP für statische DTrace-Sonden konfigurieren

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`

Dadurch werden die statischen Sonden im Kern von PHP verfügbar. Alle PHP-Erweiterungen, die ihre eigenen Sonden bereitstellen, müssen separat als dynamische Erweiterungen gebaut werden.

Um Sonden zu aktivieren, muss die Umgebungsvariable USE_ZEND_DTRACE=1 für die PHP-Zielprozesse gesetzt werden.

### Statische DTrace-Sonden im Kern von PHP

Die folgenden statischen Sonden stehen in PHP zur Verfügung
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.

### Liste statischer DTrace-Sonden in PHP

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.

### DTrace-Beispiel für PHP

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);
          [ . . .]
    }

### Siehe auch

- OCI8 und DTrace Dynamic Tracing

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open