В последние пару недель я провел много времени, изучая различные способы отправки данных OpenTelemetry (OTel) в Lightstep.
Если супер-очевидный заголовок не натолкнул вас на мысль, есть три разных способа сделать это:
- Непосредственно из приложения
- Коллектор OpenTelemetry
- Запускающие устройства (через коллектор или непосредственно из приложения).
В этой статье я подробно рассмотрю каждый из этих трех подходов, с фрагментами кода, которые объясняют, как получить данные в Lightstep Observability. Давайте сделаем это!
Примечание: Если вы ищете полные листинги кода, не паникуйте! Вы найдете их в репозитории примеров Lightstep OTel.
- Предварительные требования
- OpenTelemetry & Lightstep
- Напрямую из приложения
- Как это работает
- 1- Установите необходимые библиотеки OTel
- 2- Настройте экспортер
- 3- Настройте TracerProvider
- 4- Инициализируйте Exporter и TracerProvider для отправки данных в Lightstep
- Попробуйте!
- 1 — Клонируйте репозиторий
- 2- Откройте окно терминала и запустите серверную программу
- 3- Откройте новое окно терминала и выберите конечную точку
- 4- Посмотреть в Lightstep
- Коллектор OpenTelemetry
- Как это работает
- 1- Установите необходимые библиотеки OTel
- 2- Настройте экспортер
- 3- Настройте TracerProvider
- 4- Инициализируем экспортер и TracerProvider для отправки данных в Lightstep
- Попробуйте!
- 1 — Клонируйте репозиторий
- 2- Запустите коллектор
- 3- Откройте новое окно терминала и запустите серверную программу
- 4- Откройте третье окно терминала и нажмите на конечную точку
- 5- Посмотреть в Lightstep
- Launcher
- Как это работает
- 1- Установите необходимые библиотеки OTel
- 2- Настройка запуска
- 3- Инициализация запуска
- Попробуйте!
- 1 — Клонируйте репозиторий
- 2- Запустите коллектор
- 3- Откройте новое окно терминала и запустите серверную программу
- 4- Откройте третье окно терминала и нажмите на конечную точку
- Задачи
- 1- Отладка gRPC
- 2- Отладочные пролеты (только для Launchers)
- Какой подход лучше?
- Заключительные мысли
Предварительные требования
Прежде чем мы продолжим, вот некоторые вещи, которые вам понадобятся:
- Базовое понимание Golang
- Базовое понимание коллектора OpenTelemetry Collector
Если вы хотите запустить примеры с полным кодом, вам также понадобятся:
- Учетная запись Lightstep Observability
- Токен доступа Lightstep, чтобы указать Lightstep, в какой проект отправлять ваши трассы
- рабочая локальная среда разработки Golang
- Docker (он понадобится нам для локального запуска OTel Collector)
OpenTelemetry & Lightstep
Lightstep Observability поддерживает собственный протокол OpenTelemetry Protocol (OTLP). Он может получать данные в формате OTLP либо через HTTP, либо через gRPC. Вам нужно будет указать, какой метод вы хотите использовать в своем коде, как мы увидим в последующих фрагментах кода.
Если вам интересно, как использовать gRPC и HTTP для OpenTelemetry, ознакомьтесь с этими документами.
Примечание: Другие инструменты Observability, поддерживающие OTLP, включают Honeycomb, Grafana и Jaeger.
Напрямую из приложения
Если вы начинаете работать с инструментами OpenTelemetry в своем приложении, это, вероятно, самый распространенный путь, который выбирают большинство новичков. Как следует из названия, мы отправляем данные на данный бэкэнд Observability непосредственно из кода нашего приложения.
Для этого мы должны сделать следующее:
- Установить необходимые пакеты OpenTelemetry и импортировать их.
- Настроить экспортер
- Настроить TracerProvider
- Инициализировать экспортер и TracerProvider для отправки данных в Lightstep.
Не паникуйте, если вы не знаете, что все это значит. Вскоре мы начнем разбираться.
Примечание: Вы можете посмотреть полный пример отправки данных OTel в Lightstep напрямую через OTLP по gRPC здесь. HTTP-версию можно найти здесь.
Как это работает
1- Установите необходимые библиотеки OTel
Это библиотеки, которые необходимы для отправки данных в Observability back-end (например, Lightstep).
go get go.opentelemetry.io/otel
go.opentelemetry.io/otel/exporters/otlp/otlptrace
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
go.opentelemetry.io/otel/propagation
go.opentelemetry.io/otel/sdk/resource
go.opentelemetry.io/otel/sdk/trace
go.opentelemetry.io/otel/semconv/v1.10.0
go.opentelemetry.io/otel/trace
В коде нашего приложения нам нужно будет импортировать те же библиотеки:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
"go.opentelemetry.io/otel/trace"
)
Если вы хотите использовать HTTP вместо gRPC, замените otlptracegrpc
на otlptracehttp
.
2- Настройте экспортер
Экспортер — это то, как мы отправляем данные в OpenTelemetry. Как я упоминал ранее, Lightstep принимает данные в формате OTLP, поэтому нам нужно определить OTLP Exporter.
Примечание: Некоторые поставщики не принимают данные в формате OTLP, поэтому для отправки им данных вам придется использовать экспортер, предназначенный для конкретного поставщика.
Мы настроим наш экспортер следующим образом:
var (
tracer trace.Tracer
endpoint = "ingest.lightstep.com:443"
lsToken = "<LS_ACCESS_TOKEN>"
)
func newExporter(ctx context.Context) (*otlptrace.Exporter, error) {
var headers = map[string]string{
"lightstep-access-token": lsToken,
}
client := otlptracegrpc.NewClient(
otlptracegrpc.WithHeaders(headers),
otlptracegrpc.WithEndpoint(endpoint),
)
return otlptrace.New(ctx, client)
}
Некоторые примечательные элементы:
endpoint
установлен наingest.lightstep.com:443
, который указывает на публичный пул микроспутников Lightstep. Если вы используете местный спутниковый пул, ознакомьтесь с этой документацией.- Вы должны указать значение для
<LS_ACCESS_TOKEN>
с вашим собственным токеном доступа Lightstep. - Мы отправляем данные в Lightstep через gRPC. Если вы хотите использовать HTTP вместо gRPC, ваше клиентское соединение будет выглядеть следующим образом:
client := otlptracehttp.NewClient(
otlptracehttp.WithHeaders(headers),
otlptracehttp.WithEndpoint(endpoint),
otlptracehttp.WithURLPath("traces/otlp/v0.9"),
)
Обратите внимание, что мы должны добавить дополнительный параметр конфигурации, WithURLPath
. Этот параметр конфигурации позволяет нам переопределить путь URL по умолчанию для отправки трасс. Значение по умолчанию — /v1/traces
; однако для HTTP-соединений Lightstep ожидает, что это значение будет traces/otlp/v0.9
.
3- Настройте TracerProvider
TracerProvider
служит точкой входа в OpenTelemetry API. Он предоставляет доступ к Tracer
s. Tracer
отвечает за создание Span для отслеживания заданной операции.
Мы настраиваем наш TracerProvider следующим образом:
var (
tracer trace.Tracer
serviceName = "test-go-server-grpc"
serviceVersion = "0.1.0"
lsEnvironment = "dev"
)
func newTraceProvider(exp *otlptrace.Exporter) *sdktrace.TracerProvider {
resource, rErr :=
resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(serviceName),
semconv.ServiceVersionKey.String(serviceVersion),
attribute.String("environment", lsEnvironment),
),
)
if rErr != nil {
panic(rErr)
}
return sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exp),
sdktrace.WithResource(resource),
)
}
Несколько примечательных моментов:
- Мы определяем ресурс (Resource), чтобы предоставить OpenTelemetry кучу информации, которая идентифицирует наш сервис. Сюда входят такие вещи, как
serviceName
иserviceVersion
, которые должны быть установлены Lightstep. Как следует из названия,serviceName
— это имя микросервиса, который вы инструментируете.
4- Инициализируйте Exporter и TracerProvider для отправки данных в Lightstep
Наконец-то мы готовы отправить данные в Lightstep! Для этого мы вызываем функции newExporter
и newTraceProvider
из нашей функции main
:
func main() {
ctx := context.Background()
exp, err := newExporter(ctx)
if err != nil {
log.Fatalf("failed to initialize exporter: %v", err)
}
tp := newTraceProvider(exp)
defer func() { _ = tp.Shutdown(ctx) }()
otel.SetTracerProvider(tp)
// More code here
...
}
Попробуйте!
Давайте посмотрим пример кода в действии. В этом примере мы запустим сервер с конечной точкой /ping
. Сервер будет отправлять данные OTel в Lightstep напрямую через OTLP по gRPC. Мы будем обращаться к конечной точке с помощью curl
.
1 — Клонируйте репозиторий
git clone git@github.com:lightstep/opentelemetry-examples.git
2- Откройте окно терминала и запустите серверную программу
cd opentelemetry-examples/go/opentelemetry/otlp/server
export LS_ACCESS_TOKEN=<your_access_token>
go run server.go
Обязательно замените <your_access_token>
на ваш собственный Lightstep Access Token
3- Откройте новое окно терминала и выберите конечную точку
curl http://localhost:8081/ping
Боковой пример вывода данных с сервера и команды curl
:
4- Посмотреть в Lightstep
Примечание: Хотите запустить HTTP версию? Замените
go run server.go
в Шаге 2 наgo run server-http.go
.
Коллектор OpenTelemetry
Следующий подход к отправке данных в Observability back-end — это использование OpenTelemetry Collector. Для установок, не связанных с разработкой, это рекомендуемый подход к отправке данных OpenTelemetry на бэкэнд Observability.
Чтобы отправить данные, полученные с помощью приборов, на внутренний модуль Observability через Коллектор, необходимо сделать следующее:
- Запустить где-нибудь экземпляр OpenTelemetry Collector (проще всего запустить его локально).
- Установить необходимые пакеты OpenTelemetry и импортировать их.
- Настроить экспортер
- Настройте TracerProvider
- Инициализируйте экспортер и TracerProvider
Примечание: Вы можете посмотреть полный листинг кода здесь.
Выглядит почти так же, как и прямой подход, не так ли? Почти…
В ближайшее время мы рассмотрим различия.
Как это работает
1- Установите необходимые библиотеки OTel
Это библиотеки, которые необходимы для отправки данных в Observability back-end (например, Lightstep).
go get go.opentelemetry.io/otel
go.opentelemetry.io/otel/exporters/otlp/otlptrace
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc
go.opentelemetry.io/otel/propagation
go.opentelemetry.io/otel/sdk/resource
go.opentelemetry.io/otel/sdk/trace
go.opentelemetry.io/otel/semconv/v1.10.0
go.opentelemetry.io/otel/trace
В коде нашего приложения нам нужно будет импортировать те же библиотеки:
import (
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/sdk/resource"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
"go.opentelemetry.io/otel/trace"
)
Если вы хотите использовать HTTP вместо gRPC, замените otlptracegrpc
на otlptracehttp
.
2- Настройте экспортер
Как мы видели в примере Direct, мы экспортируем наши данные через OTLP (см. тип возврата otlptrace.Exporter
). Разница в том, что вместо экспорта данных непосредственно в Lightstep, мы экспортируем их в OTel Collector, который получает данные OTel из нашего приложения в формате OTLP.
В нашем примере Direct, прежде чем создать новый экспортер, нам сначала нужно было создать новый клиент трассировки (otlptracegrpc.NewClient
), чтобы мы могли указать OpenTelemetry, как отправлять данные в Lightstep. Нам не нужно делать этого при использовании коллектора, потому что коллектор позаботится о создании клиента трассировки для нас за кулисами, используя для этого информацию в YAML конфигурации коллектора.
Мы настраиваем наш экспортер следующим образом:
var (
endpoint = "localhost:4317"
)
func newExporter(ctx context.Context) (*otlptrace.Exporter, error) {
exporter, err :=
otlptracegrpc.New(ctx,
otlptracegrpc.WithInsecure(),
otlptracegrpc.WithEndpoint(endpoint),
)
return exporter, err
}
Некоторые примечательные элементы:
endpoint
— это URL вашего коллектора.- В примере ниже, коллектор
endpoint
установлен наlocalhost:4317
, что означает, что OpenTelemetry Collector запущен локально, с помощью Docker, прослушивая gRPC порт4317
. - Вам не нужно предоставлять токен Lightstep Access как часть этой конфигурации, так как это значение задается в YAML-файле конфигурации OTel Collector.
- Обратите внимание, что опция
WithInsecure
установлена. Это требуется, если вы используете Коллектор, и только в том случае, если сертификат не настроен в Коллекторе. (Это статья в блоге для другого дня 😜). - Мы отправляем данные в Коллектор через gRPC. Если вы хотите использовать HTTP вместо gRPC, просто замените
otlptracegrpc
наotlptracehttp
следующим образом:
exporter, err :=
otlptracehttp.New(ctx,
otlptracehttp.WithInsecure(),
otlptracehttp.WithEndpoint(endpoint),
)
3- Настройте TracerProvider
Наш TracerProvider
идентичен тому, который мы настроили в примере Direct:
var (
tracer trace.Tracer
serviceName = "test-go-server-grpc"
serviceVersion = "0.1.0"
lsEnvironment = "dev"
)
func newTraceProvider(exp *otlptrace.Exporter) *sdktrace.TracerProvider {
resource, rErr :=
resource.Merge(
resource.Default(),
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceNameKey.String(serviceName),
semconv.ServiceVersionKey.String(serviceVersion),
attribute.String("environment", lsEnvironment),
),
)
if rErr != nil {
panic(rErr)
}
return sdktrace.NewTracerProvider(
sdktrace.WithBatcher(exp),
sdktrace.WithResource(resource),
)
}
4- Инициализируем экспортер и TracerProvider для отправки данных в Lightstep
Наконец-то мы готовы отправить данные в Lightstep! Для этого мы вызываем функции newExporter
и newTraceProvider
из нашей функции main
:
func main() {
ctx := context.Background()
exp, err := newExporter(ctx)
if err != nil {
log.Fatalf("failed to initialize exporter: %v", err)
}
tp := newTraceProvider(exp)
defer func() { _ = tp.Shutdown(ctx) }()
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(
propagation.NewCompositeTextMapPropagator(
propagation.TraceContext{},
propagation.Baggage{},
),
)
tracer = tp.Tracer(serviceName, trace.WithInstrumentationVersion(serviceVersion))
// More code here
...
}
Обратите внимание, что это то же самое, что мы видели в примере Direct. Только основной код в функции newExporter
отличается.
Попробуйте!
Давайте посмотрим пример кода в действии. В этом примере мы запустим сервер с конечной точкой /ping
. Сервер будет отправлять данные OTel в Lightstep через коллектор по протоколу gRPC. Мы будем обращаться к конечной точке с помощью curl
.
1 — Клонируйте репозиторий
git clone git@github.com:lightstep/opentelemetry-examples.git
2- Запустите коллектор
Откройте новое окно терминала. Сначала вам нужно будет отредактировать файл collector.yaml. Обязательно замените ${LIGHTSTEP_ACCESS_TOKEN}
на ваш собственный токен доступа Lightstep.
Теперь вы можете запустить коллектор:
cd opentelemetry-examples/collector/vanilla
docker run -it --rm -p 4317:4317 -p 4318:4318
-v $(pwd)/collector.yaml:/otel-config.yaml
--name otelcol otel/opentelemetry-collector-contrib:0.53.0
"/otelcol-contrib"
"--config=otel-config.yaml"
Примечание: Это может занять некоторое время, если вы впервые запускаете изображение Коллектора.
Образец вывода:
3- Откройте новое окно терминала и запустите серверную программу
cd opentelemetry-examples/go/opentelemetry/collector/server
go run server.go
4- Откройте третье окно терминала и нажмите на конечную точку
curl http://localhost:8081/ping
Бок о бок примеры вывода из вывода сервера и команды curl
:
И ваш вывод Collector должен выглядеть примерно так:
5- Посмотреть в Lightstep
Launcher
Последний подход, который мы рассмотрим сегодня — это Launcher. Если вы просмотрели документацию по OpenTelemetry и не увидели нигде упоминания о Launcher, это потому, что они не являются частью OTel как таковой.
Вы можете думать о лаунчерах как обертках вокруг SDK OTel. Изначально Launchers были созданы некоторыми талантливыми инженерами в Lightstep, чтобы обеспечить способ инкапсуляции установки и конфигурации OpenTelemetry. Проще говоря, пусковые установки были созданы потому, что они устали дублировать код настройки SDK. И снова лень разработчика в выигрыше! (Для справки, я твердо убежден, что лень разработчиков — это то, что делает отличное программное обеспечение. Мы просто ненавидим повторения!) Launchers также добавляют уровень проверки, чтобы дать пользователям лучшее понимание всех необходимых параметров. Подробнее о лаунчерах читайте в этой статье Теда Янга.
В настоящее время у нас есть Launchers для Go, Python, Java и Node.JS.
Хорошо… теперь, когда мы поняли, зачем существуют Launchers, давайте выясним, как использовать их для отправки данных OTel в Lightstep.
Для этого мы должны сделать следующее:
- Установить необходимые пакеты OpenTelemetry и Launcher и импортировать их.
- Настроить Launcher
- Инициализировать Launcher
Выглядит немного иначе, чем в двух других примерах, не так ли? Как вы видите, Launcher берет на себя заботу о конфигурации и инициализации Exporter и TracerProvider.
Давайте покопаемся в этом.
Примечание: Полный пример отправки данных OTel в Lightstep с помощью Go Launcher через коллектор по gRPC вы можете посмотреть здесь. Прямую версию (через Launcher) можно найти здесь.
Как это работает
1- Установите необходимые библиотеки OTel
go get github.com/lightstep/otel-launcher-go/launcher
go.opentelemetry.io/otel
go.opentelemetry.io/otel/semconv/v1.10.0
go.opentelemetry.io/otel/trace
В коде нашего приложения нам нужно будет импортировать те же библиотеки:
import (
"github.com/lightstep/otel-launcher-go/launcher"
"go.opentelemetry.io/otel"
semconv "go.opentelemetry.io/otel/semconv/v1.10.0"
"go.opentelemetry.io/otel/trace"
)
Хм… меньше пакетов для установки и импорта!
2- Настройка запуска
Здесь мы настраиваем Launcher, аналогично тому, что мы делали, когда настраивали Exporter и TracerProvider. Только все это заключено в этом чудесном launcher.ConfigureOpentelemetry
! Супер круто. 😎
var (
tracer trace.Tracer
serviceName = "test-go-server-launcher"
serviceVersion = "0.1.0"
endpoint = "ingest.lightstep.com:443"
lsToken = "<LS_ACCESS_TOKEN>"
)
func newLauncher() launcher.Launcher {
otelLauncher := launcher.ConfigureOpentelemetry(
launcher.WithServiceName(serviceName),
launcher.WithServiceVersion(serviceVersion),
launcher.WithAccessToken(lsToken),
launcher.WithSpanExporterEndpoint(endpoint),
launcher.WithMetricExporterEndpoint(endpoint),
launcher.WithPropagators([]string{"tracecontext", "baggage"}),
launcher.WithResourceAttributes(map[string]string{
string(semconv.ContainerNameKey): "my-container-name",
}),
)
return otelLauncher
}
Некоторые примечательные элементы:
endpoint
установлен наingest.lightstep.com:443
, который указывает на публичный пул микроспутников Lightstep. Если вы используете местный спутниковый пул, ознакомьтесь с этой документацией.- Вы должны указать значение для
<LS_ACCESS_TOKEN>
с вашим собственным токеном доступа Lightstep. - Запускающие устройства используют только gRPC. Честно говоря, это не проблема.
Это все хорошо, но что если вы хотите использовать коллектор? Разве я не говорил, что это предпочтительный метод для установок без разработчиков? Да, я говорил! И не волнуйтесь, потому что вы можете использовать Launchers для отправки данных OTel в коллектор, а не напрямую в Lightstep. Для этого вам просто нужно:
- Изменить значение
endpoint
наlocalhost:4317
. - Установить
WithSpanExporterInsecure
наtrue
- Установите
WithMetricExporterInsecure
вtrue
- Удалите параметр
WithAccessToken
(поскольку он обрабатывается YAML-файлом конфигурации OTel Collector).
Это означает, что ваш код будет выглядеть следующим образом:
var (
tracer trace.Tracer
serviceName = "test-go-server-launcher"
serviceVersion = "0.1.0"
endpoint = "ingest.lightstep.com:443"
)
func newLauncher() launcher.Launcher {
otelLauncher := launcher.ConfigureOpentelemetry(
launcher.WithServiceName(serviceName),
launcher.WithServiceVersion(serviceVersion),
launcher.WithSpanExporterInsecure(true),
launcher.WithSpanExporterEndpoint(endpoint),
launcher.WithMetricExporterEndpoint(endpoint),
launcher.WithMetricExporterInsecure(true),
launcher.WithPropagators([]string{"tracecontext", "baggage"}),
launcher.WithResourceAttributes(map[string]string{
string(semconv.ContainerNameKey): "my-container-name",
}),
)
return otelLauncher
}
3- Инициализация запуска
Все, что нам нужно сделать, это вызвать нашу функцию newLauncher
, и все готово!
func main() {
otelLauncher := newLauncher()
defer otelLauncher.Shutdown()
tracer = otel.Tracer(serviceName)
// More code here
...
}
В целом, подход Launcher требует меньше кода по сравнению с двумя другими подходами sans-Launcher.
Попробуйте!
Давайте посмотрим пример кода в действии. В этом примере мы запустим сервер с конечной точкой /ping
. Сервер будет отправлять данные OTel в Lightstep с помощью Go Launcher через коллектор, по gRPC. Мы будем обращаться к конечной точке с помощью curl
.
1 — Клонируйте репозиторий
git clone git@github.com:lightstep/opentelemetry-examples.git
2- Запустите коллектор
Откройте новое окно терминала. Сначала вам нужно будет отредактировать файл collector.yaml. Обязательно замените ${LIGHTSTEP_ACCESS_TOKEN}
на ваш собственный токен доступа Lightstep.
Теперь вы можете запустить коллектор:
cd opentelemetry-examples/collector/vanilla
docker run -it --rm -p 4317:4317 -p 4318:4318
-v $(pwd)/collector.yaml:/otel-config.yaml
--name otelcol otel/opentelemetry-collector-contrib:0.53.0
"/otelcol-contrib"
"--config=otel-config.yaml"
Примечание: Это может занять некоторое время, если вы впервые запускаете изображение Коллектора.
Образец вывода:
3- Откройте новое окно терминала и запустите серверную программу
cd opentelemetry-examples/go/launcher/server
go run server.go
4- Откройте третье окно терминала и нажмите на конечную точку
curl http://localhost:8081/ping
Бок о бок примеры вывода из вывода сервера и команды curl
:
И ваш вывод Collector должен выглядеть примерно так:
- Посмотреть в Lightstep
Примечание: Хотите запустить прямую версию с помощью Launcher? Просто пропустите Шаг 2. В Шаге 3 установите переменную окружения
LS_ACCESS_TOKEN
:export LS_ACCESS_TOKEN=<your_access_token>
, где<your_access_token>
— ваш собственный Lightstep Access Token, и заменитеgo run server.go
наgo run server-otlp.go
.
Задачи
Пока я возился с каждым из трех подходов, я столкнулся с несколькими проблемами, поэтому я решил поделиться ими здесь.
1- Отладка gRPC
gRPC — это бич моего существования. Особенно когда я вижу это прекрасное сообщение context deadline exceeded
. Это заставляет мою кровь кипеть. К счастью, мои друзья OTel из Lighstep рассказали мне о двух небольших флагах, которые немного облегчают отладку gRPC:
export GRPC_GO_LOG_VERBOSITY_LEVEL=99
export GRPC_GO_LOG_SEVERITY_LEVEL=info
Установите эти красивые флажки, и вы относительно быстро узнаете, если не можете подключиться к конечной точке gRPC. Вот как выглядит успешное соединение:
2022/07/26 16:28:36 Using default LS endpoint ingest.lightstep.com:443
2022/07/26 16:28:36 INFO: [core] [Channel #1] Channel created
2022/07/26 16:28:36 INFO: [core] [Channel #1] original dial target is: "ingest.lightstep.com:443"
2022/07/26 16:28:36 INFO: [core] [Channel #1] parsed dial target is: {Scheme:ingest.lightstep.com Authority: Endpoint:443 URL:{Scheme:ingest.lightstep.com Opaque:443 User: Host: Path: RawPath: ForceQuery:false RawQuery: Fragment: RawFragment:}}
2022/07/26 16:28:36 INFO: [core] [Channel #1] fallback to scheme "passthrough"
2022/07/26 16:28:36 INFO: [core] [Channel #1] parsed dial target is: {Scheme:passthrough Authority: Endpoint:ingest.lightstep.com:443 URL:{Scheme:passthrough Opaque: User: Host: Path:/ingest.lightstep.com:443 RawPath: ForceQuery:false RawQuery: Fragment: RawFragment:}}
2022/07/26 16:28:36 INFO: [core] [Channel #1] Channel authority set to "ingest.lightstep.com:443"
2022/07/26 16:28:36 INFO: [core] [Channel #1] Resolver state updated: {
"Addresses": [
{
"Addr": "ingest.lightstep.com:443",
"ServerName": "",
"Attributes": null,
"BalancerAttributes": null,
"Type": 0,
"Metadata": null
}
],
"ServiceConfig": null,
"Attributes": null
} (resolver returned new addresses)
2022/07/26 16:28:36 INFO: [core] [Channel #1] Channel switches to new LB policy "pick_first"
2022/07/26 16:28:36 INFO: [core] [Channel #1 SubChannel #2] Subchannel created
2022/07/26 16:28:36 Using default service name test-go-client-grpc
2022/07/26 16:28:36 Using default service version 0.1.0
2022/07/26 16:28:36 Using default environment dev
2022/07/26 16:28:36 INFO: [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to CONNECTING
2022/07/26 16:28:36 INFO: [core] [Channel #1 SubChannel #2] Subchannel picks a new address "ingest.lightstep.com:443" to connect
2022/07/26 16:28:36 INFO: [core] pickfirstBalancer: UpdateSubConnState: 0x14000380100, {CONNECTING <nil>}
2022/07/26 16:28:36 INFO: [core] [Channel #1] Channel Connectivity change to CONNECTING
Get "http://localhost:8081/ping": dial tcp [::1]:8081: connect: connection refused
2022/07/26 16:28:37 INFO: [core] [Channel #1 SubChannel #2] Subchannel Connectivity change to READY
2022/07/26 16:28:37 INFO: [core] pickfirstBalancer: UpdateSubConnState: 0x14000380100, {READY <nil>}
2022/07/26 16:28:37 INFO: [core] [Channel #1] Channel Connectivity change to READY
2- Отладочные пролеты (только для Launchers)
Если вы используете Launcher и ваши Spans не отображаются в Lightstep, вы можете установить флаг OTEL_LOG_LEVEL
перед запуском кода:
export OTEL_LOG_LEVEL=debug
go run <your_app>.go
Ваш отладочный вывод будет выглядеть примерно так:
2022/07/26 15:39:10 debug logging enabled
2022/07/26 15:39:10 configuration
2022/07/26 15:39:10 {
"SpanExporterEndpoint": "localhost:4317",
"SpanExporterEndpointInsecure": true,
"ServiceName": "test-go-client-launcher",
"ServiceVersion": "0.1.0",
"Headers": null,
"MetricExporterEndpoint": "localhost:4317",
"MetricExporterEndpointInsecure": true,
"MetricExporterTemporalityPreference": "cumulative",
"MetricsEnabled": true,
"LogLevel": "debug",
"Propagators": [
"tracecontext",
"baggage"
],
...
}
Какой подход лучше?
Когда я только начинал свое путешествие по OTel в 2021 году (в дни, предшествовавшие Lightstep), я отправлял данные OTel на бэкэнд Observability с помощью OTel Collector. Для меня это было несложно, потому что коллектор может:
- получать данные из различных источников (включая приложения и метрики инфраструктуры)
- добавлять/удалять метаданные
- маскировать данные
- отбирать данные
- отправлять данные на несколько внутренних серверов одновременно (что очень удобно, если вы оцениваете различных поставщиков или переходите от одного поставщика к другому).
Я лично являюсь большим поклонником коллектора, и я поддерживаю свое заявление о том, что хорошей практикой является запуск OTel Collector в средах Pre-Prod/Prod для отправки данных OpenTelemetry на бэкэнд Observability.
НО… я должен признать, что я думал об этой проблеме скорее с точки зрения эксплуатации, чем с точки зрения разработчика.
Дело в том, что когда вы начинаете работать с OTel, есть шанс, что вы начинаете с нуля. Это означает, что вам уже приходится разбираться со всем этим инструментарием. Это и так достаточно напряженно. Добавьте к этому попытку создать коллектор, и вы получите слишком много движущихся частей и, вероятно, очень перегруженного разработчика… даже если вы запустите его с самой простой конфигурацией (т.е. локально, через Docker). К тому же, действительно ли вам нужно запускать Collector, если вы просто ведете локальную разработку? Вероятно, это больше усилий, чем пользы.
НО… я также узнал из личного опыта, что подключение к Observability back-end через прямой подход — это королевская боль в заднице. Документация была очень скудной. Примеры были неполными. Излишне говорить, что это было очень трудное путешествие. И у меня были трудности с использованием HTTP и gRPC.
В связи с этим возникает вопрос: какой хороший и простой способ инструментировать ваш код и отправить его на бэкэнд Observability? Вот тут-то и вступают в игру Launchers! Потому что они дают вам лучшее из двух миров. Вы можете подключиться непосредственно к бэкенду Observability, ИЛИ вы можете подключиться через OTel Collector. Кроме того, Launchers не ограничивает вас в использовании Lightstep в качестве бэкенда Observability, потому что:
- Если вы подключаетесь к коллектору из Launcher, коллектор автоматически дает вам возможность отправлять на несколько бэкэндов Observability.
- Если вы решили подключиться напрямую к бэкенду, не относящемуся к Lightstep Observability, который принимает данные OTel в формате OTLP из Launcher.
Должен признаться, что до использования Go Launcher я относился к нему довольно скептически. В конце концов, это не ванильный OTel, что заставило меня подумать… «О-о-о… блокировка поставщика! Разве не этого пытается избежать OTel?».
Но две вещи изменили мое мнение об этом. Во-первых, тот факт, что вы не привязаны к конкретному поставщику (см. выше). Во-вторых, наши друзья из Honeycomb работают над внедрением лаунчеров в сообщество, согласно работе, проделанной здесь, так что есть шанс, что лаунчеры могут стать (ванильным) будущим OTel!
Мой вывод: Launcher выигрывает благодаря своей гибкости и общей простоте по сравнению с аналогами.
Заключительные мысли
Мы узнали о том, как мы можем отправлять данные OTel в Lightstep тремя различными способами:
- Непосредственно из нашего приложения
- Через OTel Collector
- Используя Launchers, которые могут отправлять данные непосредственно в Lightstep или через коллектор.
При использовании коллектора предпочтительным способом отправки данных в Observability является использование коллектора; однако, если вы только начинаете работать с OTel, отправка данных OTel непосредственно в Observability имеет наибольший смысл, поскольку вам придется иметь дело с меньшим количеством движущихся частей.
Тем не менее, использование ванильного OTel для выполнения любого из вышеперечисленных действий может быть немного перегруженным, поэтому на помощь приходят Launchers, которые абстрагируют кучу вещей, связанных с подключением, что упрощает отправку данных на вашу Observability back-end, будь то напрямую или через коллектор.
Ух ты! Было о чем подумать и что принять! Похлопайте себя по спине, потому что мы многое рассмотрели! А теперь, пожалуйста, наслаждайтесь фотографией коз.
Мира, любви и кода. 🦄 🌈 💫
Есть вопросы по инструментарию OTel с Golang? Свяжитесь с нами! Свяжитесь с нами по электронной почте или напишите мне в Twitter. Надеюсь услышать вас всех!