Привет, Хабр! Меня зовут Александр Белышев. Хочу немного вам рассказать о библиотеке (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 — коммерческое решение с расширенными возможностями