DEV Community

Alex Spinov
Alex Spinov

Posted on

OpenTelemetry Has a Free API That Instruments Your Entire Stack in One Standard

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
Enter fullscreen mode Exit fullscreen mode
// 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()
Enter fullscreen mode Exit fullscreen mode
# Run with auto-instrumentation
node -r ./tracing.ts src/index.ts
Enter fullscreen mode Exit fullscreen mode

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()
  })
}
Enter fullscreen mode Exit fullscreen mode

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()
})
Enter fullscreen mode Exit fullscreen mode

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' })
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Need observability for scraping pipelines? Scrapfly provides built-in monitoring. Email spinov001@gmail.com for instrumented scraping solutions.

Top comments (0)