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 помогает увидеть реальный путь запроса и понять, на каком участке возникла проблема.