На прошлой неделе фоновый скрипт 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 +++
скопировать код
Невозможно использовать этот инструмент.Сложно то, как подробно проанализировать проблему и позволить инструменту помочь вам.Эта статья предназначена только для того, чтобы предложить идею.Самое главное-практиковаться и набираться опыта.