> For the complete documentation index, see [llms.txt](https://docs.expirenza.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.expirenza.com/api/scheme/open-telemetry.md).

# Підтримка трасування запитів (OpenTelemetry-підхід)

## 1. Загальна схема взаємодії

Інтеграція працює за наступною схемою:

1. Сервіси Expirenza надсилають інтегратору команду через **WebSocket**.
2. Інтеграція виконує необхідні дії (свій бізнес-процес, звернення до внутрішніх сервісів тощо).
3. Інтеграція повертає результат у Expirenza через **HTTP callback**.
4. Увесь шлях запиту має бути пов’язаний одним і тим самим `traceId`.

Логічний ланцюжок виглядає так:

> Expirenza (internal service)\
> → Expirenza External Connector\
> → API інтегратора\
> → Expirenza External Connector\
> → Expirenza (internal service)

На кожному новому сервісі створюється **новий `spanId`**, при цьому:

* `traceId` залишається незмінним протягом усього життєвого циклу запиту;
* `parent-span-id` вказує, з якого span прийшов запит.

***

## 2. Структура повідомлень у WebSocket

Усі WebSocket-повідомлення від Expirenza до інтегратора мають службове поле `__headers__`.

Приклад вхідного повідомлення:

```json
{
    "rID" : "2021-03-13 00:32:04.942046#UP57RxE",
    "operation" : "categoriesInfo",
    "__headers__": {
    "traceId": "c0a8017f6f2c4d98bd70a35c90f1f01",
    "spanId": "7b9a3d3c4e2f1a90"
    }
}
```

#### 2.1. Поля в `__headers__`

* `traceId`
  * Унікальний ідентифікатор всього запиту (end-to-end).
  * Є **обов’язковим** до збереження та передачі назад у відповідь (HTTP callback).
  * Інтеграція не повинна змінювати формат чи значення `traceId`. Сприймайте його як “чорну скриньку”.
* `spanId`
  * Ідентифікатор поточного етапу (span) усередині загального запиту.
  * Для інтеграції він виконує роль **`parent-span-id`** – тобто span, від якого “відгалужується” робота інтеграції.
  * Обробка `spanId` є **рекомендованою, але не обов’язковою** (див. розділ 4).

***

## 3. Обов’язкові вимоги до інтеграції

#### 3.1. Збереження `traceId` в контексті

Після отримання WebSocket-повідомлення інтеграція повинна:

1. Прочитати `traceId` з `message.__headers__.['traceId']`.
2. Зберегти його в контексті обробки запиту (thread context, request-scoped context, MDC/лог-контекст тощо).
3. Використовувати цей `traceId` при всіх логуваннях, що стосуються даного запиту.

#### 3.2. Передача `traceId` в HTTP callback

При формуванні HTTP-відповіді (callback) інтеграція **обов’язково** має додати заголовок:

```
traceId: <значення traceId з WebSocket-повідомлення>
```

**Приклад HTTP callback:**

```json5
POST /expirenza/callback/payment HTTP/1.1
Host: api.expirenza.example
Content-Type: application/json
traceId: c0a8017f-6f2c-4d98-bd70-3a35c90f1f01

{
  "status": "SUCCESS",
  "orderId": "ORD-12345",
  "transactionId": "TX-98765"
}
```

Це дозволяє Expirenza “зшити” логи WebSocket-команди, внутрішніх сервісів та відповіді інтеграції в один наскрізний трейс.

{% hint style="warning" %}
Важливо: **передача `traceId` у callback – обов’язкова вимога**.\
Якщо `traceId` буде відсутній або змінений, трасування буде порушене.
{% endhint %}

***

## 4. Рекомендована (опційна) підтримка `spanId` та `parent-span-id`

Підтримка `spanId`/`parent-span-id` на стороні інтеграції **рекомендована**, але **не є обов’язковою**.\
Вона потрібна для більш детального трасування всередині системи інтеграції та між сервісами.

#### 4.1. Що рекомендується робити

1. Прочитати вхідний:
   * `traceId`
   * `spanId` (як **`parent-span-id`** для інтеграції)
2. Створити \*новий \* **`spanId`** для роботи інтеграції (наприклад, `spanId` інтеграції):
   * `parent-span-id` = вхідний `spanId` з WebSocket.
   * `spanId` = нове згенероване значення.
3. Якщо інтеграція викликає свої внутрішні сервіси:
   * передавати:
     * той самий `traceId`,
     * `spanId` (власний) (внутрішній сервіс запише його як `parent-span-id`)
     * Внутрішній сервіс сгенерує новий `spanId` для кожного дочірнього виклику.
4. При поверненні відповіді в Expirenza (HTTP callback) можна (опційно) передавати:

```jsonl
traceId: <обов'язково>
spanId: <span-id інтегратора з якого було здійснено http виклик>
```

Ще раз: **для Expirenza обов’язковим є тільки `traceId`**.\
Передача/ланцюжок `spanId` та `parent-span-id` – опція, яка дозволить глибше аналізувати ланцюжок викликів, якщо інтегратор цього бажає.&#x20;

***

## 5. Навіщо це потрібно інтеграції

Підтримка `traceId` (мінімально) та `spanId` (опційно) дає інтеграції такі переваги:

1. **Швидкий пошук інцидентів**
   * Можна отримати `traceId` від Expirenza (наприклад, з технічного запиту) і швидко знайти всі пов’язані логи та виклики у своїй системі.
2. **Кореляція логів між системами**
   * Expirenza та інтеграції дивляться на один і той самий `traceId`, що спрощує спільну діагностику.
3. **Глибинний аналіз продуктивності** (якщо використовуєте `spanId`)
   * Можна будувати детальні діаграми: скільки часу зайняла обробка в інтеграції, скільки – у внутрішніх сервісах інтеграції, де “вузьке місце”.
4. **Сумісність із OpenTelemetry та APM-системами**
   * Якщо інтеграція вже використовує OpenTelemetry, `traceId`, `spanId` та `parent-span-id` можна напряму мапити на відповідні сутності (trace/span/parent span).

***

## 6. Діаграма проходження запиту (послідовність)

{% @mermaid/diagram content="sequenceDiagram
participant IS as Expirenza Internal Service
participant EC as Expirenza External Connector
participant INT as Integrator API

```
Note over IS,INT: traceId = T1 (незмінний протягом усього життєвого циклу)

IS->>EC: Запит на зовнішній виклик (traceId=T1, spanId=S1)
EC->>INT: WebSocket повідомлення (traceId=T1, spanId=S2)

Note over INT: Інтегратор зберігає traceId=T1,<br/>spanId=S2 як parent-span-id,<br/>генерує власний spanId S3 (опційно)

INT->>INT: Внутрішня обробка (traceId=T1, spanId=S3, parent-span-id=S2)
INT-->>EC: HTTP callback (traceId=T1, spanId=S3)
EC-->>IS: Результат обробки (traceId=T1, spanId=S4, parent-span-id=S3)" %}
```

{% hint style="info" %}
Якщо інтеграція не реалізує `spanId`/`parent-span-id`, ви все одно повинні зберігати і повертати **`traceId`** – тоді всі вузли будуть пов’язані хоча б на рівні трейсів.
{% endhint %}

***

## 7. Підсумок вимог

**Обов’язково для інтеграції:**

1. Прочитати `traceId` із WebSocket-повідомлення (`__headers__.traceId`).
2. Зберігати `traceId` в контексті обробки запиту.
3. Логувати `traceId` для всіх дій у межах одного запиту.
4. Передавати `traceId` у HTTP callback як заголовок `traceId`.

**Опційно (рекомендовано):**

1. Використовувати `spanId` із WebSocket-повідомлення як `parent-span-id`.
2. Генерувати власні `spanId` для операцій інтеграції.
3. Передавати `spanId` у HTTP callback.
4. Інтегрувати цю схему з OpenTelemetry / APM системами для розширеної візуалізації трейсів.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.expirenza.com/api/scheme/open-telemetry.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
