Intermediate

Distributed Tracing with OpenTelemetry

Propagate trace IDs across microservices using OpenTelemetry and connect them to LogFlow's trace correlation and Service Map features.

LogFlow TeamApr 25, 202625 minOpenTelemetryMicroservices

When a request touches multiple microservices, a trace ID connects all the logs together. Without it, debugging means grep-ing through logs from five different services hoping to reconstruct what happened. With OpenTelemetry and LogFlow, you click one log line and see the entire trace.

How trace correlation works in LogFlow

Every log that includes a trace_id field becomes part of a trace. In the Logs Explorer, click any log → View trace → LogFlow shows every log from every service that shares that trace ID, sorted chronologically with relative timestamps (+0ms, +23ms, +340ms).

The Service Map uses the same data to draw edges between services automatically.

Step 1 — Install OpenTelemetry

For Node.js services, install the SDK and HTTP propagator:

npm install @opentelemetry/sdk-node \
  @opentelemetry/auto-instrumentations-node \
  @opentelemetry/exporter-trace-otlp-http \
  @opentelemetry/api

Step 2 — Initialize tracing

Create src/tracing.js and load it before anything else:

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({
  serviceName: process.env.SERVICE_NAME || 'my-service',
  traceExporter: new OTLPTraceExporter({
    url: 'https://api.getlogflow.com/v1/otlp/traces',
    headers: {
      Authorization: `Bearer ${process.env.LOGFLOW_API_KEY}`,
    },
  }),
  instrumentations: [getNodeAutoInstrumentations()],
})

sdk.start()

process.on('SIGTERM', () => sdk.shutdown())

Start your app with tracing enabled:

node --import ./src/tracing.js src/index.js

Step 3 — Extract trace ID and add to logs

OpenTelemetry sets a trace ID on every request. Extract it and pass it to LogFlow:

import { trace, context } from '@opentelemetry/api'
import { LogFlow } from '@getlogflow/js'

const logger = new LogFlow({
  apiKey: process.env.LOGFLOW_API_KEY,
  service: process.env.SERVICE_NAME,
})

// Helper: get current trace ID
function getTraceId() {
  const span = trace.getActiveSpan()
  return span?.spanContext().traceId
}

// Use in your code:
logger.info('Processing payment', {
  traceId: getTraceId(),
  orderId: order.id,
  amount: order.total,
})

Step 4 — Propagate trace ID across services

When Service A calls Service B, the trace ID must be included in the HTTP request. OpenTelemetry's auto-instrumentation handles this automatically for fetch, axios, and http calls — the W3C traceparent header is added without any extra code.

To extract the trace ID on the receiving side:

import { propagation, context, trace } from '@opentelemetry/api'

// Express middleware to extract incoming trace context
app.use((req, res, next) => {
  const extractedContext = propagation.extract(context.active(), req.headers)
  context.with(extractedContext, () => {
    const span = trace.getActiveSpan()
    req.traceId = span?.spanContext().traceId
    next()
  })
})

Step 5 — Send logs via OTLP

Alternatively, skip the SDK and send logs directly via OpenTelemetry's log format. LogFlow accepts OTLP/HTTP at https://api.getlogflow.com/v1/otlp/logs:

curl -X POST https://api.getlogflow.com/v1/otlp/logs \
  -H "Authorization: Bearer lf_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "resourceLogs": [{
      "resource": {
        "attributes": [{"key": "service.name", "value": {"stringValue": "payment-service"}}]
      },
      "scopeLogs": [{
        "logRecords": [{
          "timeUnixNano": "1715000000000000000",
          "severityNumber": 9,
          "severityText": "INFO",
          "body": {"stringValue": "Payment processed"},
          "attributes": [
            {"key": "traceId", "value": {"stringValue": "abc123"}},
            {"key": "orderId", "value": {"stringValue": "ord_456"}}
          ]
        }]
      }]
    }]
  }'

Viewing traces in LogFlow

After logs start arriving with trace_id fields:

  1. Open Logs Explorer and click any log line
  2. Find the trace_id field in the details panel
  3. Click View trace — LogFlow shows all logs with that trace ID
  4. Open Service Map to see which services this trace passed through

The TraceTimeline shows each log with relative timestamps so you can see exactly where time was spent.

FAQ

Does LogFlow store OpenTelemetry spans? Currently LogFlow stores the trace_id and span_id from spans as log attributes and uses them for correlation. Full span storage and waterfall views are on the roadmap.

What if I'm not using OpenTelemetry? You can add trace IDs manually. Generate a UUID at the entry point of each request and pass it to every log call and downstream HTTP request via a custom header like x-trace-id.

Does the Service Map work without OpenTelemetry? Yes. The Service Map builds edges from logs that include a service field — it doesn't require OTel. But OTel trace correlation adds the ability to click a node and see its traces.

Start monitoring your logs today

Free plan available. No credit card required. Up and running in 2 minutes.

Get started free