core code helper

Observability: логи, метрики й трейси з OpenTelemetry

Чим observability відрізняється від моніторингу, як зв'язати логи, метрики і трейси одним trace_id і як підключити OpenTelemetry до сервісу без переписування коду.

0 імпортували Імпортувати собі

Моніторинг відповідає на питання, які ви знали заздалегідь: «чи не забагато помилок?», «чи не закінчується диск?». 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 Інші способи входу