Slowlog PHP-FPM показує стек викликів запиту в момент, коли він працює довше заданого порогу, — це знімок одного застряглого місця виконання, а не безперервна трасування. Інструменту для читання цього знімка і відділення повільного коду від повільної бази даних у каталозі раніше не було.
Що саме пише slowlog і чого не пише
Якщо запит працює довше request_slowlog_timeout, PHP-FPM один раз робить дамп трасування стека — яка функція і рядок виконувалися на момент знімка. Це не схоже на звичайний error_log: там видно повідомлення після завершення скрипту, а slowlog показує те, що відбувається в реальному часі, поки процес ще живий.
Знімок не містить історії викликів у часі — лише один зріз на момент таймауту. Розбір того, що і як потрапляє в error_log і у вивід фаталів, окремо описано в статті про логи PHP.
Увімкнення slowlog у конфігурації пулу
Директиви задаються в конфігурації пулу, поруч з іншими параметрами PHP-FPM, розібраними в статті про пули й воркери PHP-FPM. request_slowlog_timeout визначає порог, після якого знімається трасування, а slowlog — шлях до файлу.
Порог варто вибирати за очікуваним часом відповіді конкретного ендпоінта: для звичайної сторінки 5 секунд вже підозріло довго, а для фонового важкого звіту той самий порог спрацює на кожному запиті і забʼє лог марними трасуваннями.
Як читати трасування
У записі видно ланцюжок викликів функцій з номерами рядків — зверху найзовнішній виклик, знизу поточна, застрягла функція. Якщо знизу виклик функції роботи з файлами, мережею чи базою даних, найімовірніше скрипт чекає зовнішній ресурс, а не рахує щось процесором.
- Зовнішній HTTP-запит до API без таймауту чи з великим таймаутом
- Запит до бази даних без індексу — характерний ланцюжок викликів PDO чи mysqli
- Цикл з N+1 запитами, де кожна iтерація чекає окрему відповідь від бази
- Регулярний вираз з катастрофічним backtracking на довгому рядку
- Очікування файлового блокування, яке тримає інший процес
Таблиця основних параметрів slowlog
Значення в таблиці — орієнтир для старту, а не універсальний стандарт: порог підбирається за профілем конкретного ендпоінта.
| Параметр | Що робить | Типовий старт |
|---|---|---|
| slowlog | шлях до файлу трасувань | /var/log/php8.3-fpm-slow.log |
| request_slowlog_timeout | порог, після якого пишеться трасування | 5s |
| request_terminate_timeout | примусове завершення застряглого запиту | 30s |
| slowlog_timeout_depth | глибина стека в записі трасування | 128 |
Slowlog проти slow query log MySQL
Якщо трасування впирається у виклик PDO чи mysqli, це ознака повільного запиту до бази, а не повільного PHP-коду. У цьому разі точний діагноз дає slow query log самої бази — увімкнення і розбір описані в статті про MySQL Slow Query Log, де видно сам SQL і кількість просканованих рядків.
Ротація: slowlog росте швидко при низькому порозі на навантаженому сайті, тому файл варто додати в logrotate так само, як звичайні логи Nginx і PHP, інакше він займе все вільне місце на диску.
slowlog = /var/log/php8.3-fpm-slow.log
request_slowlog_timeout = 5s
request_terminate_timeout = 30sЧасті питання
Чи можна тримати slowlog увімкненим постійно в продакшені?
Так, якщо порог вибраний розумно: запис робиться лише коли запит перевищує порог, тому постійно увімкнений slowlog з порогом 5 секунд не навантажує сервер на звичайних швидких запитах.
Чому трасування порожнє чи обривається на першому рядку?
Найчастіше це занадто мале значення slowlog_timeout_depth: воно обмежує глибину стека, і якщо застряглий виклик знаходиться глибше заданої межі, трасування просто обривається.
У трасуванні видна функція curl_exec, що робити?
Це зовнішній HTTP-запит без таймауту чи з великим таймаутом — потрібно додати чи зменшити таймаут самого запиту, а не збільшувати request_slowlog_timeout, який лише приховує симптом.