Observability: логи, метрики й трейси з OpenTelemetry
Чим observability відрізняється від моніторингу, як зв'язати логи, метрики і трейси одним trace_id і як підключити OpenTelemetry до сервісу без переписування коду.
Моніторинг відповідає на питання, які ви знали заздалегідь: «чи не забагато помилок?», «чи не закінчується диск?». Observability — здатність відповісти на питання, яких ви не передбачили: «чому запити користувачів з Польщі через мобільний застосунок повільні лише після 18:00?».
Три сигнали
| Сигнал | Що дає | Слабке місце |
|---|---|---|
| Метрики | Агреговані числа в часі, дешеві, швидкі | Не показують окремий запит |
| Логи | Деталі подій | Дорогі в обсязі, важко зв'язати між сервісами |
| Трейси | Шлях одного запиту через усі сервіси з таймінгами | Потрібна інструментація, семплінг |
Сила — у зв'язку між ними: з графіка p99 → до трейсів повільних запитів → до логів конкретного запиту. Ключ до цього — спільний trace_id.
Що таке трейс
Трейс — це дерево спанів. Спан — одна операція: вхідний HTTP-запит, запит до БД, виклик іншого сервісу. Кожен має початок, тривалість, атрибути і посилання на батьківський спан.
POST /checkout 420 ms
├─ auth.verify_token 8 ms
├─ SELECT cart_items ... 35 ms
├─ POST payments-service /charge 310 ms
│ ├─ fraud.check 240 ms ← ось де час
│ └─ INSERT payments ... 12 ms
└─ publish order.created 6 msМіж сервісами контекст трейсу передається HTTP-заголовком traceparent (стандарт W3C Trace Context).
OpenTelemetry
OpenTelemetry (OTel) — відкритий стандарт і набір SDK для збору телеметрії, незалежний від постачальника. Ви інструментуєте код один раз, а бекенд (Jaeger, Tempo, Grafana, Datadog, Honeycomb…) можна змінити без переписування застосунку.
Автоінструментація Python-сервісу
pip install opentelemetry-distro opentelemetry-exporter-otlp
opentelemetry-bootstrap -a install # встановить інструментації для знайдених бібліотек
export OTEL_SERVICE_NAME=orders-api
export OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
export OTEL_TRACES_SAMPLER=parentbased_traceidratio
export OTEL_TRACES_SAMPLER_ARG=0.1 # зберігати 10% трейсів
opentelemetry-instrument uvicorn app.main:app --host 0.0.0.0Без змін у коді з'являться спани для вхідних HTTP-запитів, запитів до PostgreSQL, Redis, вихідних HTTP-викликів.
Власні спани для бізнес-логіки
from opentelemetry import trace
tracer = trace.get_tracer("orders")
def apply_discount(order, code):
with tracer.start_as_current_span("apply_discount") as span:
span.set_attribute("discount.code", code)
span.set_attribute("order.items", len(order.items))
...Collector — посередник, якого варто мати
Застосунки надсилають телеметрію в OTel Collector, а він уже — у бекенди. Це дає:
- одну точку налаштування замість конфігів у кожному сервісі;
- семплінг, фільтрацію, видалення чутливих даних;
- можливість змінити бекенд без передеплою застосунків.
# otel-collector.yaml (спрощено)
receivers:
otlp:
protocols: { grpc: {}, http: {} }
processors:
batch: {}
attributes/scrub:
actions:
- key: http.request.header.authorization
action: delete
exporters:
otlp/tempo:
endpoint: tempo:4317
tls: { insecure: true }
service:
pipelines:
traces:
receivers: [otlp]
processors: [attributes/scrub, batch]
exporters: [otlp/tempo]Структуровані логи з trace_id
{"ts":"2026-08-29T15:31:02.118Z","level":"error","service":"orders-api",
"msg":"payment declined","order_id":88412,"trace_id":"4bf92f3577b34da6a3ce929d0e0e4736"}- JSON замість рядків — логи можна фільтрувати за полями, а не регулярками;
- trace_id у кожному записі — з трейсу в Grafana одним кліком відкриваються логи цього запиту;
- рівні логування з сенсом:
error— щось зламалось і потрібна увага, а не «користувач ввів неправильний пароль».
ОбережноУ логи й атрибути спанів не повинні потрапляти паролі, токени, номери карток і персональні дані. Фільтруйте їх у коді і додатково в Collector.
Семплінг
Зберігати 100% трейсів при великому трафіку дорого. Варіанти:
- head sampling — рішення на початку запиту (наприклад, 10%); просто, але можна пропустити рідкісні помилки;
- tail sampling у Collector — рішення після завершення трейсу: зберегти всі трейси з помилками і повільні, а з успішних — лише частку.
Як трейс «знає», що виклик payments-service належить до того самого запиту /checkout?
Сервіс-відправник додає до вихідного HTTP-запиту заголовок traceparent з ідентифікатором трейсу і батьківського спану. SDK OpenTelemetry в отримувачі читає цей заголовок і створює свої спани як дочірні в тому самому трейсі.
Збережіть статтю собі
Увійдіть, щоб імпортувати її у власні нотатки, відмічати вивчене, ставити лайки й питати спільноту. Реєстрація безкоштовна: вхід через Google займає кілька секунд.
Увійти через Google Інші способи входу