Привет, Хабр! Меня зовут Александр Белышев. Хочу немного вам рассказать о библиотеке (Laravel Zipkin Tracer), которую я разработал изучая трейсинг в php, возможно кому-то это будет так же интересно, как и мне. О OpenTelemetry я знал что он есть, даже его пощупал, но хотелось чуть с другой стороны изучить предмет и решить его несколько другим способом.
Laravel Zipkin Tracer — это специализированный модуль для Laravel, который обеспечивает автоматический трейсинг HTTP‑запросов, SQL‑запросов и позволяет создавать пользовательские спаны (spans) для интеграции с Zipkin.
Архитектура модуля
Модуль состоит из нескольких ключевых компонентов:
ZipkinTracerProvider — основной провайдер, регистрирующий все сервисы
ZipkinTracerMiddleware — middleware для перехвата HTTP‑запросов
EventSubscriber — подписчик на события Laravel для автоматического трейсинга
DataCollectorService — сервис для сбора и сохранения данных трейсинга
CustomSpanService — сервис для создания пользовательских спанов
SyncDataCommand — команда для синхронизации данных с Zipkin
Общая архитектура системы

Детальная схема сбора данных

Установка и настройка
Требования
PHP ^8.2
Laravel ^10
openzipkin/zipkin ^3.2
Установка
composer require xman12/laravel-zipkin-tracer
Настройка
Добавление провайдера в
app/bootstrap/providers.php:return [ App\Providers\AppServiceProvider::class, ZipkinTracerProvider::class, ];Копирование конфигурации:
php artisan vendor:publish --tag=zipkin-tracerНастройка переменных окружения в
.env:ZIPKIN_TRACER_ENABLE=true ZIPKIN_TRACER_STORAGE_PATH=/path/to/storage/zipkin_tracer ZIPKIN_TRACER_SERVICE_NAME=my-service ZIPKIN_TRACER_ENDPOINT=http://127.0.0.1:9411/api/v2/spansНастройка cron для синхронизации данных:
# Добавить в crontab * * * * * php artisan zipkin-tracer:sync_data
Функциональность
Модуль автоматически отслеживает:
HTTP-запросы
Метод запроса (GET, POST, PUT, DELETE)
URL
Статус код ответа
Размер запроса и ответа
Время выполнения
Исключения
SQL-запросы
Текст SQL‑запроса
Время выполнения
Файл и строка выполнения
Транзакции (begin, commit, rollback)
HTTP-клиент запросы
Исходящие HTTP‑запросы через Laravel HTTP Client
Заголовки запросов
Статус коды ответов
Ошибки соединения
Пользовательские спаны
Модуль позволяет создавать собственные спаны для отслеживания бизнес‑логики:
/** @var CustomSpanService $customSpanService */ $customSpanService = app(CustomSpanService::class); // Простой спан $span = $customSpanService->createSpan('user-registration', function () { // Бизнес-логика регистрации пользователя $user = User::create([ 'name' => 'John Doe', 'email' => 'john@example.com' ]); return [ 'user_id' => $user->id, 'registration_method' => 'email' ]; }); $customSpanService->addSpan($span);
Вложенные спаны
// Дочерние спаны $validationSpan = $customSpanService->createSpan('validate-user-data', function () { // Валидация данных return ['validation_passed' => true]; }); $emailSpan = $customSpanService->createSpan('send-welcome-email', function () { // Отправка приветственного письма return ['email_sent' => true]; }); // Родительский спан с дочерними $mainSpan = $customSpanService->createSpan('user-registration-process', function () { // Основная логика return ['process_completed' => true]; }, [$validationSpan, $emailSpan]); $customSpanService->addSpan($mainSpan);
Процесс сбора данных
Процесс синхронизации с Zipkin



Сравнение с OpenTelemetry
В процессе изучения вопроса, я естественно столкнулся с OpenTelemetry. Я его изучил, пощупал, но как писал выше мне хотелось решить задачу другим методом, чуть менее зависимым и чуть более предсказуемым хотя возможно это не совсем и правильный путь.
Laravel Zipkin Tracer vs OpenTelemetry
Характеристика | Laravel Zipkin Tracer | OpenTelemetry |
|---|---|---|
Специализация | Специально для Laravel + Zipkin | Универсальный стандарт |
Сложность настройки | Простая | Средняя-высокая |
Автоматический трейсинг | ✅ HTTP, SQL, HTTP Client | ✅ Более широкий спектр |
Пользовательские спаны | ✅ Простой API | ✅ Более сложный API |
Производительность | Высокая (минимальные накладные расходы) | Средняя (больше метаданных) |
Интеграция с Laravel | Нативная | Требует дополнительной настройки |
Поддержка стандартов | Zipkin-specific | OpenTelemetry standard |
Экосистема | Ограниченная | Огромная |

Преимущества Laravel Zipkin Tracer
Простота использования
Минимальная конфигурация
Автоматическая интеграция с Laravel
Понятный API для пользовательских спанов
Производительность
Асинхронная отправка данных
Минимальные накладные расходы
Эффективное хранение в файловой системе
Специализация
Оптимизирован для Laravel
Готовая интеграция с Zipkin
Автоматический трейсинг типичных сценариев
Недостатки Laravel Zipkin Tracer
Ограниченная экосистема
Только Zipkin
Меньше инструментов и интеграций
Функциональность
Меньше возможностей по сравнению с OpenTelemetry
Ограниченные возможности для метрик
Стандартизация
Не следует открытым стандартам
Может быть сложнее мигрировать в будущем
Практические примеры
Пример 1: Трейсинг API-эндпоинта
// UserController.php class UserController extends Controller { public function show($id) { /** @var CustomSpanService $customSpanService */ $customSpanService = app(CustomSpanService::class); $user = User::with(['profile', 'posts'])->findOrFail($id); $span = $customSpanService->createSpan('get-user-profile', function () use ($user) { return [ 'user_id' => $user->id, 'profile_complete' => $user->profile ? true : false, 'posts_count' => $user->posts->count() ]; }); $customSpanService->addSpan($span); return response()->json($user); } }
Пример 2: Трейсинг внешних API-вызовов
// ExternalApiService.php class ExternalApiService { public function fetchUserData($userId) { /** @var CustomSpanService $customSpanService */ $customSpanService = app(CustomSpanService::class); $span = $customSpanService->createSpan('external-api-call', function () use ($userId) { // Laravel HTTP Client автоматически трейсится $response = Http::get("https://api.external.com/users/{$userId}"); return [ 'external_user_id' => $userId, 'response_status' => $response->status(), 'response_size' => strlen($response->body()) ]; }); $customSpanService->addSpan($span); return $response->json(); } }
Пример 3: Трейсинг сложной бизнес-логики
// OrderService.php class OrderService { public function processOrder($orderData) { /** @var CustomSpanService $customSpanService */ $customSpanService = app(CustomSpanService::class); // Валидация заказа $validationSpan = $customSpanService->createSpan('validate-order', function () use ($orderData) { $validator = Validator::make($orderData, [ 'items' => 'required|array', 'customer_id' => 'required|exists:customers,id' ]); if ($validator->fails()) { throw new ValidationException($validator); } return ['validation_passed' => true]; }); // Проверка наличия товаров $inventorySpan = $customSpanService->createSpan('check-inventory', function () use ($orderData) { foreach ($orderData['items'] as $item) { $product = Product::find($item['product_id']); if ($product->stock < $item['quantity']) { throw new InsufficientStockException(); } } return ['inventory_available' => true]; }); // Создание заказа $orderSpan = $customSpanService->createSpan('create-order', function () use ($orderData) { DB::transaction(function () use ($orderData) { $order = Order::create([ 'customer_id' => $orderData['customer_id'], 'total_amount' => $this->calculateTotal($orderData['items']) ]); foreach ($orderData['items'] as $item) { $order->items()->create($item); } }); return ['order_created' => true]; }); // Основной спан $mainSpan = $customSpanService->createSpan('process-order-complete', function () { return ['order_processed' => true]; }, [$validationSpan, $inventorySpan, $orderSpan]); $customSpanService->addSpan($mainSpan); } }
Мониторинг и отладка
После настройки синхронизации данные будут доступны в веб‑интерфейсе Zipkin:
Откройте Zipkin UI (обычно http://localhost:9411)
Выберите сервис из выпадающего списка
Настройте временной диапазон
Просматривайте трейсы и спаны

В Zipkin вы сможете увидеть:
Время выполнения каждого спана
Зависимости между сервисами
Узкие места в производительности
Ошибки и исключения
SQL-запросы с временем выполнения
Типичные сценарии отладки
Медленные запросы: Анализ времени выполнения SQL-запросов
Ошибки внешних API: Просмотр HTTP-клиент запросов
Проблемы бизнес-логики: Анализ пользовательских спанов
Проблемы производительности: Выявление узких мест в цепочке запросов
Итоги
Laravel Zipkin Tracer вам подойдет если вам нужно:
У вас Laravel‑приложение
Используется Zipkin как система трейсинга
Простоту интеграции с минимальными изменениями в коде (не нужно устанавливать дополнительные расширения)
Автоматический трейсинг типичных сценариев
Гибкость для создания пользовательских спанов
Производительность с асинхронной отправкой данных
❌ Не рекомендуется, если:
Нужна поддержка множественных систем трейсинга
Требуется полная совместимость с OpenTelemetry
Необходимы продвинутые возможности метрик
Планируется миграция на другие системы мониторинга
Альтернативы
Для более сложных сценариев рассмотрите:
OpenTelemetry PHP — универсальный стандарт
Jaeger — альтернативная система трейсинга
DataDog APM — коммерческое решение с расширенными возможностями
