Профілювальник

Дата оновлення перекладу 2024-06-10

Профілювальник

Профілювальник - це потужний інструмент розробки який надає детальну інформацію про виконання будь-якого запиту.

Caution

Ніколи не підключайте профілювальник у середовищах виробництва, так як це призведе до серйозних вразливостей безпеки вашого додатку.

Установка

У додатках, що використовують Symfony Flex , виконайте цю команду, щоб встановити пакет Symfony profiler перед його використанням:

1
$ composer require --dev symfony/profiler-pack

Тепер, відкрийте будь-яку сторінку вашого додатку у середовищі розробки, щоб дозволити профілювальнику зібрати інформацію. Потім, натисніть на будь-який елемент панелі інструментів налагодження, впровадженої знизу ваших сторінок, щоб відкрити веб-інтерфейс Профілювальника Symfony, який виглядатиме так:

Сторінка веб-профілювальника Symfony.

Note

Панель інструментів налагодження впроваджується лише у HTML-відповіді. Для інших типів змісту (наприклад, JSON-відповідей у заптах API) URL профілювальника пдоступний в HTTP-заголовку відповіді X-Debug-Token-Link. Перейдіть по URL /_profiler, щоб побачити всі профілі.

Note

To limit the storage used by profiles on disk, they are probabilistically removed after 2 days.

Програмний доступ до даних профілювання

У більшості випадків, доступ та аналіз інформації профілювальника відбувається з використанням його веб-інтерфейсу. Однак, ви також можете вилучити інформацію профілювання пограмно, завдяки методам, наданим сервісом profiler.

Коли доступний обʼєкт відповіді, використайте метод loadProfileFromResponse(), щоб отримати доступ до його асоційованого профілю:

1
2
// ... $profiler - це сервіс 'profiler'
$profile = $profiler->loadProfileFromResponse($response);

Коли профілювальник зберігає дані про запит, він також асоціює з ним токен; цей токен доступний в HTTP-заголовку відповіді X-Debug-Token. Використовуючи цей токен, ви можете отримати доступ до профілю будь-якого попереднього запиту, завдяки методу loadProfile():

1
2
$token = $response->headers->get('X-Debug-Token');
$profile = $profiler->loadProfile($token);

Tip

Коли профілювальник включено, але не у панелі веб-інструментів налагодження, дослідіть сторінку за допомогоб інструментів розробника вашого браузера, щоб отримати значення HTTP-заголовку X-Debug-Token.

Сервіс profiler також надає метод find(), щоб шукати токени, засновуючись на якихось критеріях:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// отримує останні 10 токенів
$tokens = $profiler->find('', '', 10, '', '', '');

// отримує останні 10 токенів для всіх URL, що містять /admin/
$tokens = $profiler->find('', '/admin/', 10, '', '', '');

// отримує останні 10 токенів для всіх URL, що не містять /api/
$tokens = $profiler->find('', '!/api/', 10, '', '', '');

// отримує останні 10 токенів для локальних запитів POST
$tokens = $profiler->find('127.0.0.1', '', 10, 'POST', '', '');

// отримує останні 10 токенів для запитів, які відбулися від 2 до 4 днів тому
$tokens = $profiler->find('', '', 10, '', '4 days ago', '2 days ago');

Колектори даних

Профілювальник отримує інформацію, використовуючи деякі сервіси під назвою "колектори даних". Symfony постачається з декількома колекторами, які отирмують інфомацію про запит, логер, машрутизацію, кеш та ін.

Виконайте цю команду, щоб отримати перелік колекторів, дійсно включених у вашому додатку:

1
$ php bin/console debug:container --tag=data_collector

Ви також можете створити власний колектор даних, щоб зберігати будь-які дані, згенеровані вашим додатком, та відображати їх у панелі інструментів налагодження та веб-інтерфейсі профілювальника.

Засікання часу виконання додатку

Якщо ви хочете виміряти час, який займають якісь задачі у вашому додатку, немає необхідності створювати користувацький колектор даних. Натомість, використайте вбудовані утиліти, щоб профілювати додатки Symfony .

Tip

Розгляньте використання професійного профілювальника типу Blackfire, щоб виміряти час та проаналізувати виконання вашого додатку детально.

Включення профілювальника програмно

Профілювальник Symfony не може бути включено/відключено за умовами, використовуючи зіставники, так як ця функція була видалена в Symfony 4.0. Однак, ви можете використати методи enable() та disable() класу Profiler у ваших контролерах, щоб управляти профілювальником програмно:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use Symfony\Component\HttpKernel\Profiler\Profiler;
// ...

class DefaultController
{
    // ...

    public function someMethod(?Profiler $profiler): Response
    {
        // $profiler не буде встановлено, якщо ваше середовище не має профілювальника (як prod, за замовчуванням)
        if (null !== $profiler) {
            // якщо він існує, відключіть профілювальник для цієї конкретної дії контролера
            $profiler->disable();
        }

        // ...
    }
}

Для того, щоб профілювальник був впроваджений у ваш контролер, вам потрібно створити псевдонім, що вказує на існуючий сервіс profiler:

1
2
3
# config/services_dev.yaml
services:
    Symfony\Component\HttpKernel\Profiler\Profiler: '@profiler'

Ввімкнення профілювальника з умовами

Замість того, щоб вмикати профілювальник програмно, як описано у попередньому розділі, ви також можете увімкнути його при виконанні певної умови (наприклад, коли певний параметр включено до URL):

1
2
3
4
5
# config/packages/dev/web_profiler.yaml
    framework:
        profiler:
            collect: false
            collect_parameter: 'profile'
Ця конфігурація вимикає профілювальник за замовчуванням (collect: false) для
покращення продуктивності додатку; але вмикає його для запитів, які містять параметр запиту profile (ви можете вільно обирати назву цього параметра запиту).
Крім параметра запиту, ця функція також працює при відправці поля форми з таким ім'ям
(корисно для ввімкнення профілювальника в POST запитах)

або при включенні його як атрибута запиту.

Оновлення панелі веб-інструментів налагодження після запитів AJAX

Односторінкові додатки (SPA) - це веб-додатки, які взаємодіють з користувачем, динамічно перреписуючи поточну сторінку, а не завантажуючи цілі нові сторінки з сервера.

За замовчуванням, панель інструментів налагодження відображує інформацію завантаження початкової сторінки і не оновлюється після кожного запиту AJAX. Однак, ви можете встановити заголовок Symfony-Debug-Toolbar-Replace у значення 1 у відповідь на запит AJAX, щоб форсувати оновлення панелі інструментів:

1
$response->headers->set('Symfony-Debug-Toolbar-Replace', 1);

В ідеалі цей заголовок має бути встановлений лише під час розробки і не у виробництві. Щоб зробити це, створіть підписник подій та слухайте подію kernel.response :

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
26
27
28
29
30
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelInterface;

// ...

class MySubscriber implements EventSubscriberInterface
{
    public function __construct(
        private KernelInterface $kernel,
    ) {
    }

    // ...

    public function onKernelResponse(ResponseEvent $event): void
    {
        if (!$this->kernel->isDebug()) {
            return;
        }

        $request = $event->getRequest();
        if (!$request->isXmlHttpRequest()) {
            return;
        }

        $response = $event->getResponse();
        $response->headers->set('Symfony-Debug-Toolbar-Replace', '1');
    }
}

Створення колектора даних

Symfony Profiler отримує інформацію для профілювання та налагодження за допомогою деяких спеціальних класів, які називаються колекторами даних. Symfony постачається з декількома з них, але ви також можете створити свій власний.

Колектор даних - це PHP-клас, який реалізує DataCollectorInterface. Для зручності, ваші колектори даних також можуть розширюватися з класу AbstractDataCollector, який реалізує інтерфейс і надає деякі утиліти та властивість $this->data для зберігання зібраної інформації.

У наступному прикладі показано користувацький колектор, який зберігає інформацію про запит:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// src/DataCollector/RequestCollector.php
namespace App\DataCollector;

use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class RequestCollector extends AbstractDataCollector
{
    public function collect(Request $request, Response $response, \Throwable $exception = null): void
    {
        $this->data = [
            'method' => $request->getMethod(),
            'acceptable_content_types' => $request->getAcceptableContentTypes(),
        ];
    }
}

Ось методи, які ви можете визначити у клас колектора даних:

Метод collect():

Зберігає зібрані дані у локальних властивостях ($this->data, якщо ви розширюєте з AbstractDataCollector). Якщо вам потрібні якісь сервіси для збору даних, додайте ці сервіси до конструктора колектора даних.

Caution

Метод collect() викликається лише один раз. Він не використовується для "збору" даних, але існує для "підбирання" даних, які були збережені вашим сервісом.

Caution

Оскільки профілювальник серіалізує екземпляри колекторів даних, вам не слід зберігати об'єкти, які не можна серіалізувати (наприклад, об'єкти PDO), або вам потрібно надати власний метод серіалізувати().

Метод reset():
Викликається між запитами для скидання стану профілювальника. За замовчуванням очищується лише зміст $this->data, але ви можете перевизначити цей метод для додаткового очищення.
Метод getName():
Повертає ідентифікатор колектора, який має бути унікальним у додатку. За замовчуванням повертає FQCN класу колектора даних, але ви можете перевизначити цей метод, щоб повернути користувацьке ім'я (наприклад, app.request_collector). Це значення використовується пізніше для доступу до інформації про колектор (див. Як використовувати профілювальник у функціональному тесті), тому ви можете використовувати короткі рядки замість рядків FQCN.

Метод collect() викликається під час події kernel.response . Якщо вам потрібно зібрати дані, які будуть доступні лише пізніше, реалізуйте LateDataCollectorInterface63871210454396bd39dcc1a502d798cb149379e9lateCollect()`, який викликається безпосередньо перед серіалізацією даних профілювальника (під час події kernel.terminate ).

Note

Якщо ви використовуєте конфігурацію services.yaml за замовчуванням з autoconfigure, то Symfony почне використовувати ваш колектор даних після наступного оновлення сторінки. В іншому випадку, увімкніть колектор даних вручну .

Додавання шаблонів веб-профілювальника

Інформація, зібрана вашим колектором даних, може відображатися як у панелі інструментів веб-налагодження, так і у веб-профілювальнику. Для цього вам потрібно створити шаблон Twig шаблон, який містить певні блоки.

По-перше, додайте метод getTemplate() в клас вашого колектора даних, який повертає шлях до шаблону Twig, який потрібно використовувати. Потім додайте кілька геттерів, щоб надати шаблону шаблону доступ до зібраної інформації:

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
26
27
28
29
30
31
// src/DataCollector/RequestCollector.php
namespace App\DataCollector;

use Symfony\Bundle\FrameworkBundle\DataCollector\AbstractDataCollector;
use Symfony\Component\VarDumper\Cloner\Data;

class RequestCollector extends AbstractDataCollector
{
    // ...

    public static function getTemplate(): ?string
    {
        return 'data_collector/template.html.twig';
    }

    public function getMethod(): string
    {
        return $this->data['method'];
    }

    public function getAcceptableContentTypes(): array
    {
        return $this->data['acceptable_content_types'];
    }

    public function getSomeObject(): Data
    {
        // використати метод cloneVar(), щоб скинути зібрані дані у профілювальник
        return $this->cloneVar($this->data['method']);
    }
}

У найпростішому випадку ви хочете відобразити інформацію на панелі інструментів без використання панелі профілювальника. Для цього потрібно визначити блок toolbar і встановити значення двох змінних під назвою icon і text:

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
26
27
28
{# templates/data_collector/template.html.twig #}
{% extends '@WebProfiler/Profiler/layout.html.twig' %}

{% block toolbar %}
    {% set icon %}
        {# це зміст, який відображається як панель у панелі інструментів #}
        <svg xmlns="http://www.w3.org/2000/svg"> ... </svg>
        <span class="sf-toolbar-value">Request</span>
    {% endset %}

    {% set text %}
        {# це зміст, який відображається при наведенні курсору
           the toolbar panel #}
        <div class="sf-toolbar-info-piece">
            <b>Method</b>
            <span>{{ collector.method }}</span>
        </div>

        <div class="sf-toolbar-info-piece">
            <b>Accepted content type</b>
            <span>{{ collector.acceptableContentTypes|join(', ') }}</span>
        </div>
    {% endset %}

    {# значення 'link', встановлене як 'false', означає, що ця панель не відображає
       розділ у веб-профілювальнику #}
    {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: false }) }}
{% endblock %}

Tip

Іконки Symfony Profiler вибираються з іконок Tabler, великої відкритої колекції іконок
у форматі SVG. Рекомендується також використовувати ці іконки для ваших власних панелей профілювальника, щоб отримати узгоджений вигляд.

Tip

Вбудовані шаблони колекторів визначають всі свої зображення як вбудовані SVG-файли. Це дозволяє їм працювати скрізь без необхідності змінювати посилання на веб-ресурси:

1
2
3
4
{% set icon %}
    {{ include('data_collector/icon.svg') }}
    {# ... #}
{% endset %}

Якщо панель інструментів містить розширену інформацію веб-профілювальника, шаблон Twig також має визначати додаткові блоки:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
{# templates/data_collector/template.html.twig #}
{% extends '@WebProfiler/Profiler/layout.html.twig' %}

{% block toolbar %}
    {% set icon %}
        {# ... #}
    {% endset %}

    {% set text %}
        <div class="sf-toolbar-info-piece">
            {# ... #}
        </div>
    {% endset %}

    {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { 'link': true }) }}
{% endblock %}

{% block head %}
    {# Опціональьно. Тут ви можете послатися на або визначити ваш власний зміст CSS та JS. #}
    {# Використайте {{ parent() }}, щоб розширити стилі за замовчуванням замість того, щоб перевизначати їх. #}
{% endblock %}

{% block menu %}
    {# Це лівостороннє меню зʼявляється прир використанні повноекранного профілювальника. #}
    <span class="label">
        <span class="icon"><img src="..." alt=""/></span>
        <strong>Request</strong>
    </span>
{% endblock %}

{% block panel %}
    {# Опціонально, для відображення найбільшої кількості деталей. #}
    <h2>Acceptable Content Types</h2>
    <table>
        <tr>
            <th>Content Type</th>
        </tr>

        {% for type in collector.acceptableContentTypes %}
        <tr>
            <td>{{ type }}</td>
        </tr>
        {% endfor %}
    </table>
{% endblock %}

Блоки menu і panel є єдиними обовʼязковими блоками для визначення змісту, що відображається на панелі веб-профілювальника, пов'язаного з цим колектором даних. Всі блоки мають доступ до об'єкта collector.

Note

Положення кожної панелі на панелі інструментів визначається пріоритетом колектора, який можна визначити лише при конфігуруванні колектора даних вручну .

Note

Якщо ви використовуєте конфігурацію services.yaml за замовчуванням з autoconfigure, то Symfony почне відображати дані вашого колектора в панелі інструментів після наступного оновлення сторінки. В іншому випадку, увімкніть колектор даних вручну .

Увімкнення користувацьких колекторів даних

Якщо ви не використовуєте конфігурацію Symfony за замовчуванням з автомонтуванням та автоконфігурацією вам потрібно буде налаштувати колектор даних явно:

1
2
3
4
5
6
7
8
9
10
11
12
# config/services.yaml
services:
    App\DataCollector\RequestCollector:
        tags:
            -
                name: data_collector
                # має співпадати зі значенням, поверненим методом getName()
                id: 'App\DataCollector\RequestCollector'
                # опціональний шаблон (має вищий пріоритет, ніж значення, повернене  getTemplate())
                template: 'data_collector/template.html.twig'
                # опціональний пріоритет (додатне або від'ємне ціле число; за замовчуванням = 0)
                # priority: 300