Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Middle: питання на співбесіді з теми «Налагодження»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

3 питання

Логування в Laravel побудоване на Monolog; канали налаштовуються в config/logging.php.

Log::info('Замовлення створено', ['id' => $order->id]);
Log::channel('slack')->critical('Платіж не пройшов');

Типи каналів: single (один файл), daily (ротація по днях), slack, papertrail, stderr, а також stack - який пише одразу в кілька:

'stack' => ['driver' => 'stack', 'channels' => ['daily', 'slack']],

Практики: рівні (debug…emergency), структуроване логування з контекстом, маскування PII, окремий канал для критичних подій у Slack/Sentry. У проді LOG_LEVEL зазвичай warning+.

Докладніше в документації: Логування

Подивитися SQL одного запиту без виконання:

User::where('active', true)->orderBy('name')->toSql();
// select * from "users" where "active" = ? order by "name" asc

User::where('active', true)->toRawSql();
// select * from "users" where "active" = 1 ...   - з підставленими значеннями

Вивести й продовжити чи зупинитися:

User::where('active', true)->dumpRawSql()->get();  // вивести й виконати
User::where('active', true)->ddRawSql();           // вивести й зупинити

toRawSql() зручний, щоб скопіювати запит у консоль бази й запустити EXPLAIN. Але для реального виконання Laravel завжди використовує підготовлені запити з окремими параметрами - підставлені значення лише для читання людиною.

Усі запити за запит чи команду:

DB::enableQueryLog();
// ... код ...
dump(DB::getQueryLog());   // SQL, параметри й час кожного

Слухач запитів - для логування в розробці:

// AppServiceProvider::boot()
if (app()->isLocal()) {
    DB::listen(function (QueryExecuted $query): void {
        Log::debug($query->toRawSql(), ['ms' => $query->time]);
    });
}

Сповіщення про повільну роботу з базою за весь запит:

DB::whenQueryingForLongerThan(500, function (Connection $connection, QueryExecuted $event): void {
    Log::warning('Багато часу в базі', ['connection' => $connection->getName()]);
});

Як знайти проблеми системно:

  • N+1: Model::preventLazyLoading(! app()->isProduction()) - виняток при лінивому завантаженні зв'язку в циклі;
  • Laravel Debugbar чи Telescope - список запитів сторінки з дублікатами й часом;
  • сторінка помилки Laravel також показує виконані запити;
  • на продакшені - журнал повільних запитів бази (pg_stat_statements, slow query log), а не логування кожного запиту.

Пастка: enableQueryLog у довгому процесі (воркер, команда з мільйоном записів) накопичує всі запити в пам'яті - вмикайте його лише на час налагодження.

Докладніше в документації: Налагодження запитів

Класичний спосіб - tail -f storage/logs/laravel.log. Він працює лише з файловим каналом, показує сирий текст разом з багаторядковими стеками, і його незручно фільтрувати.

Laravel Pail - Artisan-команда, яка показує записи логів у реальному часі в зручному вигляді:

composer require --dev laravel/pail
php artisan pail

Головна перевага: Pail отримує записи напряму від застосунку, тому працює з будь-яким драйвером логів - навіть якщо записи йдуть у Sentry, Papertrail чи stderr і локального файлу немає.

Фільтри:

php artisan pail --filter="QueryException"   # тип винятку, файл, текст
php artisan pail --message="Payment"         # лише за текстом повідомлення
php artisan pail --level=error               # рівень
php artisan pail --user=42                   # записи, зроблені в запитах користувача 42
php artisan pail -v                          # без скорочень
php artisan pail -vv                         # зі стеком викликів

Фільтр за користувачем особливо корисний: можна відтворити проблему під потрібним обліковим записом і бачити лише свої записи серед загального потоку.

Типові сценарії:

  • налагодження черги чи планувальника, де немає сторінки помилки: запустити pail поруч з воркером;
  • розробка інтеграції з вебхуками - бачити, що прийшло й що записано, одразу;
  • composer run dev у новому Laravel-проєкті запускає Pail разом із сервером, чергою й Vite.

Обмеження:

  • потрібне розширення PCNTL - на Windows лише через WSL;
  • Pail показує записи, що з'являються після запуску, - історію дивляться в логах;
  • це інструмент розробника: на продакшені для пошуку причин збоїв потрібне централізоване сховище логів з пошуком і зберіганням, а не перегляд у терміналі.

Щоб логи були корисними в Pail: структурований контекст замість склеювання рядків - Log::info('Order paid', ['order_id' => $order->id]).

Докладніше в документації: Перегляд логів через Pail