Clockwork — отладочная панель для PHP

Clockwork – это библиотека и расширение для браузера предоставляющие удобный интерфейс отладки производительности PHP кода.

Расскажу про свой опыт использования и сделаю небольшое сравнение с альтернативами.

Как это работает?

Сначала устанавливаем библиотеку Clockwork с помощью composer в текущий проект: composer require itsgoingd/clockwork

Затем инициализируем где-то в начале жизненного цикла нашего приложения. Есть готовые интеграции для популярных фреймворков: Laravel, Lumen, Slim, Symfony.

Но ничто не мешает использовать эту библиотеку и с любым произвольным PHP кодом. Я, например, подключал к самописному проекту.

В процессе работы нашего PHP кода библиотека Clockwork может собирать метрики. Например, запоминает все SQL вызовы и время их выполнения, накапливает информацию об использованных шаблонах, о текущей сессии и пользователе, о маршруте, максимальное использование памяти (с помощью функции memory_get_peak_usage), может собирать какие-то отладочные логи.

Если интегрируемся в Laravel приложение, то в комплекте идёт ClockworkServiceProvider, который подписывается на все основные события Laravel: события работы с базой через Eloquent, события composing для шаблонов, перехватывает работу с кэшем, с отправкой нотификаций, с задачами в очереди и т.п.

Есть также интеграция с Doctrine, Twig, SwiftMailer, Monolog, Guzzle.

Если же нужно подключить Clockwork к какому-то самописному фреймворку, никакой магии нет, придётся самому в нужных точках приложения вызывать методы Clockwork типа «зарегистрируй этот SQL запрос» или «запиши такую-то отладочную информацию в лог» или «только что произошел рендер какого-то шаблона, вот подробности, запиши их» и т.п.

Вся собранная информация накапливается во внутренних массивах библиотеки Clockwork.

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

Наконец, перед отправкой ответа на клиент в HTTP заголовки ответа добавляется специальный заголовок X-Clockwork-Id, содержащий уникальный идентификатор текущего запроса — он указывает на только что записанную на диск метаинформацию.

Видя HTTP заголовок X-Clockwork-Id, браузерное расширение Clockwork обращается к бэкенду за сохранённой на диск метаинформацией. Чтобы бэкенд смог отдать эту метаинформацию по ID, в нашем приложении должен быть зарегистрировать специальный роут обрабатывающий запросы по адресу __clockwork. Если мы используем интеграцию с Laravel, то такой роут регистрируется автоматически с помощью ClockworkServiceProvider. Если же это самописное приложение, то нужно не забыть написать обработку запросов на этот специальный url, что делается достаточно просто.

Также Clockwork умеет собирать клиентские метрики и так называемые Web Vitals, но эти возможности я пока не исследовал.

Безопасность.

Естественно, на production не рекомендуется включать Clockwork по соображениям безопасности. Впрочем, из коробки предоставляются механизмы авторизации, так что доступ к метрикам можно закрыть за паролем или реализовать собственную стратегию проверки прав.

Мой опыт.

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

С точки зрения API библиотеки не скажу, что всё идеально. В документации описаны не все публичные методы, нужно читать исходный код библиотеки, очень помогло изучение кода интеграции с Laravel.

Сами исходники несколько запутанные и, к сожалению, пестрят магическими методами __call, __callStatic и динамическими вызовами $method(…$args), из-за этого при изучении сложно навигироваться по коду в PhpStorm и не работает автокомплит. Тут не помешали бы PhpDoc блоки с описанием всех возможных виртуальных методов.

В процессе нашел баг с фильтрацией входящих запросов по url. В библиотеке есть настройка, с помощью которой можно отключить сбор метрик на определённых адресах, либо наоборот, задать белый список адресов. Я хотел починить этот баг и отправить Pull Request, но обнаружил, что в проекте вообще нет тестов и я не могу подкрепить свой фикс парочкой примеров и регрессионными тестами! Пришлось отправить Pull Request без тестов.

В целом ощущение от культуры кода в этом проекте осталось так себе, однако, библиотека работает, решает свою задачу и я очень доволен находкой!

Альтернативы.

Для измерения похожих метрик выполнения кода на production, в том числе для анализа SQL запросов, я уже давно использую Newrelic. Но в локальной разработке и отладке «здесь и сейчас» Newrelic не подходит (либо я не знаю, как организовать этот процесс).

Для более тонкого изучения производительности конкретной страницы, конкретного скрипта, я обычно использую Blackfire. Но с ним не так удобно, как с Laravel Debugbar или Clockwork: во-первых, при использовании Blackfire рекомендуется отключать Xdebug, потому что при подключённом расширении Xdebug, пусть даже без autostart, все метрики куда-то уплывают и не показывают реальной картины. Во-вторых, с Blackfire не удобно отлаживать ajax запросы. Кстати, про Blackfire у меня был отдельный выпуск Пятиминуки PHP, послушайте: https://5minphp.ru/episode22/

Для локальной профилировки в суровом стиле можно использовать Xdebug profiler и какую-нибудь программу визуализации. Я, например, предпочитаю открывать профили непосредственно в PhpStorm. Но это профилирование только самих PHP функций, нет возможности расставить метки на некоем timeline или собрать лог SQL запросов. И визуализация так себе. Если есть возможность использовать Blackfire, я предпочитаю Blackfire, а не Xdebug profiler. Кстати, браузерное расширение Clockwork умеет визуализировать данные собранные с помощью Xdebug profiler, но я пока не пробовал.

Наконец, к популярным фреймворкам уже есть готовые Debugbars, хорошо интегрированные в инфраструктуру конкретного фреймворка. По умолчанию это похоже на идеальный вариант. Но эти панели рисуются с помощью JavaScript поверх текущей страницы и могут накосячить с вёрсткой или как-то иначе конфликтовать с фронтендом. В моём же случае, когда надо было подключиться к самописному фреймворку, Clockwork оказался весьма удачным выбором!