Что такое OpenTelemetry и зачем он нужен?
Когда запрос проходит через пять сервисов за 800 мс, важно понять, какой именно сервис вызывает задержку. Именно здесь приходит на помощь OpenTelemetry.
Основные возможности:
- Инструментирует код для генерации следов (traces), метрик и логов в нейтральном формате от поставщика.
- Позволяет выбрать бэкэнд (например Jaeger, Grafana Tempo, Honeycomb или Datadog).
Установка и настройка
Для начала работы необходимо установить следующие пакеты:
npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http @opentelemetry/resources \ @opentelemetry/semantic-conventions
Затем создайте файл instrumentation.ts, который должен загружаться до запуска вашего приложения:
import { NodeSDK } from '@opentelemetry/sdk-node'
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
import { Resource } from '@opentelemetry/resources'
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'
const sdk = new NodeSDK({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: 'my-api',
[SemanticResourceAttributes.SERVICE_VERSION]: process.env.npm_package_version,
}),
traceExporter: new OTLPTraceExporter({
url: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
}),
instrumentations: [
getNodeAutoInstrumentations(),
],
})
sdk.start()
process.on('SIGTERM', () => sdk.shutdown())
В файле package.json добавьте скрипт для старта приложения:
{
"scripts": {
"start": "node --require ./instrumentation.js dist/server.js"
}
}
Автоматическая инструментирование
Функция getNodeAutoInstrumentations() автоматически отслеживает такие действия как:
- Входящие и исходящие HTTP-запросы
- Запросы к базе данных PostgreSQL
- Операции с Redis
- Вызовы gRPC
- DNS-запросы При этом не требуется вносить изменения в существующий код.
Ручные следы (spans)
Если нужно добавить кастомные следы для бизнес-логики, используйте следующий подход:
import { trace, SpanStatusCode } from '@opentelemetry/api'
const tracer = trace.getTracer('my-service')
async function processOrder(orderId: string) {
return tracer.startActiveSpan('process-order', async (span) => {
span.setAttribute('order.id', orderId)
try {...}