Получение трассировки стека

Дата обновления перевода 2021-08-05

Получение трассировки стека

При заявлении об баге, кроме случаев неправильного поведения в коде, очень важно, чтобы вы предоставляли один или несколько трассировок стека. Чтобы понять, зачем, для начала вам нужно понять. что такое трассировка стека и как она может быть полезна вам как разработчику, а также менеджерам библиотек.

Анатомия трассировки стека

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

Трассировки стека и исключения

В PHP, каждое исключение имеет собственную трассировку стека, которая отображается по умолчанию, если исключение не обнаружено. При использовании Symfony, такие исключение проходят через пользовательский обработчик исключений, который улучшает их множеством способов до отображения текущему серверу API (CLI или нет). Это означает более удобный способ получения трассировки стека, когда вам не нужно, чтобы программа продолжала вызывать исключения, следующим образом: throw new \Exception();

Встроенные исключения

По мере роста приложений, их сложность часто обрабатывается слоями архитектуры, которые нужно разделять. Например, если у вас имеется веб-приложение, которое делает вызов к удаленному API, при совершении этого вызова может быть полезно обернуть исключения исключениями, которые имеют особый смысл в вашем домене, и создать соответствующие HTTP-исключения из них. Исключения могут быть встроены с использованием аргумента $previous, который отображается в подписи класса Exception: public __construct ([ string $message = "" [, int $code = 0 [, Throwable $previous = NULL ]]] ) Это означает, что иногда, когда вы получаете исключение из приложения, на самом деле у вас их может быть несколько.

Что искать в трассировке стека

При использовании библиотеки, вы будете вызывать код, который вы не писали. При использовании фреймворка, все наоборот: так как вы следуете соглашениям фреймворка, фреймворк находит ваш код и вызывает его, и делает какие-то вещи за вас, вроде маршрутизации или контроля доступа. Symfony является и фреймворком, и библиотекой компонентов, поэтому вызывает ваш код и затем ваш код может вызвать ее. Это означает, что у вас всегда будет минимум 2 части, а зачастую и 3, в ваших трассировках стека, при использовании Symfony: часть, которая начинается в одной из точек входа фреймворка (в большинстве случаев bin/console или public/index.php), и заканчивается при достижении вашего кода, в большинстве случаев в команде или в контроллере, находящимся под src. Затем, будет вызвано исключение либо в вашем коде, либо в вызываемых вами библиотеках. Последнее требует третьей части трассировки стека, с вызовами в файлах под vendor. До того, как оказаться в этой библиотеке, код проходит через множество процессов рассмотрения и конвейеров CI, что означает, что он с меньшей вероятностью станет источником проблемы, чем код вашего приложения, так что вам важно сначала фокусироваться на строках, начинающихся с src, и искать все, что выглядит подозрительно или неожиданно, вроде вызовов метода, которые не должны происходить.

Далее, вы можете посмотреть, какие пакеты вовлечены. Файлы под vendor систематизированы Composer в следующем порядке: vendor/acme/router. где acme - поставщик, router - библиотека, а acme/router - пакет Composer. Если вы планируете заявить о баге, убедитесь, что заявляете о нем библиотеке, которая вызывает исключение. composer home acme/router должен привести вас в правильное место. Так как Symfony является монохранилищем, используйте composer home symfony/symfony при зявлении о баге в любом компоненте.

Получение трассировки стека в Symfony

Теперь, когда мы все это знаем, давайте посмотрим, как получить трассировку стека в Symfony.

Трассировки стека в вашем веб-браузере

Необходимо помнить о нескольких вещах при выборе трассировки стека из вашего окружения разработки через веб-браузер:

  1. Исключений несколько? Если да, то наиболее инетерсным чаще всего является 1/n, которое отображается последним в примере ниже (оно обозначено как исключение [1/2]).
  2. Во вкладке "Stack Traces", вы найдете исключения, написанные простым текстом, чтобы вы могли легко делиться ими, например, в отчетах о багах. Убедитесь в том, что вы удалили конфиденциальную информацию до того, как делиться.
  3. Вы можете заметить, что существует также вкладка логов; эта вкладка не имеет ничего общего с трассировкой стека, а содержит только логи, произведенные в произвольных местах вашего приложения. Они могут относиться к тому исключению, которое вы получаете, или нет, но не являются тем, что подразумевает под собой термин "трассировка стека".

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

Трассировки стека в CLI

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ php bin/console debug:exception


   Command "debug:exception" is not defined.

   Did you mean one of these?
       debug:autowiring
       debug:config
       debug:container
       debug:event-dispatcher
       debug:form
       debug:router
       debug:translation
       debug:twig

Если это не тот случай, вы можете получить трассировку стека, увеличив уровень детальности с помощью --verbose:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ php bin/console --verbose debug:exception

 In Application.php line 644:

   [Symfony\Component\Console\Exception\CommandNotFoundException]
   Command "debug:exception" is not defined.

   Did you mean one of these?
       debug:autowiring
       debug:config
       debug:container
       debug:event-dispatcher
       debug:form
       debug:router
       debug:translation
       debug:twig


 Трассировка исключения:
   at /app/vendor/symfony/console/Application.php:644
  Symfony\Component\Console\Application->find() at /app/vendor/symfony/framework-bundle/Console/Application.php:116
  Symfony\Bundle\FrameworkBundle\Console\Application->find() at /app/vendor/symfony/console/Application.php:228
  Symfony\Component\Console\Application->doRun() at /app/vendor/symfony/framework-bundle/Console/Application.php:82
  Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /app/vendor/symfony/console/Application.php:140
  Symfony\Component\Console\Application->run() at /app/bin/console:42

Трассировки стека и вызовы API

При получении исключения из API, вы можете не получить трассировку стека, или она может быть отображена в виде, непригодном для распространения. К счастью, в окружении разработки, вы можете получить трассировку стека в виде простого текста, используя профилировщик. Чтобы найти профиль, вы можете посмотреть на заголовки ответов X-Debug-Token-Link:

1
2
3
4
5
6
$ curl --head http://localhost:8000/api/posts/1
… more headers
X-Debug-Token: 110e1e
X-Debug-Token-Link: http://localhost:8000/_profiler/110e1e
X-Robots-Tag: noindex
X-Previous-Debug-Token: 209101

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