Мониторинг Go приложений с помощью Proto Observability

Подключение трейсинга и сбора метрик для Go приложений.

На этой странице:

Введение

Общий процесс подключения Go приложения на мониторинг в Proto Observability Platform :

  1. Установка ProtoOBP Агента.
  2. Установка трейсера.
  3. Конфигурация трейсера (опционально).

После подключения будут доступны все возможности модуля Application Performance Monitoring Proto Observability Platform.

Инструментацию Go-приложения можно подключить двумя категориями способов: автоматической — без написания кода инструментации (рекомендуется), и ручной — через изменение кода. Внутри каждой категории есть несколько вариантов, отличающихся трейсером и механизмом сбора данных.

Автоматическая инструментация (рекомендуется)

СпособПлюсыМинусыДокументация
Orchestrion — на этапе компиляции (Datadog-совместимая)Самое полное покрытие библиотек; runtime-метрики Go из коробки; код менять не нужноТребуется пересборка приложения с orchestrionorchestrion
OpenTelemetry AutoSDK — eBPFНе требует ни изменения кода, ни пересборки; прикрепляется к запущенному бинарюМинимальный набор библиотек (net/http, gRPC, database/sql, kafka-go); нужен привилегированный агент рядом; runtime-метрики отдельноopentelemetry-go-instrumentation
OpenTelemetry OBI — eBPFЕдиный zero-code подход для любого языка, не только Go; код/сборку менять не нужноПокрытие на уровне сетевых протоколов (HTTP/gRPC/SQL), без деталей внутри процесса; нужен привилегированный агентopentelemetry-ebpf-instrumentation

Ручная инструментация

СпособПлюсыМинусыДокументация
Datadog трейсер (dd-trace-go)Зрелый трейсер, широкое покрытие через contrib-пакеты; runtime-метрики из коробки; полный контроль над спанамиТребует изменения кодаdd-trace-go
OpenTelemetry — ручная инструментацияVendor-neutral (OpenTelemetry SDK); полный контроль; большой выбор инструментацийТребует изменения кода и настройки SDK/экспортёраOpenTelemetry Go: instrumentation
Трейсер ProtoOBP (pobp-trace-go) ⚠️ устаревшееСовместимость с уже подключёнными сервисамиУстаревший вариант; для новых проектов используйте Datadog-совместимый или OpenTelemetrypobp-trace-go

Как выбрать способ

  • По умолчанию — Orchestrion (на этапе компиляции). Даёт самое полное покрытие и runtime-метрики Go без изменения кода. Подходит, если вы собираете приложение сами и можете добавить шаг сборки в CI/CD.
  • Нельзя менять сборку или код (готовый бинарь, сторонний образ) — OpenTelemetry AutoSDK (eBPF): агент прикрепляется к запущенному процессу. Покрытие ограничено набором поддерживаемых библиотек.
  • Полиглот-окружение (Go вместе с другими языками) и нужен единый zero-code подход — OpenTelemetry OBI (eBPF): один механизм на уровне ядра для всех сервисов.
  • Нужен полный контроль над тем, что и как трейсится, или кастомные спаны на зрелом трейсере — ручная инструментация Datadog-трейсером.
  • Стандартизируетесь на OpenTelemetry и готовы вести инструментацию в коде — ручная инструментация OpenTelemetry.
  • Трейсер ProtoOBP устарел — для новых проектов не используйте.

Ниже — детали по каждому способу.

Автоматическая инструментация (рекомендуется)

Автоматические способы не требуют написания кода инструментации. Выберите один из трёх вариантов ниже.

Инструментация на этапе компиляции (Orchestrion)

Рекомендуемый способ по умолчанию.

Пакет Orchestrion автоматически добавляет инструментацию в приложения Go во время компиляции, устраняя необходимость в модификации кода. Пакет обеспечивает всестороннее покрытие трассировкой:

  • Инструментирует ваш код и все зависимости, включая стандартную библиотеку Go.
  • Инструментирует ваш код во время компиляции, предотвращая пробелы в покрытии трассировки из-за упущенной ручной инструментации.

Требования для инструментации на этапе компиляции:

Для добавления в Go приложение инструментации на этапе компиляции выполните:

  1. Установите пакет Orchestrion:

    go install github.com/DataDog/orchestrion@latest
    
  2. Выполните команду:

    orchestrion pin
    
  3. Добавьте префикс orchestrion к обычным командам go:

    orchestrion go build .
    orchestrion go run .
    orchestrion go test ./...
    

Пример Dockerfile:

FROM golang:1.26

WORKDIR /home/apm-tutorial-golang

COPY go.mod ./
COPY go.sum ./
RUN go mod download

#Copy notes application
COPY notes notes/
COPY cmd/notes cmd/notes/ 

# добавление инструментации
RUN go install github.com/DataDog/orchestrion@latest
RUN orchestrion pin
RUN orchestrion go build -o cmd/notes/notes ./cmd/notes

# конфигурация трейсера
ENV DD_AGENT_HOST=protoobp-agent
ENV DD_TRACE_AGENT_PORT=8126
ENV DD_REMOTE_CONFIGURATION_ENABLED=false
ENV DD_TRACE_SAMPLE_RATE=1.0

#Run application
ENTRYPOINT ["./cmd/notes/notes"]  

OpenTelemetry AutoSDK (eBPF)

zero-code инструментация с помощью eBPF, реализованная проектом opentelemetry-go-instrumentation (образ otel/autoinstrumentation-go, модуль go.opentelemetry.io/auto). Отдельный агент прикрепляется к уже запущенному бинарю Go через eBPF (uprobes) и формирует трейсы без изменения исходного кода и без пересборки приложения, отправляя их в OTLP-приёмник Агента ProtoOBP.

Какие библиотеки инструментируются автоматически:

БиблиотекаЧто трейсится
net/httpHTTP-сервер и HTTP-клиент
google.golang.org/grpcgRPC-сервер и клиент
database/sqlзапросы к базе данных
github.com/segmentio/kafka-goproducer и consumer

AutoSDK — ручные спаны без настройки SDK. Чтобы размечать бизнес-логику собственными спанами, используйте стандартный API OpenTelemetry (go.opentelemetry.io/otel) совместно с пакетом go.opentelemetry.io/auto/sdk. Настраивать собственный TracerProvider, экспортёр или OTLP-конвейер в коде не нужно: пока eBPF-агент не прикреплён, такие спаны являются дешёвыми no-op, а когда агент прикреплён — он сам превращает их в реальные спаны и связывает с автоматическими (net/http, gRPC, database/sql, kafka-go).

import "go.opentelemetry.io/otel"

// SDK НЕ инициализируется. Просто используем глобальный трейсер:
tr := otel.Tracer("my-service")
ctx, span := tr.Start(ctx, "validate-order")
defer span.End()

Требования:

  • Linux с поддержкой eBPF. Агент запускается привилегированно (privileged, runAsUser: 0) и должен видеть процесс приложения (общий PID namespace).
  • Бинарь приложения собран без флагов -ldflags "-s -w" — агенту нужна build-info/символьная информация Go.
  • Один агент инструментирует один бинарь; цель задаётся переменной OTEL_GO_AUTO_TARGET_EXE (путь, по которому был запущен бинарь).

Перед началом включите OTLP-приёмник на Агенте ProtoOBP — см. Включение поддержки OpenTelemetry на агенте. Затем запустите агент инструментации рядом с приложением:

Добавьте контейнер-агент в docker-compose.yml. И контейнер приложения, и агент запускаются с pid: "host" и монтируют /proc, чтобы агент нашёл процесс по пути его бинаря:

services:
  my-app:
    image: my-app:latest
    pid: "host"
    volumes:
      - /proc:/host/proc

  go-auto:
    image: otel/autoinstrumentation-go:v0.24.0
    privileged: true
    pid: "host"
    environment:
      - OTEL_GO_AUTO_TARGET_EXE=/app/my-app                 # путь, по которому запущен бинарь
      - OTEL_SERVICE_NAME=my-app                            # имя сервиса в ProtoOBP
      - OTEL_EXPORTER_OTLP_ENDPOINT=http://protoobp-agent:4318
      - OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
      - OTEL_PROPAGATORS=tracecontext,baggage
      # опционально — захват SQL-запросов в спаны database/sql:
      - OTEL_GO_AUTO_INCLUDE_DB_STATEMENT=true
    volumes:
      - /proc:/host/proc

Убедитесь, что контейнеры приложения, агента инструментации и Агента ProtoOBP находятся в одной Docker-сети.

Добавьте агент как sidecar в под приложения. Под помечается shareProcessNamespace: true (чтобы sidecar видел процесс приложения), а сам sidecar получает securityContext с privileged: true и runAsUser: 0. Эндпоинт берётся с host IP узла (как в настройке OpenTelemetry):

apiVersion: apps/v1
kind: Deployment
#(...)
    spec:
      shareProcessNamespace: true
      containers:
        - name: my-app
          image: my-app:latest
          command: ["/app/my-app"]
        - name: go-auto
          image: otel/autoinstrumentation-go:v0.24.0
          securityContext:
            runAsUser: 0
            privileged: true
          env:
            - name: OTEL_GO_AUTO_TARGET_EXE
              value: /app/my-app
            - name: OTEL_SERVICE_NAME
              value: my-app
            - name: HOST_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.hostIP
            - name: OTEL_EXPORTER_OTLP_ENDPOINT
              value: "http://$(HOST_IP):4318"
            - name: OTEL_EXPORTER_OTLP_PROTOCOL
              value: http/protobuf
            - name: OTEL_GO_AUTO_INCLUDE_DB_STATEMENT
              value: "true"

Поддерживаемые версии Go и библиотек см. в таблице совместимости.

OpenTelemetry OBI (eBPF)

OpenTelemetry eBPF Instrumentation (OBI) — zero-code инструментация на основе eBPF, работающая для любого языка, не только Go. OBI разворачивается как привилегированный агент (обычно DaemonSet в Kubernetes) и формирует трейсы и метрики на уровне сетевых протоколов (HTTP, gRPC, SQL и др.), не требуя ни изменения кода, ни пересборки.

В отличие от AutoSDK, OBI не привязан к Go и удобен в полиглот-окружениях, где нужно единообразно покрыть сервисы на разных языках. Покрытие при этом ограничено тем, что видно на уровне ядра (границы запросов между сервисами), без деталей внутри процесса.

Телеметрия отправляется в OTLP-приёмник Агента ProtoOBP (см. настройку OpenTelemetry).

Подробная инструкция по установке и настройке OBI — на странице Zero-code инструментация с OpenTelemetry eBPF (OBI).

Ручная инструментация

Ручная инструментация требует изменения кода: вы подключаете трейсер и пакеты-интеграции для нужных библиотек. Доступны три трейсера:

  • Datadog (dd-trace-go) — рекомендуемый вариант для ручной инструментации: зрелый трейсер с широким покрытием и runtime-метриками.
  • OpenTelemetry — vendor-neutral инструментация в коде с OpenTelemetry SDK; см. официальную документацию.
  • Трейсер ProtoOBP (pobp-trace-go) — ⚠️ устаревший, оставлен для обратной совместимости. Для новых проектов используйте Datadog-совместимую или OpenTelemetry инструментацию.

Добавьте библиотеку трейсера в свое приложение Сначала импортируйте и запустите трейсер в своем коде, следуя инструкциям в документации по настройке библиотеки. Инструкции по настройке и подробную информацию об использовании API см. ниже.

Добавление модуля pobptrace:

go get -u git.proto.group/protoobp/pobp-trace-go/pobptrace

или добавьте в main.go файл:

import(
  "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

Добавление модуля ddtrace:

go get -u github.com/DataDog/dd-trace-go/v2

или добавьте в main.go файл:

import(
	"github.com/DataDog/dd-trace-go/v2/ddtrace/ext"
	"github.com/DataDog/dd-trace-go/v2/ddtrace/tracer"
)

Используйте документацию трейсера:

https://pkg.go.dev/github.com/DataDog/dd-trace-go/v2/ddtrace

Этот вариант предназначен для миграции приложений, уже инструментированных агентом New Relic: их распределённые трейсы направляются в Proto Observability Platform без изменения кода. Для новых приложений он не рекомендуется — используйте один из трейсеров, рекомендованных на этой странице.

Подробнее: Подключение приложений с трейсерами New Relic.

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Go:

    https://opentelemetry.io/docs/languages/go/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Активируйте интеграции Go для создания спанов Активируйте интеграции Go для генерации спанов. Предлагаются ряд подключаемых пакетов, которые обеспечивают готовую поддержку для инструментации ряда библиотек и фреймворков. Список этих пакетов можно найти на странице «Требования к совместимости». Импортируйте эти пакеты в свое приложение и следуйте инструкциям по настройке, указанным рядом с каждой интеграцией.

Дополнительные модули интеграции – пример добавления:

go get -u git.proto.group/protoobp/pobp-trace-go/contrib/net/http

Для автоматической инструментации вызововов поддерживаются следующие библиотеки и фреймворки (примеры доступны в документации по ссылкам):

ФреймворкДокументация по интеграции
Ginhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/gin-gonic/gin
Gorilla Muxhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/gorilla/mux
gRPChttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/google.golang.org/grpc
gRPC v1.2https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/google.golang.org/grpc.v12
chihttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/go-chi/chi
echo v4https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/labstack/echo.v4
echo v3https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go//contrib/labstack/echo
Fiberhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/gofiber/fiber.v2
БиблиотекаДокументация по интеграции
AWS SDKhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/aws/aws-sdk-go/aws
Elasticsearchhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/olivere/elastic
Cassandrahttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/gocql/gocql
GraphQLhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/graph-gophers/graphql-go
HTTPhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/net/http
HTTP routerhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/julienschmidt/httprouter
Redis (go-redis)https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/go-redis/redis
Redis (go-redis-v8)https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/go-redis/redis.v8
Redis (redigo)https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/garyburd/redigo
Redis (new redigo)https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/gomodule/redigo
SQLhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/database/sql
SQLxhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/jmoiron/sqlx
MongoDBhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/go.mongodb.org/mongo-driver/mongo
MongoDB (mgo)73https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/globalsign/mgo
BuntDBhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/tidwall/buntdb
LevelDBhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/syndtr/goleveldb/leveldb
miekg/dnshttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/miekg/dns
Kafka (confluent)https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/confluentinc/confluent-kafka-go
Kafka (sarama)https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/Shopify/sarama
Google APIhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/google.golang.org/api
go-restfulhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/emicklei/go-restful
Twirphttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/twitchtv/twirp
Vaulthttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/hashicorp/vault
Consulhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/hashicorp/consul
Gormhttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/jinzhu/gorm
Gorm v2https://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/gorm.io/gorm.v1
Kuberneteshttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/k8s.io/client-go/kubernetes
Memcachehttps://pkg.go.dev/git.proto.group/protoobp/pobp-trace-go/contrib/bradfitz/gomemcache/memcache

Пакеты для интеграции должны быть импортированы следующим образом:

import "git.proto.group/protoobp/pobp-trace-go/contrib/<PACKAGE_DIR>/<PACKAGE_NAME>"

Пример использования пакета для инструментации стандартных net/http:

package main

import (
	"fmt"
	"net/http"

	httptrace "git.proto.group/protoobp/pobp-trace-go/contrib/net/http" // дополнительный пакет
	"git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func hello(w http.ResponseWriter, req *http.Request) {

	w.Write([]byte("Hello My World!\n"))

}

func headers(w http.ResponseWriter, req *http.Request) {

	for name, headers := range req.Header {
		for _, h := range headers {
			fmt.Fprintf(w, "%v: %v\n", name, h)
		}
	}
}

func main() {

	tracer.Start(
		tracer.WithService("test-server"), 
		tracer.WithRuntimeMetrics(),       
		tracer.WithAgentAddr("protoobp-agent:8126"),
		tracer.WithDogstatsdAddress("protoobp-agent"),
	)
	mux := httptrace.NewServeMux()

	defer tracer.Stop()

	mux.HandleFunc("/hello", hello)
	mux.HandleFunc("/headers", headers)

	http.ListenAndServe(":8090", mux)
}

Пакеты интеграции импортируются следующим образом:

import "github.com/DataDog/dd-trace-go/contrib/<PACKAGE_DIR>/<PACKAGE_NAME>/v2"
ФреймворкGoDoc Документация
Gingithub.com/DataDog/dd-trace-go/contrib/gin-gonic/gin/v2
Gorilla Muxgithub.com/DataDog/dd-trace-go/contrib/gorilla/mux/v2
gRPCgithub.com/DataDog/dd-trace-go/contrib/google.golang.org/grpc/v2
chigithub.com/DataDog/dd-trace-go/contrib/go-chi/chi/v2
echo v4github.com/DataDog/dd-trace-go/contrib/labstack/echo.v4/v2
Fibergithub.com/DataDog/dd-trace-go/contrib/gofiber/fiber.v2/v2

Трейсер поддерживает следующие библиотеки и хранилища данных:

БиблиотекаПримеры использования и документация
AWS SDKgithub.com/DataDog/dd-trace-go/contrib/aws/aws-sdk-go/aws/v2
AWS SDK v2github.com/DataDog/dd-trace-go/contrib/aws/aws-sdk-go-v2/aws/v2
Elasticsearchgithub.com/DataDog/dd-trace-go/contrib/olivere/elastic.v5/v2
Cassandragithub.com/DataDog/dd-trace-go/contrib/gocql/gocql/v2
GraphQLgithub.com/DataDog/dd-trace-go/contrib/graph-gophers/graphql-go/v2
HTTPgithub.com/DataDog/dd-trace-go/contrib/net/http/v2
HTTP routergithub.com/DataDog/dd-trace-go/contrib/julienschmidt/httprouter/v2
Redis (go-redis)github.com/DataDog/dd-trace-go/contrib/go-redis/redis/v2
Redis (go-redis-v8)github.com/DataDog/dd-trace-go/contrib/go-redis/redis.v8/v2
Redis (redigo)github.com/DataDog/dd-trace-go/contrib/garyburd/redigo/v2
Redis (new redigo)github.com/DataDog/dd-trace-go/contrib/gomodule/redigo/v2
SQLgithub.com/DataDog/dd-trace-go/contrib/database/sql/v2
SQLxgithub.com/DataDog/dd-trace-go/contrib/jmoiron/sqlx/v2
MongoDBgithub.com/DataDog/dd-trace-go/contrib/go.mongodb.org/mongo-driver/mongo/v2
MongoDB (mgo)github.com/DataDog/dd-trace-go/contrib/globalsign/mgo/v2
BuntDBgithub.com/DataDog/dd-trace-go/contrib/tidwall/buntdb/v2
LevelDBgithub.com/DataDog/dd-trace-go/contrib/syndtr/goleveldb/leveldb/v2
miekg/dnsgithub.com/DataDog/dd-trace-go/contrib/miekg/dns/v2
Kafka (confluent)github.com/DataDog/dd-trace-go/contrib/confluentinc/confluent-kafka-go/v2
Kafka (sarama)github.com/DataDog/dd-trace-go/contrib/IBM/sarama/v2
Google APIgithub.com/DataDog/dd-trace-go/contrib/google.golang.org/api/v2
go-restfulgithub.com/DataDog/dd-trace-go/contrib/emicklei/go-restful.v3/v2
Twirpgithub.com/DataDog/dd-trace-go/contrib/twitchtv/twirp/v2
Vaultgithub.com/DataDog/dd-trace-go/contrib/hashicorp/vault/v2
Consulgithub.com/DataDog/dd-trace-go/contrib/hashicorp/consul/v2
Gorm v2github.com/DataDog/dd-trace-go/contrib/gorm.io/gorm.v1/v2
Kubernetesgithub.com/DataDog/dd-trace-go/contrib/k8s.io/client-go/kubernetes/v2
Memcachegithub.com/DataDog/dd-trace-go/contrib/bradfitz/gomemcache/memcache/v2

Этот вариант предназначен для миграции приложений, уже инструментированных агентом New Relic: их распределённые трейсы направляются в Proto Observability Platform без изменения кода. Для новых приложений он не рекомендуется — используйте один из трейсеров, рекомендованных на этой странице.

Подробнее: Подключение приложений с трейсерами New Relic.

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Go:

    https://opentelemetry.io/docs/languages/go/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Конфигурация трейсера

Трейсер поддерживает конфигурацию через переменные окружения или через параметры инициализации в коде вашего приложения.

Конфигурация трейсера через переменные окружения (рекомендуется)

POBP_AGENT_HOST – адрес Агента, на который будет отсылать данные трейсер:

  • если Агент запущен в Docker контейнере, укажите имя Docker контейнера Агента:
    ENV POBP_AGENT_HOST="protoobp-agent"
    
    Убедитесь, что контейнер Агента и контейнер приложения находятся в одной Docker сети. Адрес агента должен быть доступен из Docker контейнера приложения.
  • если Агент запущен на хосте как сервис (не в контейнере):
    ENV POBP_AGENT_HOST="host.docker.internal"
    
    Убедитесь что в конфигурации Агента разрешен прием APM данных от контейнеров:
    apm_config:
      apm_non_local_traffic: true
    

POBP_SERVICE – имя сервиса, которое будет отображаться в интерфейсе Proto OBP:

ENV POBP_SERVICE="my_service_name"

POBP_ENV – окружение сервиса, которое будет отображаться в интерфейсе Proto OBP:

ENV POBP_ENV="prod" # prod/test/stage/dev и тд

POBP_RUNTIME_METRICS_ENABLED – обязательно установите в true для получения runtime метрик

ENV POBP_RUNTIME_METRICS_ENABLED="true"

POBP_TRACE_TELEMETRY_ENABLED – установите в false

ENV POBP_TRACE_TELEMETRY_ENABLED="false"

DD_AGENT_HOST – адрес Агента, на который будет отсылать данные трейсер:

  • если Агент запущен в Docker контейнере, укажите имя Docker контейнера Агента:
    ENV DD_AGENT_HOST="protoobp-agent"
    
    Убедитесь, что контейнер Агента и контейнер приложения находятся в одной Docker сети. Адрес агента должен быть доступен из Docker контейнера приложения.
  • если Агент запущен на хосте как сервис (не в контейнере):
    ENV DD_AGENT_HOST="host.docker.internal"
    
    Убедитесь что в конфигурации Агента разрешен прием APM данных от контейнеров:
    apm_config:
      apm_non_local_traffic: true
    

DD_SERVICE – имя сервиса, которое будет отображаться в интерфейсе Proto OBP:

ENV DD_SERVICE="my_service_name"

DD_ENV – окружение сервиса, которое будет отображаться в интерфейсе Proto OBP:

ENV DD_ENV="prod" # prod/test/stage/dev и тд

DD_RUNTIME_METRICS_ENABLED – обязательно установите в true для получения runtime метрик

ENV DD_RUNTIME_METRICS_ENABLED="true"

DD_TRACE_TELEMETRY_ENABLED – установите в false

ENV DD_TRACE_TELEMETRY_ENABLED="false"

Этот вариант предназначен для миграции приложений, уже инструментированных агентом New Relic: их распределённые трейсы направляются в Proto Observability Platform без изменения кода. Для новых приложений он не рекомендуется — используйте один из трейсеров, рекомендованных на этой странице.

Подробнее: Подключение приложений с трейсерами New Relic.

Если приложение запускается в Docker контейнере

Пример готового Dockerfile:

ENV POBP_SERVICE=dispatch
ENV POBP_DOGSTATSD_NON_LOCAL_TRAFFIC=true
# следующие переменные лучше задавать в среде выполнения, а не в Dockerfile 
ENV POBP_ENV=prod                             
ENV POBP_AGENT_HOST=protoobp-agent
ENV DD_SERVICE=dispatch
ENV DD_DOGSTATSD_NON_LOCAL_TRAFFIC=true
# следующие переменные лучше задавать в среде выполнения, а не в Dockerfile 
ENV DD_ENV=prod                             
ENV DD_AGENT_HOST=protoobp-agent

Этот вариант предназначен для миграции приложений, уже инструментированных агентом New Relic: их распределённые трейсы направляются в Proto Observability Platform без изменения кода. Для новых приложений он не рекомендуется — используйте один из трейсеров, рекомендованных на этой странице.

Подробнее: Подключение приложений с трейсерами New Relic.

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Go:

    https://opentelemetry.io/docs/languages/go/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Если приложение работает в Kubernetes

Убедитесь, что у вас успешно установлен и настроен ProtoOBP Агент для Kubernetes.

Дополнительно необходимо передать поду переменную окружения POBP_AGENT_HOST со значением IP адреса воркер-ноды, а также переменные окружения для связи трейсов с инфраструктурой (имя k8s кластера нужно задать вручную).

apiVersion: apps/v1
kind: Deployment
#(...)
    spec:
      containers:
      - name: "<CONTAINER_NAME>"
        image: "<CONTAINER_IMAGE>/<TAG>"
        env:
          - name: POBP_SERVICE
            value: dispatch			
          - name: POBP_AGENT_HOST
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: POBP_TAGS
            value: "pod_name:$(POD_NAME),node:$(NODE_NAME),kube_namespace:$(POD_NAMESPACE),kube_cluster_name:<my_cluster_name>"            
            

Дополнительно необходимо передать поду переменную окружения DD_AGENT_HOST со значением IP адреса воркер-ноды, а также переменные окружения для связи трейсов с инфраструктурой (имя k8s кластера нужно задать вручную).

apiVersion: apps/v1
kind: Deployment
#(...)
    spec:
      containers:
      - name: "<CONTAINER_NAME>"
        image: "<CONTAINER_IMAGE>/<TAG>"
        env:
          - name: DD_SERVICE
            value: dispatch			
          - name: DD_AGENT_HOST
            valueFrom:
              fieldRef:
                fieldPath: status.hostIP
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                fieldPath: spec.nodeName
          - name: POD_NAMESPACE
            valueFrom:
              fieldRef:
                fieldPath: metadata.namespace
          - name: POD_NAME
            valueFrom:
              fieldRef:
                fieldPath: metadata.name
          - name: DD_TAGS
            value: "pod_name:$(POD_NAME),node:$(NODE_NAME),kube_namespace:$(POD_NAMESPACE),kube_cluster_name:<my_cluster_name>"            
            

Этот вариант предназначен для миграции приложений, уже инструментированных агентом New Relic: их распределённые трейсы направляются в Proto Observability Platform без изменения кода. Для новых приложений он не рекомендуется — используйте один из трейсеров, рекомендованных на этой странице.

Подробнее: Подключение приложений с трейсерами New Relic.

  1. Выполните шаги, указанные на странице подключения инструментации OpenTelemetry для Go:

    https://opentelemetry.io/docs/languages/go/

  2. Выполните шаги, указанные на странице настройки OpenTelemetry в Proto Observability Platform.

Метрики Go runtime

Помимо трейсов, ошибок и метрик по трейсам, Proto OBP также собирает runtime метрики Go приложений. Runtime метрики отображаются на дашборде конкретного инстанса сервиса.

Включение метрик Go runtime

Убедитесь, что у Агента установлена переменная окружения:

POBP_DOGSTATSD_NON_LOCAL_TRAFFIC=true

Добавьте переменную окружения к приложению:

POBP_RUNTIME_METRICS_ENABLED=true  

Добавьте переменную окружения к приложению:

DD_RUNTIME_METRICS_ENABLED=true  

Список метрик Go runtime, собираемых Proto OBP

runtime_go_num_cpu
(gauge)
Процессоры, обнаруженные средой выполнения.
runtime_go_num_goroutine
(gauge)
Созданные goroutines.
runtime_go_num_cgo_call
(gauge)
Выполненные вызовы CGO.
runtime_go_mem_stats_alloc
(gauge)
Alloc — это байты выделенных объектов кучи.
runtime_go_mem_stats_total_alloc
(gauge)
TotalAlloc — это совокупный объем выделенной памяти для объектов кучи.
runtime_go_mem_stats_sys
(gauge)
Sys — это общий объем памяти, полученной от ОС. Отображается в байтах
runtime_go_mem_stats_lookups
(gauge)
Lookups — количество поисков указателей, выполненных.
runtime_go_mem_stats_mallocs
(gauge)
Mallocs — совокупное количество выделенных объектов кучи.
runtime_go_mem_stats_frees
(gauge)
Frees — это совокупное количество освобожденных объектов кучи.
runtime_go_mem_stats_heap_alloc
(gauge)
HeapAlloc — это байты выделенных объектов кучи.
runtime_go_mem_stats_heap_sys
(gauge)
HeapSys — это количество байтов кучи памяти, полученных от ОС.
runtime_go_mem_stats_heap_idle
(gauge)
HeapIdle — это количество байтов в неиспользуемых (незанятых) интервалах.
runtime_go_mem_stats_heap_inuse
(gauge)
HeapInuse — это байты в используемых диапазонах.
runtime_go_mem_stats_heap_released
(gauge)
HeapReleased — это количество байтов физической памяти, возвращенных ОС.
runtime_go_mem_stats_heap_objects
(gauge)
HeapObjects — это количество выделенных объектов кучи.
runtime_go_mem_stats_stack_inuse
(gauge)
StackInuse — это количество байтов в стеке.
runtime_go_mem_stats_stack_sys
(gauge)
StackSys — это количество байтов памяти стека, полученных от ОС.
runtime_go_mem_stats_m_span_inuse
(gauge)
MSpanInuse — это количество байтов выделенных структур mspan.
runtime_go_mem_stats_m_span_sys
(gauge)
MSpanSys — это количество байтов памяти, полученных от ОС для структур mspan.
runtime_go_mem_stats_m_cache_inuse
(gauge)
MCacheInuse — это количество байтов выделенных структур mcache.
runtime_go_mem_stats_m_cache_sys
(gauge)
MCacheSys — это количество байтов памяти, полученных от ОС
runtime_go_mem_stats_buck_hash_sys
(gauge)
BuckHashSys — это байты памяти в хэш-таблицах профилирования.
runtime_go_mem_stats_gc_sys
(gauge)
GCSys — это байты памяти в метаданных сборки мусора.
runtime_go_mem_stats_other_sys
(gauge)
OtherSys — это байты памяти в различных внекупочных областях.
runtime_go_mem_stats_next_gc
(gauge)
NextGC — это целевой размер кучи для следующего цикла GC.
runtime_go_mem_stats_last_gc
(gauge)
LastGC — время завершения последней сборки мусора в наносекундах с 1970 года (эпоха UNIX).
runtime_go_mem_stats_pause_total_ns
(gauge)
PauseTotalNs — это совокупное количество наносекунд в GC.
runtime_go_mem_stats_num_gc
(gauge)
NumGC — количество завершенных циклов GC.
runtime_go_mem_stats_num_forced_gc
(gauge)
NumForcedGC — количество циклов GC, которые были принудительно запущены приложением, вызвавшим функцию GC.
runtime_go_mem_stats_gc_cpu_fraction
(gauge)
GCCPUFraction — доля доступного времени ЦП данной программы, использованного GC с момента запуска программы.
runtime_go_gc_stats_pause_quantiles_min
(gauge)
Распределение времени пауз GC: минимальные значения. Отображается в наносекундах
runtime_go_gc_stats_pause_quantiles_25p
(gauge)
Распределение времени пауз GC: 25-й процентиль. Отображается в наносекундах
runtime_go_gc_stats_pause_quantiles_75p
(gauge)
Распределение времени пауз GC: 50-й процентиль. Отображается в наносекундах
runtime_go_gc_stats_pause_quantiles_95p
(gauge)
Распределение времени паузы GC: 75-й процентиль. Отображается в наносекундах
runtime_go_gc_stats_pause_quantiles_max
(gauge)
Распределение времени паузы GC: максимальные значения. Отображается в наносекундах

Отображение метрик Go runtime

Для отображения метрик Go runtime выберите сервис, перейдите на вкладки Инстансы и откройте дашборд интересующего инстанса:

Трейсер ProtoOBP – дополнительная документация

Конфигурация трейсера при инициализации в коде

Параметры можно задать явным образом при инициализаци трейсера. В случае добавления ранее переменных окружения, достаточно указать только tracer.WithRuntimeMetrics() для отдачи метрик.


package main

import (
    "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func main() {
	tracer.Start(
		tracer.WithService("test-server"), 				// имя сервиса 
		tracer.WithRuntimeMetrics(),       				// включение передачи Go метрик
		tracer.WithAgentAddr("protoobp-agent"),	        // адрес по которому доступен ProtoOBP агент
		tracer.WithDogstatsdAddress("protoobp-agent"),	// адрес по которому доступен ProtoOBP агент
	)

    defer tracer.Stop()
}

Использование трейсера

Создание трейсера


package main

import (
    "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func main() {
	tracer.Start(
		tracer.WithService("test-server"), 				// имя сервиса 
		tracer.WithRuntimeMetrics(),       				// включение передачи Go метрик
	)

    defer tracer.Stop()
}

Ручное добавление спанов

Если автоматической инструментации библиотек и фреймворков недостаточно, вы можете вручную добавить спаны. Для добавления спанов доступно две функции - StartSpan и StartSpanFromContext

//Создание спана с эндпонитом /user, который дочерный к родительскому спану.
span := tracer.StartSpan("mainOp", tracer.ResourceName("/user"), tracer.ChildOf(parentSpan))

// Создание спана, который будет дочерним к спану в контексте ctx, если в контексте есть спан.
// Возвращает новый спан, и новый контекст, содержащий спан.
span, ctx := tracer.StartSpanFromContext(ctx, "mainOp", tracer.ResourceName("/user"))
Пример ручного создания спанов
package main

import (
	"io/ioutil"
	"log"

	"git.proto.group/protoobp/pobp-trace-go/pobptrace/ext"
	"git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func main() {
	// Запускаем трейсер и не забывает про Stop.
	tracer.Start(tracer.WithAgentAddr("host:port"))
	defer tracer.Stop()

	// Начинаем корневой спан.
	span := tracer.StartSpan("get.data")
	defer span.Finish()

	// Создаем дочерный спан, вычисляем время, необходимое для открытия файла.
	child := tracer.StartSpan("read.file", tracer.ChildOf(span.Context()))
	child.SetTag(ext.ResourceName, "test.json")

	// Выполняем операцию.
	_, err := ioutil.ReadFile("~/test.json")

	// Мы можем завершить дочерный спан используя возвращаемую ошибку. Если это 
	// nil, будет отброшено.
	child.Finish(tracer.WithError(err))
	if err != nil {
		log.Fatal(err)
	}
}

Добавление тегов к спану

package main

import (
    "log"
    "net/http"

    "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // Создание спана для web request для запросов к /posts.
	// ResourceName - имя эндпоинта в Proto OBP
    span := tracer.StartSpan("web.request", tracer.ResourceName("/posts"))
    defer span.Finish()

    // Добавляем тег
    span.SetTag("http.url", r.URL.Path)
    span.SetTag("<TAG_KEY>", "<TAG_VALUE>")
}

func main() {
    tracer.Start(tracer.WithService("<SERVICE_NAME>"))
    defer tracer.Stop()
    http.HandleFunc("/posts", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}
Пример добавления тэга к спану со значением кастомного HTTP заголовка

Используйте функцию span.SetTag("<KEY>", "<VALUE>") для добавления HTTP заголовка в тэг трейса, где:

KEY - должен начинаться с http.request.headers.<ИМЯ_HTTP_ЗАГОЛОВКА>

VALUE - значение заголовка

Пример:

package main

import (
    "log"
    "net/http"

    "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // Создание спана для web request для запросов к /posts.
	// ResourceName - имя эндпоинта в Proto OBP
    span := tracer.StartSpan("web.request", tracer.ResourceName("/posts"))
    defer span.Finish()

    // Добавляем тег
    span.SetTag("http.url", r.URL.Path)
	//Добавляем HTTP заголовк в тэг трейса
    span.SetTag("http.request.headers.x-request-id", "<VALUE>")
}

func main() {
    tracer.Start(tracer.WithService("<SERVICE_NAME>"))
    defer tracer.Stop()
    http.HandleFunc("/posts", handler)
    log.Fatal(http.ListenAndServe(":8080", nil))
}

Распределенный трейсинг и обработка контекста

Мы используем тип Context для связи спанов. Если нужно добавить теги связанные с Context, вызывайте SpanFromContext:


package main

import (
    "net/http"

    "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // Спан для веб запроса связанный с Go Context.
    if span, ok := tracer.SpanFromContext(r.Context()); ok {
        // добавляем тег.
        span.SetTag("http.url", r.URL.Path)
    }
}

Создание распределенного трейса путем ручного внедрения контекста:

package main

import (
    "net/http"

    "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func handler(w http.ResponseWriter, r *http.Request) {
    span, ctx := tracer.StartSpanFromContext(r.Context(), "post.process")
    defer span.Finish()

    req, err := http.NewRequest("GET", "http://example.com", nil)
    req = req.WithContext(ctx)
    // Внедрение Context хедеры Request
    err = tracer.Inject(span.Context(), tracer.HTTPHeadersCarrier(req.Header))
    if err != nil {
        // Обработка или логгирование ошибки внедрения контекста
    }
    http.DefaultClient.Do(req)
}

Далее на серверной стороне для продолжения трейса создайте новый спан из извлеченного контекста:


package main

import (
    "net/http"

    "git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func handler(w http.ResponseWriter, r *http.Request) {
    // Извлекаем контекст спана и продолжаем трейс в этом сервисе
    sctx, err := tracer.Extract(tracer.HTTPHeadersCarrier(r.Header))
    if err != nil {
        // Обработка или логгирование ошибки извлечения контекста
    }

    span := tracer.StartSpan("post.filter", tracer.ChildOf(sctx))
    defer span.Finish()
}

Ошибочный спан

Для добавления признака ошибки, используйте tracer.WithError:

err := someOperation()
span.Finish(tracer.WithError(err))

Трейсинг асинхронных запросов

func main() {
	span, ctx := tracer.StartSpanFromContext(context.Background(), "mainOp")
	defer span.Finish()

	go func() {
		asyncSpan := tracer.StartSpanFromContext(ctx, "asyncOp")
		defer asyncSpan.Finish()
		performOp()
	}()
}

Использование трейсера вместе с OpenTracing

package main

import (
	opentracing "github.com/opentracing/opentracing-go"

	"git.proto.group/protoobp/pobp-trace-go/pobptrace/opentracer"
	"git.proto.group/protoobp/pobp-trace-go/pobptrace/tracer"
)

func main() {
	//Запускаем POBP tracer, опционально передаем опции (лучше все определить через переменные окружения),
	// возвращем opentracing.Tracer который оборачивает его.
	t := opentracer.New(tracer.WithAgentAddr("host:port"))
	defer tracer.Stop() // не забываем останавливать, иначе трейсы не придут

	// Используем с Opentracing API. Уже запущенный POBP tracer
	// может быть использован параллельно с Opentracing API если нужно.
	opentracing.SetGlobalTracer(t)
}