OpenTelemetry is the vendor-neutral observability framework. Traces, metrics, and logs — one SDK, any backend (Grafana, Datadog, Jaeger, Honeycomb).
What Is OpenTelemetry?
OpenTelemetry (OTel) is the CNCF standard for collecting telemetry data. Instead of vendor-specific agents, use one SDK that works with every observability platform.
Quick Start (Node.js)
npm install @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-http
// tracing.ts — run before your app
import { NodeSDK } from '@opentelemetry/sdk-node'
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http'
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter({ url: 'http://localhost:4318/v1/traces' }),
instrumentations: [getNodeAutoInstrumentations()],
serviceName: 'my-api',
})
sdk.start()
# Run with auto-instrumentation
node -r ./tracing.ts src/index.ts
Every HTTP request, database query, and external call is automatically traced.
Custom Spans
import { trace } from '@opentelemetry/api'
const tracer = trace.getTracer('my-app')
async function processOrder(orderId: string) {
return tracer.startActiveSpan('process-order', async (span) => {
span.setAttribute('order.id', orderId)
// Child span for payment
await tracer.startActiveSpan('charge-payment', async (paymentSpan) => {
await chargeStripe(orderId)
paymentSpan.setAttribute('payment.status', 'success')
paymentSpan.end()
})
// Child span for notification
await tracer.startActiveSpan('send-notification', async (notifSpan) => {
await sendEmail(orderId)
notifSpan.end()
})
span.setStatus({ code: 1 }) // OK
span.end()
})
}
Custom Metrics
import { metrics } from '@opentelemetry/api'
const meter = metrics.getMeter('my-app')
const requestCounter = meter.createCounter('http.requests', { description: 'Total HTTP requests' })
const responseTime = meter.createHistogram('http.response_time', { description: 'Response time in ms', unit: 'ms' })
const activeConnections = meter.createUpDownCounter('connections.active', { description: 'Active connections' })
// In middleware
app.use((req, res, next) => {
const start = Date.now()
activeConnections.add(1)
res.on('finish', () => {
requestCounter.add(1, { method: req.method, status: res.statusCode, path: req.path })
responseTime.record(Date.now() - start, { method: req.method })
activeConnections.add(-1)
})
next()
})
Export to Any Backend
// Grafana/Tempo
new OTLPTraceExporter({ url: 'http://tempo:4318/v1/traces' })
// Jaeger
new OTLPTraceExporter({ url: 'http://jaeger:4318/v1/traces' })
// Honeycomb
new OTLPTraceExporter({
url: 'https://api.honeycomb.io/v1/traces',
headers: { 'x-honeycomb-team': 'your-api-key' },
})
// Datadog
new OTLPTraceExporter({ url: 'http://datadog-agent:4318/v1/traces' })
Auto-Instrumented Libraries
- Express, Fastify, Koa, Hapi
- PostgreSQL, MySQL, MongoDB, Redis
- HTTP, gRPC, GraphQL
- AWS SDK, GCP, Azure
- Prisma, Sequelize, TypeORM
Getting Started (Local)
# Run Jaeger for local trace visualization
docker run -d -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one:latest
# Open http://localhost:16686 to see traces
Need observability for scraping pipelines? Scrapfly provides built-in monitoring. Email spinov001@gmail.com for instrumented scraping solutions.
Top comments (0)