Джерело: https://laravelukraine.com/docs/13.x/pulse

# Laravel Pulse

- [Вступ](#introduction)
- [Встановлення](#installation)
    - [Конфігурація](#configuration)
- [Панель](#dashboard)
    - [Авторизація](#dashboard-authorization)
    - [Налаштування](#dashboard-customization)
    - [Отримання користувачів](#dashboard-resolving-users)
    - [Картки](#dashboard-cards)
- [Захоплення записів](#capturing-entries)
    - [Рекордери](#recorders)
    - [Фільтрація](#filtering)
- [Продуктивність](#performance)
    - [Використання іншої бази даних](#using-a-different-database)
    - [Приймання через Redis](#ingest)
    - [Семплювання](#sampling)
    - [Обрізання](#trimming)
    - [Обробка винятків Pulse](#pulse-exceptions)
- [Власні картки](#custom-cards)
    - [Компоненти карток](#custom-card-components)
    - [Стилізація](#custom-card-styling)
    - [Захоплення й агрегація даних](#custom-card-data)

<a name="introduction"></a>
## Вступ

[Laravel Pulse](https://github.com/laravel/pulse) дає змогу одним поглядом оцінити продуктивність і використання вашого застосунку. З Pulse ви можете відстежувати вузькі місця на кшталт повільних завдань і ендпоїнтів, знаходити найактивніших користувачів тощо.

Для докладного налагодження окремих подій погляньте на [Laravel Telescope](/docs/{{version}}/telescope).

<a name="installation"></a>
## Встановлення

> [!WARNING]
> Власна реалізація сховища Pulse наразі потребує бази даних MySQL, MariaDB чи PostgreSQL. Якщо ви використовуєте інший рушій бази даних, вам знадобиться окрема база MySQL, MariaDB чи PostgreSQL для даних Pulse.

Встановити Pulse можна через менеджер пакетів Composer:

```shell
composer require laravel/pulse
```

Далі вам слід опублікувати конфігураційний файл і файли міграцій Pulse артизан-командою `vendor:publish`:

```shell
php artisan vendor:publish --provider="Laravel\Pulse\PulseServiceProvider"
```

Насамкінець виконайте команду `migrate`, щоб створити таблиці, потрібні для зберігання даних Pulse:

```shell
php artisan migrate
```

Щойно міграції бази даних Pulse буде виконано, ви зможете відкрити панель Pulse за маршрутом `/pulse`.

> [!NOTE]
> Якщо ви не хочете зберігати дані Pulse в основній базі даних вашого застосунку, ви можете [вказати виділене підключення до бази даних](#using-a-different-database).

<a name="configuration"></a>
### Конфігурація

Багатьма параметрами конфігурації Pulse можна керувати через змінні оточення. Щоб побачити доступні параметри, зареєструвати нові рекордери чи налаштувати розширені опції, ви можете опублікувати конфігураційний файл `config/pulse.php`:

```shell
php artisan vendor:publish --tag=pulse-config
```

<a name="dashboard"></a>
## Панель

<a name="dashboard-authorization"></a>
### Авторизація

Панель Pulse доступна за маршрутом `/pulse`. За замовчуванням ви зможете відкрити цю панель лише в середовищі `local`, тож для продакшен-середовищ вам потрібно буде налаштувати авторизацію, змінивши гейт авторизації `'viewPulse'`. Зробити це можна у файлі `app/Providers/AppServiceProvider.php` вашого застосунку:

```php
use App\Models\User;
use Illuminate\Support\Facades\Gate;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Gate::define('viewPulse', function (User $user) {
        return $user->isAdmin();
    });

    // ...
}
```

<a name="dashboard-customization"></a>
### Налаштування

Картки та компонування панелі Pulse можна налаштувати, опублікувавши представлення панелі. Представлення панелі буде опубліковано в `resources/views/vendor/pulse/dashboard.blade.php`:

```shell
php artisan vendor:publish --tag=pulse-dashboard
```

Панель працює на [Livewire](https://livewire.laravel.com/) і дозволяє налаштовувати картки та компонування без потреби перезбирати JavaScript-ассети.

У цьому файлі за рендеринг панелі відповідає компонент `<x-pulse>`, який надає сітку для карток. Якщо ви хочете, щоб панель займала всю ширину екрана, передайте компоненту проп `full-width`:

```blade
<x-pulse full-width>
    ...
</x-pulse>
```

За замовчуванням компонент `<x-pulse>` створить сітку з 12 колонок, але ви можете змінити це пропом `cols`:

```blade
<x-pulse cols="16">
    ...
</x-pulse>
```

Кожна картка приймає пропи `cols` і `rows` для керування простором і розташуванням:

```blade
<livewire:pulse.usage cols="4" rows="2" />
```

Більшість карток також приймають проп `expand`, щоб показати картку повністю замість прокручування:

```blade
<livewire:pulse.slow-queries expand />
```

<a name="dashboard-resolving-users"></a>
### Отримання користувачів

Для карток, які показують інформацію про ваших користувачів, як-от картка Application Usage, Pulse записуватиме лише ID користувача. Під час рендерингу панелі Pulse візьме поля `name` і `email` з вашої моделі `Authenticatable` за замовчуванням і показуватиме аватари через вебсервіс Gravatar.

Ви можете змінити ці поля й аватар, викликавши метод `Pulse::user` у класі `App\Providers\AppServiceProvider` вашого застосунку.

Метод `user` приймає замикання, яке отримає модель `Authenticatable` для показу і має повернути масив з інформацією `name`, `extra` та `avatar` для користувача:

```php
use Laravel\Pulse\Facades\Pulse;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Pulse::user(fn ($user) => [
        'name' => $user->name,
        'extra' => $user->email,
        'avatar' => $user->avatar_url,
    ]);

    // ...
}
```

> [!NOTE]
> Ви можете повністю змінити те, як захоплюється й отримується автентифікований користувач, реалізувавши контракт `Laravel\Pulse\Contracts\ResolvesUsers` і прив'язавши його в [сервіс-контейнері](/docs/{{version}}/container#binding-a-singleton) Laravel.

<a name="dashboard-cards"></a>
### Картки

<a name="servers-card"></a>
#### Сервери

Картка `<livewire:pulse.servers />` показує використання системних ресурсів для всіх серверів, на яких запущено команду `pulse:check`. Докладніше про звітування про системні ресурси дивіться в документації щодо [рекордера серверів](#servers-recorder).

Якщо ви заміните сервер у своїй інфраструктурі, ви можете захотіти, щоб неактивний сервер перестав показуватися на панелі Pulse через певний час. Зробити це можна пропом `ignore-after`, який приймає кількість секунд, після яких неактивні сервери слід прибрати з панелі Pulse. Як альтернативу ви можете передати рядок з відносним часом, наприклад `1 hour` чи `3 days and 1 hour`:

```blade
<livewire:pulse.servers ignore-after="3 hours" />
```

<a name="application-usage-card"></a>
#### Використання застосунку

Картка `<livewire:pulse.usage />` показує топ-10 користувачів, які роблять запити до вашого застосунку, диспетчеризують завдання та стикаються з повільними запитами.

Якщо ви хочете бачити всі метрики використання на екрані одночасно, ви можете додати картку кілька разів і вказати атрибут `type`:

```blade
<livewire:pulse.usage type="requests" />
<livewire:pulse.usage type="slow_requests" />
<livewire:pulse.usage type="jobs" />
```

Щоб дізнатися, як налаштувати спосіб, у який Pulse отримує та показує інформацію про користувачів, зверніться до нашої документації щодо [отримання користувачів](#dashboard-resolving-users).

> [!NOTE]
> Якщо ваш застосунок отримує багато запитів чи диспетчеризує багато завдань, ви можете захотіти увімкнути [семплювання](#sampling). Докладніше дивіться в документації [рекордера запитів користувачів](#user-requests-recorder), [рекордера завдань користувачів](#user-jobs-recorder) і [рекордера повільних завдань](#slow-jobs-recorder).

<a name="exceptions-card"></a>
#### Винятки

Картка `<livewire:pulse.exceptions />` показує частоту та свіжість винятків, що трапляються у вашому застосунку. За замовчуванням винятки групуються за класом винятку й місцем, де він стався. Докладніше дивіться в документації [рекордера винятків](#exceptions-recorder).

<a name="queues-card"></a>
#### Черги

Картка `<livewire:pulse.queues />` показує пропускну здатність черг у вашому застосунку, включно з кількістю завдань у черзі, в обробці, оброблених, повернутих і невдалих. Докладніше дивіться в документації [рекордера черг](#queues-recorder).

<a name="slow-requests-card"></a>
#### Повільні запити

Картка `<livewire:pulse.slow-requests />` показує вхідні запити до вашого застосунку, які перевищують налаштований поріг, що за замовчуванням становить 1 000 мс. Докладніше дивіться в документації [рекордера повільних запитів](#slow-requests-recorder).

<a name="slow-jobs-card"></a>
#### Повільні завдання

Картка `<livewire:pulse.slow-jobs />` показує завдання з черги у вашому застосунку, які перевищують налаштований поріг, що за замовчуванням становить 1 000 мс. Докладніше дивіться в документації [рекордера повільних завдань](#slow-jobs-recorder).

<a name="slow-queries-card"></a>
#### Повільні запити до бази

Картка `<livewire:pulse.slow-queries />` показує запити до бази даних у вашому застосунку, які перевищують налаштований поріг, що за замовчуванням становить 1 000 мс.

За замовчуванням повільні запити до бази групуються за SQL-запитом (без прив'язок) і місцем, де вони сталися, але ви можете не захоплювати місце, якщо хочете групувати лише за SQL-запитом.

Якщо ви стикаєтеся з проблемами продуктивності рендерингу через підсвічування синтаксису надзвичайно великих SQL-запитів, ви можете вимкнути підсвічування, додавши проп `without-highlighting`:

```blade
<livewire:pulse.slow-queries without-highlighting />
```

Докладніше дивіться в документації [рекордера повільних запитів до бази](#slow-queries-recorder).

<a name="slow-outgoing-requests-card"></a>
#### Повільні вихідні запити

Картка `<livewire:pulse.slow-outgoing-requests />` показує вихідні запити, зроблені через [HTTP-клієнт](/docs/{{version}}/http-client) Laravel, які перевищують налаштований поріг, що за замовчуванням становить 1 000 мс.

За замовчуванням записи групуються за повним URL. Однак ви можете захотіти нормалізувати чи згрупувати схожі вихідні запити за допомогою регулярних виразів. Докладніше дивіться в документації [рекордера повільних вихідних запитів](#slow-outgoing-requests-recorder).

<a name="cache-card"></a>
#### Кеш

Картка `<livewire:pulse.cache />` показує статистику влучань і промахів кешу для вашого застосунку - як загалом, так і за окремими ключами.

За замовчуванням записи групуються за ключем. Однак ви можете захотіти нормалізувати чи згрупувати схожі ключі за допомогою регулярних виразів. Докладніше дивіться в документації [рекордера взаємодій з кешем](#cache-interactions-recorder).

<a name="capturing-entries"></a>
## Захоплення записів

Більшість рекордерів Pulse автоматично захоплюють записи на основі подій фреймворку, які диспетчеризує Laravel. Однак [рекордер серверів](#servers-recorder) і деякі сторонні картки мають регулярно опитувати інформацію. Щоб користуватися цими картками, вам потрібно запустити демон `pulse:check` на всіх ваших окремих серверах застосунку:

```php
php artisan pulse:check
```

> [!NOTE]
> Щоб процес `pulse:check` постійно працював у фоні, вам слід використовувати монітор процесів на кшталт Supervisor, аби команда не припиняла роботу.

Оскільки команда `pulse:check` - це довготривалий процес, вона не побачить змін у вашій кодовій базі без перезапуску. Вам слід коректно перезапускати команду, викликаючи команду `pulse:restart` під час розгортання вашого застосунку:

```shell
php artisan pulse:restart
```

> [!NOTE]
> Pulse використовує [кеш](/docs/{{version}}/cache) для зберігання сигналів перезапуску, тож перед використанням цієї можливості переконайтеся, що драйвер кешу правильно налаштований для вашого застосунку.

<a name="recorders"></a>
### Рекордери

Рекордери відповідають за захоплення записів з вашого застосунку для збереження в базі даних Pulse. Рекордери реєструються й налаштовуються в секції `recorders` [конфігураційного файлу Pulse](#configuration).

<a name="cache-interactions-recorder"></a>
#### Взаємодії з кешем

Рекордер `CacheInteractions` захоплює інформацію про влучання та промахи [кешу](/docs/{{version}}/cache) у вашому застосунку для показу на картці [Кеш](#cache-card).

За бажанням ви можете скоригувати [частоту семплювання](#sampling) та шаблони ігнорованих ключів.

Ви також можете налаштувати групування ключів, щоб схожі ключі групувалися в один запис. Наприклад, ви можете захотіти прибрати унікальні ID з ключів, що кешують той самий тип інформації. Групи налаштовуються регулярним виразом, який «знаходить і замінює» частини ключа. Приклад є в конфігураційному файлі:

```php
Recorders\CacheInteractions::class => [
    // ...
    'groups' => [
        // '/:\d+/' => ':*',
    ],
],
```

Використано буде перший шаблон, який збігся. Якщо жоден шаблон не збігається, ключ буде захоплено як є.

<a name="exceptions-recorder"></a>
#### Винятки

Рекордер `Exceptions` захоплює інформацію про придатні до звітування винятки, що трапляються у вашому застосунку, для показу на картці [Винятки](#exceptions-card).

За бажанням ви можете скоригувати [частоту семплювання](#sampling) та шаблони ігнорованих винятків. Ви також можете налаштувати, чи захоплювати місце, звідки походить виняток. Захоплене місце буде показано на панелі Pulse, що може допомогти відстежити походження винятку; однак, якщо той самий виняток трапляється в кількох місцях, він з'явиться кілька разів - по одному для кожного унікального місця.

<a name="queues-recorder"></a>
#### Черги

Рекордер `Queues` захоплює інформацію про черги вашого застосунку для показу на картці [Черги](#queues-card).

За бажанням ви можете скоригувати [частоту семплювання](#sampling) та шаблони ігнорованих завдань.

<a name="slow-jobs-recorder"></a>
#### Повільні завдання

Рекордер `SlowJobs` захоплює інформацію про повільні завдання у вашому застосунку для показу на картці [Повільні завдання](#slow-jobs-recorder).

За бажанням ви можете скоригувати поріг повільного завдання, [частоту семплювання](#sampling) та шаблони ігнорованих завдань.

Деякі завдання можуть виконуватися довше за інші - і це очікувано. У таких випадках ви можете налаштувати пороги для окремих завдань:

```php
Recorders\SlowJobs::class => [
    // ...
    'threshold' => [
        '#^App\\Jobs\\GenerateYearlyReports$#' => 5000,
        'default' => env('PULSE_SLOW_JOBS_THRESHOLD', 1000),
    ],
],
```

Якщо жоден шаблон регулярного виразу не збігається з іменем класу завдання, буде використано значення `'default'`.

<a name="slow-outgoing-requests-recorder"></a>
#### Повільні вихідні запити

Рекордер `SlowOutgoingRequests` захоплює інформацію про вихідні HTTP-запити, зроблені через [HTTP-клієнт](/docs/{{version}}/http-client) Laravel, які перевищують налаштований поріг, для показу на картці [Повільні вихідні запити](#slow-outgoing-requests-card).

За бажанням ви можете скоригувати поріг повільного вихідного запиту, [частоту семплювання](#sampling) та шаблони ігнорованих URL.

Деякі вихідні запити можуть виконуватися довше за інші - і це очікувано. У таких випадках ви можете налаштувати пороги для окремих запитів:

```php
Recorders\SlowOutgoingRequests::class => [
    // ...
    'threshold' => [
        '#backup.zip$#' => 5000,
        'default' => env('PULSE_SLOW_OUTGOING_REQUESTS_THRESHOLD', 1000),
    ],
],
```

Якщо жоден шаблон регулярного виразу не збігається з URL запиту, буде використано значення `'default'`.

Ви також можете налаштувати групування URL, щоб схожі URL групувалися в один запис. Наприклад, ви можете захотіти прибрати унікальні ID зі шляхів URL або групувати лише за доменом. Групи налаштовуються регулярним виразом, який «знаходить і замінює» частини URL. Кілька прикладів є в конфігураційному файлі:

```php
Recorders\SlowOutgoingRequests::class => [
    // ...
    'groups' => [
        // '#^https://api\.github\.com/repos/.*$#' => 'api.github.com/repos/*',
        // '#^https?://([^/]*).*$#' => '\1',
        // '#/\d+#' => '/*',
    ],
],
```

Використано буде перший шаблон, який збігся. Якщо жоден шаблон не збігається, URL буде захоплено як є.

<a name="slow-queries-recorder"></a>
#### Повільні запити до бази

Рекордер `SlowQueries` захоплює будь-які запити до бази даних у вашому застосунку, які перевищують налаштований поріг, для показу на картці [Повільні запити до бази](#slow-queries-card).

За бажанням ви можете скоригувати поріг повільного запиту до бази, [частоту семплювання](#sampling) та шаблони ігнорованих запитів. Ви також можете налаштувати, чи захоплювати місце запиту. Захоплене місце буде показано на панелі Pulse, що може допомогти відстежити походження запиту; однак, якщо той самий запит робиться в кількох місцях, він з'явиться кілька разів - по одному для кожного унікального місця.

Деякі запити до бази можуть виконуватися довше за інші - і це очікувано. У таких випадках ви можете налаштувати пороги для окремих запитів:

```php
Recorders\SlowQueries::class => [
    // ...
    'threshold' => [
        '#^insert into `yearly_reports`#' => 5000,
        'default' => env('PULSE_SLOW_QUERIES_THRESHOLD', 1000),
    ],
],
```

Якщо жоден шаблон регулярного виразу не збігається з SQL запиту, буде використано значення `'default'`.

<a name="slow-requests-recorder"></a>
#### Повільні запити

Рекордер `Requests` захоплює інформацію про запити до вашого застосунку для показу на картках [Повільні запити](#slow-requests-card) і [Використання застосунку](#application-usage-card).

За бажанням ви можете скоригувати поріг повільного маршруту, [частоту семплювання](#sampling) та ігноровані шляхи.

Деякі запити можуть виконуватися довше за інші - і це очікувано. У таких випадках ви можете налаштувати пороги для окремих запитів:

```php
Recorders\SlowRequests::class => [
    // ...
    'threshold' => [
        '#^/admin/#' => 5000,
        'default' => env('PULSE_SLOW_REQUESTS_THRESHOLD', 1000),
    ],
],
```

Якщо жоден шаблон регулярного виразу не збігається з URL запиту, буде використано значення `'default'`.

<a name="servers-recorder"></a>
#### Сервери

Рекордер `Servers` захоплює використання процесора, пам'яті та сховища серверами, на яких працює ваш застосунок, для показу на картці [Сервери](#servers-card). Цей рекордер потребує, щоб [команда pulse:check](#capturing-entries) працювала на кожному сервері, за яким ви хочете стежити.

Кожен сервер, що звітує, повинен мати унікальне ім'я. За замовчуванням Pulse використовуватиме значення, яке повертає функція PHP `gethostname`. Якщо ви хочете змінити це, встановіть змінну оточення `PULSE_SERVER_NAME`:

```env
PULSE_SERVER_NAME=load-balancer
```

Конфігураційний файл Pulse також дозволяє налаштувати каталоги, за якими ведеться спостереження.

<a name="user-jobs-recorder"></a>
#### Завдання користувачів

Рекордер `UserJobs` захоплює інформацію про користувачів, які диспетчеризують завдання у вашому застосунку, для показу на картці [Використання застосунку](#application-usage-card).

За бажанням ви можете скоригувати [частоту семплювання](#sampling) та шаблони ігнорованих завдань.

<a name="user-requests-recorder"></a>
#### Запити користувачів

Рекордер `UserRequests` захоплює інформацію про користувачів, які роблять запити до вашого застосунку, для показу на картці [Використання застосунку](#application-usage-card).

За бажанням ви можете скоригувати [частоту семплювання](#sampling) та шаблони ігнорованих URL.

<a name="filtering"></a>
### Фільтрація

Як ми вже бачили, багато [рекордерів](#recorders) дають змогу через конфігурацію «ігнорувати» вхідні записи на основі їхнього значення, наприклад URL запиту. Але іноді буває корисно відфільтрувати записи за іншими чинниками, скажімо за поточним автентифікованим користувачем. Щоб відфільтрувати такі записи, передайте замикання до методу `filter` в Pulse. Зазвичай метод `filter` слід викликати в методі `boot` `AppServiceProvider` вашого застосунку:

```php
use Illuminate\Support\Facades\Auth;
use Laravel\Pulse\Entry;
use Laravel\Pulse\Facades\Pulse;
use Laravel\Pulse\Value;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Pulse::filter(function (Entry|Value $entry) {
        return Auth::user()->isNotAdmin();
    });

    // ...
}
```

<a name="performance"></a>
## Продуктивність

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

<a name="using-a-different-database"></a>
### Використання іншої бази даних

Для високонавантажених застосунків ви можете віддати перевагу виділеному підключенню до бази даних для Pulse, щоб не впливати на базу даних вашого застосунку.

Ви можете змінити [підключення до бази даних](/docs/{{version}}/database#configuration), яке використовує Pulse, встановивши змінну оточення `PULSE_DB_CONNECTION`.

```env
PULSE_DB_CONNECTION=pulse
```

<a name="ingest"></a>
### Приймання через Redis

> [!WARNING]
> Приймання через Redis потребує Redis 6.2 чи новішої версії та `phpredis` або `predis` як налаштованого клієнтського драйвера Redis у застосунку.

За замовчуванням Pulse зберігатиме записи безпосередньо до [налаштованого підключення до бази даних](#using-a-different-database) після того, як HTTP-відповідь буде надіслано клієнту або завдання буде оброблено; однак ви можете скористатися драйвером приймання через Redis, щоб натомість надсилати записи до Redis-стріму. Це вмикається налаштуванням змінної оточення `PULSE_INGEST_DRIVER`:

```ini
PULSE_INGEST_DRIVER=redis
```

За замовчуванням Pulse використовуватиме ваше [підключення Redis](/docs/{{version}}/redis#configuration) за замовчуванням, але ви можете змінити це через змінну оточення `PULSE_REDIS_CONNECTION`:

```ini
PULSE_REDIS_CONNECTION=pulse
```

> [!WARNING]
> Використовуючи драйвер приймання через Redis, ваша інсталяція Pulse завжди має використовувати інше підключення Redis, ніж ваша черга на Redis, якщо така є.

Використовуючи приймання через Redis, вам потрібно буде запустити команду `pulse:work`, щоб стежити за стрімом і переносити записи з Redis до таблиць бази даних Pulse.

```php
php artisan pulse:work
```

> [!NOTE]
> Щоб процес `pulse:work` постійно працював у фоні, вам слід використовувати монітор процесів на кшталт Supervisor, аби воркер Pulse не припиняв роботу.

Оскільки команда `pulse:work` - це довготривалий процес, вона не побачить змін у вашій кодовій базі без перезапуску. Вам слід коректно перезапускати команду, викликаючи команду `pulse:restart` під час розгортання вашого застосунку:

```shell
php artisan pulse:restart
```

> [!NOTE]
> Pulse використовує [кеш](/docs/{{version}}/cache) для зберігання сигналів перезапуску, тож перед використанням цієї можливості переконайтеся, що драйвер кешу правильно налаштований для вашого застосунку.

<a name="sampling"></a>
### Семплювання

За замовчуванням Pulse захоплюватиме кожну релевантну подію, що відбувається у вашому застосунку. Для високонавантажених застосунків це може призвести до потреби агрегувати мільйони рядків бази даних на панелі, особливо для довших періодів часу.

Натомість ви можете увімкнути «семплювання» для певних рекордерів даних Pulse. Наприклад, встановлення частоти семплювання `0.1` для рекордера [Запити користувачів](#user-requests-recorder) означатиме, що ви записуєте лише приблизно 10% запитів до вашого застосунку. На панелі значення буде масштабовано вгору й додано префікс `~`, щоб позначити, що це наближення.

Загалом, чим більше записів ви маєте для конкретної метрики, тим нижче ви можете безпечно встановити частоту семплювання, не жертвуючи занадто великою точністю.

<a name="trimming"></a>
### Обрізання

Pulse автоматично обрізатиме збережені записи, щойно вони вийдуть за межі вікна панелі. Обрізання відбувається під час приймання даних за лотерейною системою, яку можна налаштувати в [конфігураційному файлі](#configuration) Pulse.

<a name="pulse-exceptions"></a>
### Обробка винятків Pulse

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

Якщо ви хочете змінити спосіб обробки цих винятків, передайте замикання до методу `handleExceptionsUsing`:

```php
use Laravel\Pulse\Facades\Pulse;
use Illuminate\Support\Facades\Log;

Pulse::handleExceptionsUsing(function ($e) {
    Log::debug('An exception happened in Pulse', [
        'message' => $e->getMessage(),
        'stack' => $e->getTraceAsString(),
    ]);
});
```

<a name="custom-cards"></a>
## Власні картки

Pulse дозволяє створювати власні картки, щоб показувати дані, релевантні для конкретних потреб вашого застосунку. Pulse використовує [Livewire](https://livewire.laravel.com), тож перед створенням своєї першої власної картки вам, можливо, варто [переглянути його документацію](https://livewire.laravel.com/docs).

<a name="custom-card-components"></a>
### Компоненти карток

Створення власної картки в Laravel Pulse починається з розширення базового Livewire-компонента `Card` і визначення відповідного представлення:

```php
namespace App\Livewire\Pulse;

use Laravel\Pulse\Livewire\Card;
use Livewire\Attributes\Lazy;

#[Lazy]
class TopSellers extends Card
{
    public function render()
    {
        return view('livewire.pulse.top-sellers');
    }
}
```

Коли ви користуєтеся можливістю [лінивого завантаження](https://livewire.laravel.com/docs/lazy) Livewire, компонент `Card` автоматично надасть заглушку, яка враховує атрибути `cols` і `rows`, передані вашому компоненту.

Пишучи відповідне представлення для вашої картки Pulse, ви можете скористатися Blade-компонентами Pulse задля узгодженого вигляду:

```blade
<x-pulse::card :cols="$cols" :rows="$rows" :class="$class" wire:poll.5s="">
    <x-pulse::card-header name="Top Sellers">
        <x-slot:icon>
            ...
        </x-slot:icon>
    </x-pulse::card-header>

    <x-pulse::scroll :expand="$expand">
        ...
    </x-pulse::scroll>
</x-pulse::card>
```

Змінні `$cols`, `$rows`, `$class` і `$expand` слід передати до відповідних Blade-компонентів, щоб компонування картки можна було налаштувати з представлення панелі. Ви також можете додати до свого представлення атрибут `wire:poll.5s=""`, щоб картка оновлювалася автоматично.

Щойно ви визначите свій Livewire-компонент і шаблон, картку можна додати до вашого [представлення панелі](#dashboard-customization):

```blade
<x-pulse>
    ...

    <livewire:pulse.top-sellers cols="4" />
</x-pulse>
```

> [!NOTE]
> Якщо ваша картка входить до складу пакета, вам потрібно буде зареєструвати компонент у Livewire методом `Livewire::component`.

<a name="custom-card-styling"></a>
### Стилізація

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

<a name="custom-card-styling-vite"></a>
#### Інтеграція з Laravel Vite

Якщо ваша власна картка живе в кодовій базі вашого застосунку і ви користуєтеся [інтеграцією з Vite](/docs/{{version}}/vite) у Laravel, ви можете оновити свій файл `vite.config.js`, додавши окрему точку входу CSS для вашої картки:

```js
laravel({
    input: [
        'resources/css/pulse/top-sellers.css',
        // ...
    ],
}),
```

Далі ви можете скористатися Blade-директивою `@vite` у своєму [представленні панелі](#dashboard-customization), вказавши точку входу CSS для вашої картки:

```blade
<x-pulse>
    @vite('resources/css/pulse/top-sellers.css')

    ...
</x-pulse>
```

<a name="custom-card-styling-css"></a>
#### CSS-файли

Для інших випадків, зокрема для карток Pulse у складі пакета, ви можете вказати Pulse завантажити додаткові таблиці стилів, визначивши на своєму Livewire-компоненті метод `css`, який повертає шлях до вашого CSS-файлу:

```php
class TopSellers extends Card
{
    // ...

    protected function css()
    {
        return __DIR__.'/../../dist/top-sellers.css';
    }
}
```

Коли цю картку буде додано на панель, Pulse автоматично вставить вміст цього файлу в тег `<style>`, тож його не потрібно публікувати в каталог `public`.

<a name="custom-card-styling-tailwind"></a>
#### Tailwind CSS

Використовуючи Tailwind CSS, вам слід створити окрему точку входу CSS. Наведений нижче приклад виключає базові стилі [Preflight](https://tailwindcss.com/docs/preflight) з Tailwind, які Pulse уже містить, і обмежує Tailwind CSS-селектором, щоб уникнути конфліктів із класами Tailwind у Pulse:

```css
@import "tailwindcss/theme.css";

@custom-variant dark (&:where(.dark, .dark *));
@source "./../../views/livewire/pulse/top-sellers.blade.php";

@theme {
  /* ... */
}

#top-sellers {
  @import "tailwindcss/utilities.css" source(none);
}
```

Вам також потрібно буде додати до представлення вашої картки атрибут `id` чи `class`, який збігається з CSS-селектором у вашій точці входу:

```blade
<x-pulse::card id="top-sellers" :cols="$cols" :rows="$rows" class="$class">
    ...
</x-pulse::card>
```

<a name="custom-card-data"></a>
### Захоплення й агрегація даних

Власні картки можуть отримувати та показувати дані звідки завгодно; однак ви можете захотіти скористатися потужною та ефективною системою запису й агрегації даних у Pulse.

<a name="custom-card-data-capture"></a>
#### Захоплення записів

Pulse дозволяє записувати «записи» методом `Pulse::record`:

```php
use Laravel\Pulse\Facades\Pulse;

Pulse::record('user_sale', $user->id, $sale->amount)
    ->sum()
    ->count();
```

Перший аргумент, переданий методу `record`, - це `type` запису, який ви записуєте, а другий - `key`, що визначає, як слід групувати агреговані дані. Для більшості методів агрегації вам також потрібно буде вказати `value` для агрегації. У наведеному вище прикладі значення, яке агрегується, - це `$sale->amount`. Далі ви можете викликати один чи кілька методів агрегації (як-от `sum`), щоб Pulse захоплював попередньо агреговані значення у «бакети» для ефективного отримання згодом.

Доступні методи агрегації:

* `avg`
* `count`
* `max`
* `min`
* `sum`

> [!NOTE]
> Створюючи пакет із карткою, який захоплює ID поточного автентифікованого користувача, вам слід використовувати метод `Pulse::resolveAuthenticatedUserId()`, який враховує будь-які [налаштування резолвера користувачів](#dashboard-resolving-users), зроблені в застосунку.

<a name="custom-card-data-retrieval"></a>
#### Отримання агрегованих даних

Розширюючи Livewire-компонент `Card` з Pulse, ви можете скористатися методом `aggregate`, щоб отримати агреговані дані за період, який переглядається на панелі:

```php
class TopSellers extends Card
{
    public function render()
    {
        return view('livewire.pulse.top-sellers', [
            'topSellers' => $this->aggregate('user_sale', ['sum', 'count'])
        ]);
    }
}
```

Метод `aggregate` повертає колекцію PHP-об'єктів `stdClass`. Кожен об'єкт міститиме захоплену раніше властивість `key` разом із ключами для кожного із запитаних агрегатів:

```blade
@foreach ($topSellers as $seller)
    {{ $seller->key }}
    {{ $seller->sum }}
    {{ $seller->count }}
@endforeach
```

Pulse отримуватиме дані переважно з попередньо агрегованих бакетів; тому вказані агрегати мають бути захоплені заздалегідь методом `Pulse::record`. Найстаріший бакет зазвичай частково виходитиме за межі періоду, тож Pulse агрегує найстаріші записи, щоб заповнити прогалину й дати точне значення за весь період, не агрегуючи весь період на кожен запит опитування.

Ви також можете отримати загальне значення для певного типу методом `aggregateTotal`. Наприклад, наведений нижче метод отримав би суму всіх продажів користувачів, не групуючи їх за користувачем.

```php
$total = $this->aggregateTotal('user_sale', 'sum');
```

<a name="custom-card-displaying-users"></a>
#### Показ користувачів

Працюючи з агрегатами, які записують ID користувача як ключ, ви можете перетворити ці ключі на записи користувачів методом `Pulse::resolveUsers`:

```php
$aggregates = $this->aggregate('user_sale', ['sum', 'count']);

$users = Pulse::resolveUsers($aggregates->pluck('key'));

return view('livewire.pulse.top-sellers', [
    'sellers' => $aggregates->map(fn ($aggregate) => (object) [
        'user' => $users->find($aggregate->key),
        'sum' => $aggregate->sum,
        'count' => $aggregate->count,
    ])
]);
```

Метод `find` повертає об'єкт із ключами `name`, `extra` та `avatar`, який ви за бажанням можете передати напряму до Blade-компонента `<x-pulse::user-card>`:

```blade
<x-pulse::user-card :user="{{ $seller->user }}" :stats="{{ $seller->sum }}" />
```

<a name="custom-recorders"></a>
#### Власні рекордери

Автори пакетів можуть захотіти надати класи рекордерів, щоб користувачі могли налаштовувати захоплення даних.

Рекордери реєструються в секції `recorders` конфігураційного файлу `config/pulse.php` застосунку:

```php
[
    // ...
    'recorders' => [
        Acme\Recorders\Deployments::class => [
            // ...
        ],

        // ...
    ],
]
```

Рекордери можуть слухати події, якщо вказати властивість `$listen`. Pulse автоматично зареєструє слухачів і викличе метод `record` рекордера:

```php
<?php

namespace Acme\Recorders;

use Acme\Events\Deployment;
use Illuminate\Support\Facades\Config;
use Laravel\Pulse\Facades\Pulse;

class Deployments
{
    /**
     * The events to listen for.
     *
     * @var array<int, class-string>
     */
    public array $listen = [
        Deployment::class,
    ];

    /**
     * Record the deployment.
     */
    public function record(Deployment $event): void
    {
        $config = Config::get('pulse.recorders.'.static::class);

        Pulse::record(
            // ...
        );
    }
}
```