strace помогает отлаживать PHP-код

PHP

На прошлой неделе фоновый скрипт Crontab (код PHP) столкнулся с некоторыми проблемами и, наконец, быстро решил их с помощью инструмента командной строки strace linux.Хотя проблему легко создать и решить, инструмент strace стоит изучить каждому. программист.

Этот фоновый скрипт не сталкивался с проблемами в среде разработки, но была проблема в онлайн-среде.Там не было большой разницы в слое кода между средой разработки и онлайн-средой (это было только после того, как были различия ), только среда разработки использовала тестовую базу данных и другие ресурсы.

Результатом запуска сценария онлайн-среды является то, что в определенный файл не были успешно записаны данные.Согласно обычному решению, необходимо добавить функцию отладки (например, функцию var_dump) в код PHP для пошаговой отладки. этот скрипт, используя этот метод, могут возникнуть следующие проблемы:

  • В среде разработки нет проблем. Чтобы воспроизвести проблему, вы должны выполнить отладку в онлайн-среде. Если вы добавите отладочный код, это может вызвать некоторые проблемы, например некоторые дополнительные данные, вставленные в онлайн-базу данных.

  • Скрипт работает медленно, если вы продолжаете модифицировать код, а затем отлаживать, это может занять много времени в конце.

Есть ли способ быстрой отладки? Ожидаемым результатом этого сценария является запись информации журнала в файл, то есть сценарий в конечном итоге вызовет системную функцию для записи файла, так что есть ли проблема с правами доступа к файлу? Скрипт прерывается, не выполняя шаг записи файла? Есть ли такой инструмент, как tcmdump, который может воспроизвести всю системную обработку? Круто то, что strace делает именно это, регистрируя все системные вызовы и обработку сигналов.

Поскольку скрипт не смог успешно записать данные, я извлек код ключа скрипта, код выглядит следующим образом:

<?php
$file  = "/var/log/data.log";
$fp = fopen($file, "a");
if ($fp) {
    echo "start\n";
    foreach ($log as $v) {
       fwrite($fp, $v."\r\n");
    }
}
fclose($fp);скопировать код

Затем выполните следующую команду для регистрации всех системных вызовов:

$ strace -o debug.log php test.phpскопировать код

Проверьте вывод ключа:

lstat("/var/log/data.log", {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lstat("/var/log", {st_mode=S_IFDIR|0775, st_size=4096, ...}) = 0
lstat("/var", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
open("/var/log/data.log", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lseek(3, 0, SEEK_CUR)  = 0
lseek(3, 0, SEEK_CUR)  = 0
write(1, "start\n", 6) = 6
close(3) = 0
close(2) = 0
close(1) = 0
munmap(0x7f7aa7dfd000, 4096) = 0
close(0) = 0скопировать код

Как видно из вывода, скрипт вообще не работает.fwrite($fp, $v."\r\n");Этот код, все остальное работает нормально и код нормально завершается.

Проблема уже очевидна, да$logОнлайн-среда переменной пуста, следуйте шаблону и внимательно проверяйте его.$logПотенциальным багом оказывается обработка переменных (подробно описывать не буду, это низкоуровневая ошибка). После изменения кода снова запустите strace, и результат будет следующим:

open("/var/log/data.log", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
lseek(3, 0, SEEK_CUR)  = 0
lseek(3, 0, SEEK_CUR)  = 0
write(1, "start\n", 6) = 6
write(3, "testdata\r\n", 10) = 10
close(3)  = 0
close(2)  = 0
close(1)  = 0
munmap(0x7f8a034cd000, 4096)  = 0скопировать код

Скрипт, наконец, успешно записывает данные в файл (write(3, "testdata\r\n", 10) = 10), проблема решена. На самом деле, возникновение и причина этой проблемы в конечном итоге вызваны нестрогим кодом. Этот пример не объясняет удивительность инструмента strace, потому что другие методы отладки также могут быть решены, но это неоспоримо что у инструмента strace есть очень широкие сценарии использования.

Далее мы систематически разбираемся в инструменте strace.Параметры использования и выходные данные инструмента см.man strace, в справке man определение strace выглядит следующим образом.

strace - trace system calls and signals

strace  is  a useful diagnostic, instructional, and debugging tool

Для кода PHP большая часть логики кода будет генерировать системные вызовы, такие как запись в локальный файл (запись), подключение к внешней базе данных (подключение), даже если вы вообще не знаете логики кода , вы можете использовать инструмент strace, чтобы узнать, что делает PHP-код Что произошло, разве это не удивительно?

Далее возьмем несколько простых примеров, давайте освоим использование strace.

1: Пример 1

$ strace -Tt php test.phpскопировать код

Параметр -T указывает время, затраченное на каждый системный вызов, а -t печатает время, когда произошел каждый системный вызов.

Сценарий test.php хочет подключиться к google.com, и ключевой вывод выглядит следующим образом:

17:00:21 connect(3, {sa_family=AF_INET, sin_port=htons(443), sin_addr=inet_addr("173.252.73.48")}, 16) = -1 EINPROGRESS (Operation now in progress) <0.000057>
17:00:21 poll([{fd=3, events=POLLIN|POLLOUT|POLLERR|POLLHUP}], 1, 60000) = 0 (Timeout) <60.055735>скопировать код

Как вы можете видеть из вывода, опрос, наконец, пытался в течение 60 секунд, и время ожидания вызова истекло, что очень полезно для отладки понимания сети. Вывод каждой строки представляет собой время начала системного вызова, команду системного вызова, параметры системного вызова, возвращаемое значение системного вызова и время обработки системного вызова.

2: Пример 2

# 输出 nginx 工作进程 PID 号
$ ps -uax | grep "nginx: worker process" | grep -v "grep" | awk '{print $2}' 
29785 

$ strace -p  29785 -Fскопировать код

В приведенном выше примере strace наблюдает за работой рабочего процесса nginx, чтобы понять, как внутри обрабатываются соединения.

Параметр -p указывает номер PID процесса отслеживания, а -F указывает подпроцесс, вызываемый процессом (например, PHP, выполняющий вызов exec), что является очень важным параметром.

Результат выглядит следующим образом:

Process 29785 attached
epoll_wait(9, {{EPOLLIN, {u32=3975708920, u64=140539600601336}}}, 512, -1) = 1
accept4(7, {sa_family=AF_INET, sin_port=htons(50787), sin_addr=inet_addr("218.30.113.40")}, [16], SOCK_NONBLOCK) = 3
epoll_ctl(9, EPOLL_CTL_ADD, 3, {EPOLLIN|EPOLLRDHUP|EPOLLET, {u32=3975710081, u64=140539600602497}}) = 0
epoll_wait(9, {{EPOLLIN, {u32=3975710081, u64=140539600602497}}}, 512, 60000) = 1
recvfrom(3, "\26", 1, MSG_PEEK, NULL, NULL) = 1
setsockopt(3, SOL_TCP, TCP_NODELAY, [1], 4) = 0
read(3, "\26\3\1\2\24\1\0\2\20\3\3\361\365r\343(\362p\320RV9\1\316S\31jCQ\211\22\264"..., 16709) = 537скопировать код

Видно, что nginx получил запрос от 218.30.113.40:50787 Весь процесс очень полезен для понимания сетевого программирования.

3: Пример третий

$ strace -c -o out.log php test.phpскопировать код

Параметр -c может обобщать отчет о системных вызовах, например номер системного вызова, количество сбоев и т. д., а параметр -o может сохранять вывод strace в файл out.log.

Аналогичные результаты вывода следующие:

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 21.57    0.000107           1       169           mmap
 18.75    0.000093           1        88           mprotect
 15.12    0.000075           1        81         3 open
 11.29    0.000056           1        80           rt_sigaction
  7.26    0.000036           2        20        19 access
  6.05    0.000030           1        47           readскопировать код

Если скрипт работает очень медленно, то этот параметр, вероятно, может понять, какая система медленная, и, таким образом, определить проблему.

Наконец, вводится очень полезный параметр отладки.Вы можете использовать -e для управления регулярными выражениями, такими как вывод всехwriteродственные звонки.

$ strace -e write php test.phpскопировать код

Вывод команды следующий:

write(1, "start\n", 6start
)                  = 6
write(3, "testdata\r\n", 10)            = 10
+++ exited with 0 +++скопировать код

Невозможно использовать этот инструмент.Сложно то, как подробно проанализировать проблему и позволить инструменту помочь вам.Эта статья предназначена только для того, чтобы предложить идею.Самое главное-практиковаться и набираться опыта.