OpenTelemetry в Go: как увидеть путь запроса

Иногда API начинает отвечать медленно, но по логам сложно понять причину. Запрос пришёл в сервис. Что произошло дальше?

Например: HTTP → service → PostgreSQL → external API → response

Общее время ответа составило 800 мс. Но на каком этапе ушло это время? Здесь помогают traces из OpenTelemetry. Входящий HTTP-запрос становится одним trace, внутри которого есть отдельные spans:

trace: GET /orders/123

├── HTTP handler 800 ms │ ├── OrderService 760 ms │ ├── PostgreSQL query 120 ms │ └── External API 580 ms │ └── response

По такой схеме сразу видно: проблема не в самом Go-сервисе. Основная задержка появилась во время вызова внешнего API.

В Go OpenTelemetry SDK позволяет автоматически создавать trace для HTTP-запросов, а затем передавать context дальше по цепочке:

func (s *OrderService) Get(ctx context.Context, id int64) (*Order, error) { ctx, span := tracer.Start(ctx, "OrderService.Get") defer span.End()

order, err := s.repo.Get(ctx, id) if err != nil { return nil, err }

return order, nil }

При этом важно не терять context.Context на каждом уровне:

HTTP request ↓ handler ↓ service ↓ repository ↓ DB

Так один trace можно связать с операциями внутри handler, service, repository и базы данных. Если сервис обращается к другому сервису, OpenTelemetry может передать trace context дальше:

API ↓ Order Service ↓ Payment Service ↓ Payment API ↓ PostgreSQL

В результате виден не только один обработчик, а весь путь запроса через систему.

Это уже больше, чем обычный:

logger.Info("request started")

Логи показывают, что произошло.

Метрики помогают понять, как часто это происходит.

Traces показывают, где именно потерялось время в конкретном запросе.

Для микросервисов это особенно полезно. Когда сервисов становится десятки, искать причину задержки только по логам быстро становится сложно. OpenTelemetry в Go помогает увидеть реальный путь запроса и понять, на каком участке возникла проблема.