0% прочитано

Correlation ID: як простежити один запит через систему

Один запит може пройти через middleware, контролер, прикладну логіку та базу даних. Показую, як один ідентифікатор допомагає зв’язати відповідь API з внутрішньою діагностикою.

2 жовтня 2026 р. 7 хв читанняЛаравель

Коли API-запит завершується помилкою, повідомлення "щось пішло не так" майже нічого не дає для діагностики.

У той самий момент система може обробляти сотні інших запитів. У журналах можуть бути десятки схожих помилок. І потрібно зрозуміти, який саме запис стосується відповіді, яку отримав конкретний клієнт.

Для цього я використовую Correlation ID - ідентифікатор одного запиту, який проходить разом із ним через систему.

Схема проста: прийняти коректний ідентифікатор від клієнта або створити свій, зберегти його в контексті запиту і повернути у відповіді.

Correlation ID не пояснює причину помилки. Він дозволяє точно знайти той запит, для якого цю причину потрібно дослідити.

Один запит отримує один ідентифікатор

Один ідентифікатор проходить через увесь запит
HTTP request    |    vприйняти або створити ID    |    vmiddleware    |    vконтролер    |    vприкладна логіка    |    vдіагностика / логи

Мені важливо, щоб ідентифікатор з’являвся якомога ближче до входу в API.

Тоді той самий номер можна використовувати незалежно від того, де саме завершиться обробка: успішною відповіддю, перевіркою вхідних даних або внутрішньою помилкою.

У Laravel для цього добре підходить middleware.

Якщо клієнт передав коректний ID, я можу його продовжити

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

Якщо попередня система вже створила ідентифікатор, корисно не розривати цей ланцюжок без причини.

Але я не приймаю довільний заголовок без перевірки. Значення має відповідати дозволеному формату та розумному обмеженню довжини.

Якщо значення відсутнє або не проходить перевірку, система створює власний ідентифікатор.

PHP - Прийняти коректний ID або створити новий
private function resolveCorrelationId(?string $candidate): string{    if (        $candidate !== null        && $this->isAcceptableCorrelationId($candidate)    ) {        return $candidate;    }     return (string) Str::uuid();}
Зовнішній Correlation ID все одно є вхідними даними. Я перевіряю його так само, як інші значення, що приходять ззовні.

Middleware додає ID до контексту запиту

PHP - Спрощений middleware для Correlation ID
final class CorrelationIdMiddleware{    private const HEADER = 'X-Correlation-ID';     public function handle(        Request $request,        Closure $next,    ): Response {        $correlationId = $this->resolveCorrelationId(            $request->header(self::HEADER),        );         $request->attributes->set(            'correlation_id',            $correlationId,        );

Middleware виконує три невеликі дії.

  1. Читає X-Correlation-ID або створює новий.
  2. Кладе значення в атрибути поточного запиту.
  3. Повертає той самий ID у заголовку відповіді.

Після цього іншим частинам застосунку не потрібно повторно вирішувати, звідки взявся ідентифікатор.

Я повертаю той самий ID клієнту

Узагальнений приклад відповіді
HTTP/1.1 409 ConflictX-Correlation-ID: 8d29b96f-... {    "code": "request_conflict",    "message": "The request cannot be completed.",    "correlationId": "8d29b96f-..."}

Для клієнта цей ID особливо корисний при помилці.

Замість повідомлення "у мене був 500 приблизно о 14:20" можна передати конкретний ідентифікатор запиту.

На внутрішній стороні той самий номер використовується для пошуку технічної інформації.

Я також люблю повертати значення в HTTP-заголовку, тому що тоді воно доступне незалежно від конкретної структури тіла відповіді.

Той самий ID додаю до діагностичного контексту

PHP - Ідентифікатор у внутрішній діагностиці
Log::error('Request processing failed', [    'correlation_id' => $request->attributes->get(        'correlation_id',    ),    'exception' => $exception::class,]);

Сам ідентифікатор не замінює нормальну діагностику.

Він лише дає спільний ключ, за яким можна пов’язати різні записи, створені під час обробки одного запиту.

Залежно від системи це можуть бути звичайні журнали застосунку, error tracker, записи про зовнішні виклики або інші технічні події.

Важливо, щоб потрібні записи мали один і той самий ідентифікатор.

Correlation ID особливо корисний у безпечних API-помилках

PHP - Безпечна зовнішня помилка
return response()->json(    [        'code' => 'request_conflict',        'message' => 'The request cannot be completed.',        'correlationId' => $request->attributes->get(            'correlation_id',        ),    ],    409,);

Публічна помилка не повинна містити stack trace, внутрішній SQL або текст довільного винятку лише для того, щоб розробнику було легше знайти причину.

Клієнту можна повернути стабільний і безпечний опис, а технічні подробиці залишити всередині.

Ідентифікатор запиту з’єднує ці дві сторони.

Саме тому цей механізм добре доповнює окремий контракт помилок API.

Correlation ID не є ідентичністю або секретом

Ідентифікатор запиту має дуже вузьке призначення: допомогти простежити обробку одного запиту.

Я не використовую його як:

  • автентифікацію;
  • дозвіл на виконання операції;
  • секрет;
  • ідентифікатор користувача або бізнес-сутності;
  • заміну ключа ідемпотентності.

Те, що значення унікальне, ще не означає, що воно підходить для всіх задач, де потрібен ідентифікатор.

Не кожен клас повинен знати про HTTP-заголовок

Ще одна межа, яку я намагаюся зберігати: внутрішньому коду не обов’язково знати, що зовні значення прийшло саме через X-Correlation-ID.

HTTP-заголовок належить транспортному рівню.

Усередині достатньо мати вже визначений ідентифікатор у контексті поточного запиту або передавати його туди, де він справді потрібен.

Так формат зовнішнього API не починає проникати в кожен сервіс і кожен клас.

Один ID стає ще кориснішим між кількома сервісами

Той самий ID проходить через кілька систем
Client   |   | ID: abc-123   vService A   |   | ID: abc-123   vService B   |   | ID: abc-123   vService C

У межах одного Laravel-застосунку ідентифікатор уже корисний.

Але його цінність ще більше зростає, коли один вхідний запит породжує звернення до інших сервісів.

Якщо наступний сервіс підтримує таку саму домовленість, ідентифікатор можна передати далі.

Тоді під час розслідування видно не набір незалежних помилок у різних системах, а один логічний ланцюжок.

Що я перевіряю при додаванні Correlation ID

Для такого механізму я перевіряю кілька речей:

  • ID створюється на вході, а не лише там, де вже сталася помилка.
  • Зовнішнє значення перевіряється перед використанням.
  • Якщо значення немає, система створює власне.
  • Той самий ID доступний під час усієї обробки запиту.
  • Він повертається клієнту.
  • Він присутній у потрібному діагностичному контексті.
  • Він не використовується як секрет, авторизація або бізнес-ідентичність.

Маленьке поле, яке дуже спрощує діагностику

Correlation ID не вирішує помилки і не замінює журнали чи спостережуваність.

Його задача значно простіша: дати всім записам одного запиту спільний орієнтир.

Клієнт отримує ідентифікатор у відповіді. Система використовує те саме значення під час внутрішньої діагностики. Якщо запит проходить через кілька сервісів, цей зв’язок можна продовжити далі.

Для мене це один із тих невеликих технічних механізмів, які майже непомітні під час нормальної роботи, але дуже цінні в момент, коли потрібно знайти один конкретний запит серед тисяч інших.

Correlation ID не говорить, що сталося. Він точно говорить, який запит потрібно дослідити.