Сразу хотел бы обозначить, что в данной статье не стоит цели рассказать обо всех указанных в заголовке технологиях, а скорее просто how to инструкция как настроить это все у себя в проекте. Причина по которой я сел писать этот пост - когда мне было нужно я не смог найти ничего подобного (возможно, как всегда, плохо искал). Так же во многих гайдах для работы с Jaeger использовали старую библиотеку от uber, а сейчас уже советуют отказываться от нее в пользу opentelementry клиента. Еще я толком не cмог найти информации как прокидывать trace-id через context между сервисами. В данной статье я пошагово опишу как настроить grpc сервер, как подключать grpc сервисы между собой, как подключить tracing и в конце как сделать чтобы tracing был внутри одной сессии если запросы происходят по цепочке от сервиса к сервису. Сгенерируем файлы для golang, чтобы они лежали рядом с proto файлом Теперь начнем реализацию сервера. Для начала откроем TCP сокет на порту 9000 Создадим grpc сервер Для того, чтобы удобно было общаться с сервером и можно было посмотреть список всех доступных команд, подключим reflect Создадим структуру и реализуем метод описанный в proto файле Зарегистрируем объект структуры в grpc сервере Запускаем сервер на прослушивание сокета  Запустим сервер и проверим ответ Чтобы у нас был не один сервис, а они общались между собой реализуем еще один. Скопируем файлы относящиеся к серверу и назовем их клиент. Так выглядит proto файл pkg/client/client.proto Переименуем объекты с Server в имени на Client, изменим логику в API, чтобы происходил запрос к серверу.  Запустим и проверим Теперь рассмотрим как в grpc работают заголовки и как их можно передавать между сервисами. Когда мы делаем вызов, мы можем передать параметры через заголовки, при помощи флага -H Чтобы получить доступ к заголовкам внутри метода нужно вызвать функцию md - это map слайсов. Извлечем значение из заголовка, если оно есть Таким образом мы можем извлекать значения из заголовка входящего запроса. Теперь рассмотрим как указать значение заголовка при вызове другого сервиса. А дальше мы просто передаем новый ctx при вызове к сервису и он сможет так же на входе получить значение. Для того, чтобы локально развернуть jaeger можно использовать готовый docker образ На порту 16686 работает web интерфейс, а на порту 14268 сидит collector, который будет принимать сообщения от сервисов о событиях. Добавим такой код инициализации провайдера jaeger в main.go файлы. На вход эта функция принимает http адрес до коллектора и название сервиса Добавим код инициализации трейсера в server и client в начало main() функций Так же добавим отправку событий при вызове API метода  У нас почти все готово, кроме одного. Сейчас, если открыть веб интерфейс Jaeger, то мы не сможем посмотреть всю цепочку запросов от первого сервиса до последнего. Нам нужно сделать так, чтобы при создании span, использовался TraceID вышестоящего сервиса, который произвел первый запрос в цепочке. 1 шаг. На стороне клиента, после создания span, извлечем TraceID и отправим в заголовке x-trace-id 2 шаг. На стороне сервера нам нужно извлечь это значение из заголовка и поместить настройки span внутрь ctx, чтобы при создании нового span использовался указанный TraceID Все готово! Теперь, если посмотреть веб интерфейс, то мы видим цепочку вызовов. Чтобы открыть веб интерфейс, переходим в http://localhost:16686 Полный пример можно посмотреть тут: https://github.com/HardDie/grpc_with_tracing_example