Skip to content

Exporters ​

Send traces to various observability backends.

Overview ​

OTLP Exporter ​

Recommended for production. OpenTelemetry Protocol is vendor-neutral.

Installation ​

bash
npm install @opentelemetry/exporter-trace-otlp-http

Configuration ​

typescript
import { TracingPlugin } from '@nestjs-redisx/tracing';

new TracingPlugin({
  serviceName: 'user-service',
  exporter: {
    type: 'otlp',
    endpoint: 'http://localhost:4318',
  },
})

With Custom Headers ​

typescript
{
  exporter: {
    type: 'otlp',
    endpoint: 'http://collector:4318',
    headers: {
      'x-api-key': process.env.TRACING_API_KEY,
      'x-tenant-id': 'my-tenant',
    },
  }
}

Docker Compose Setup ​

yaml
# docker-compose.yml
version: '3.8'

services:
  app:
    build: .
    environment:
      - OTLP_ENDPOINT=http://jaeger:4318
    depends_on:
      - jaeger

  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686"  # UI
      - "4318:4318"    # OTLP HTTP
    environment:
      - COLLECTOR_OTLP_ENABLED=true

Kubernetes Setup ​

yaml
# deployment.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: tracing-config
data:
  OTLP_ENDPOINT: "http://otel-collector:4318"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  template:
    spec:
      containers:
        - name: app
          envFrom:
            - configMapRef:
                name: tracing-config

Jaeger Exporter ​

Export to Jaeger via OTLP. Internally uses the same OTLP exporter — point to your Jaeger OTLP endpoint.

Configuration ​

typescript
{
  exporter: {
    type: 'jaeger',
    endpoint: 'http://jaeger:4318/v1/traces',
  }
}

Docker Compose ​

yaml
jaeger:
  image: jaegertracing/all-in-one:latest
  ports:
    - "16686:16686"  # UI
    - "14268:14268"  # HTTP collector
    - "6831:6831/udp"  # UDP agent

Access Jaeger UI ​

http://localhost:16686

Features:

  • Search traces by service, operation, tags
  • Trace timeline visualization
  • Service dependencies graph
  • Performance analytics

Zipkin Exporter ​

Export to Zipkin-compatible backends via OTLP. Internally uses the same OTLP exporter.

Configuration ​

typescript
{
  exporter: {
    type: 'zipkin',
    endpoint: 'http://zipkin:9411/api/v2/spans',
  }
}

Docker Compose ​

yaml
zipkin:
  image: openzipkin/zipkin:latest
  ports:
    - "9411:9411"

Access Zipkin UI ​

http://localhost:9411

Console Exporter ​

Development debugging - prints spans to console.

Configuration ​

typescript
{
  exporter: {
    type: 'console',
  }
}

Output ​

json
{
  "traceId": "7f9c8a3b2e1d4c5a6b7e8f9a0b1c2d3e",
  "spanId": "1a2b3c4d5e6f7g8h",
  "name": "redis.GET",
  "kind": "CLIENT",
  "timestamp": 1706123456789000,
  "duration": 1234567,
  "attributes": {
    "db.system": "redis",
    "db.operation": "GET",
    "db.redis.key": "user:123"
  },
  "status": {
    "code": "OK"
  }
}

Use cases:

  • Local development
  • CI/CD debugging
  • Quick testing

Grafana Tempo ​

Store traces in Grafana Tempo via OTLP.

Docker Compose ​

yaml
version: '3.8'

services:
  tempo:
    image: grafana/tempo:latest
    ports:
      - "4318:4318"  # OTLP HTTP
      - "3200:3200"  # Tempo UI
    volumes:
      - ./tempo.yaml:/etc/tempo.yaml
    command: ["-config.file=/etc/tempo.yaml"]

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_AUTH_ANONYMOUS_ENABLED=true
      - GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
    volumes:
      - ./grafana-datasources.yaml:/etc/grafana/provisioning/datasources/datasources.yaml

Tempo Configuration ​

yaml
# tempo.yaml
server:
  http_listen_port: 3200

distributor:
  receivers:
    otlp:
      protocols:
        http:
          endpoint: 0.0.0.0:4318

storage:
  trace:
    backend: local
    local:
      path: /tmp/tempo/blocks

Grafana Data Source ​

yaml
# grafana-datasources.yaml
apiVersion: 1

datasources:
  - name: Tempo
    type: tempo
    access: proxy
    url: http://tempo:3200

Application Configuration ​

typescript
{
  exporter: {
    type: 'otlp',
    endpoint: 'http://tempo:4318',
  }
}

Multiple Exporters ​

Export to multiple backends simultaneously.

Setup ​

typescript
import { BatchSpanProcessor, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';

const provider = new NodeTracerProvider();

// OTLP to production
provider.addSpanProcessor(
  new BatchSpanProcessor(
    new OTLPTraceExporter({
      url: 'http://collector:4318/v1/traces',
    }),
  ),
);

// Console for debugging
if (process.env.NODE_ENV === 'development') {
  provider.addSpanProcessor(
    new SimpleSpanProcessor(new ConsoleSpanExporter()),
  );
}

provider.register();

Cloud Providers ​

AWS X-Ray ​

bash
npm install @opentelemetry/propagator-aws-xray
typescript
import { AWSXRayPropagator } from '@opentelemetry/propagator-aws-xray';
import { AWSXRayIdGenerator } from '@opentelemetry/id-generator-aws-xray';

const sdk = new NodeSDK({
  textMapPropagator: new AWSXRayPropagator(),
  idGenerator: new AWSXRayIdGenerator(),
  traceExporter: new OTLPTraceExporter({
    url: 'https://YOUR_REGION.amazonaws.com/v1/traces',
  }),
});

Google Cloud Trace ​

bash
npm install @google-cloud/opentelemetry-cloud-trace-exporter
typescript
import { TraceExporter } from '@google-cloud/opentelemetry-cloud-trace-exporter';

const exporter = new TraceExporter({
  projectId: 'your-gcp-project',
});

Azure Monitor ​

bash
npm install @azure/monitor-opentelemetry-exporter
typescript
import { AzureMonitorTraceExporter } from '@azure/monitor-opentelemetry-exporter';

const exporter = new AzureMonitorTraceExporter({
  connectionString: process.env.APPLICATIONINSIGHTS_CONNECTION_STRING,
});

Commercial Platforms ​

Datadog ​

bash
npm install @opentelemetry/exporter-trace-otlp-http
typescript
{
  exporter: {
    type: 'otlp',
    endpoint: 'https://trace.agent.datadoghq.com/v1/traces',
    headers: {
      'DD-API-KEY': process.env.DATADOG_API_KEY,
    },
  }
}

New Relic ​

typescript
{
  exporter: {
    type: 'otlp',
    endpoint: 'https://otlp.nr-data.net:4318/v1/traces',
    headers: {
      'api-key': process.env.NEW_RELIC_LICENSE_KEY,
    },
  }
}

Honeycomb ​

typescript
{
  exporter: {
    type: 'otlp',
    endpoint: 'https://api.honeycomb.io/v1/traces',
    headers: {
      'x-honeycomb-team': process.env.HONEYCOMB_API_KEY,
      'x-honeycomb-dataset': 'my-service',
    },
  }
}

Exporter Comparison ​

ExporterUse CaseProsCons
OTLPProductionVendor-neutral, future-proofRequires collector
JaegerDevelopmentEasy setup, good UIUses OTLP internally
ZipkinLegacy systemsWide supportUses OTLP internally
ConsoleDebuggingNo infrastructure neededNot for production

INFO

All exporter types except 'console' use OTLPTraceExporter internally. The type field mainly serves as semantic labeling — you must configure the appropriate endpoint for your backend.

Performance Considerations ​

Batch Size ​

typescript
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';

const processor = new BatchSpanProcessor(exporter, {
  maxQueueSize: 2048,          // Queue size
  maxExportBatchSize: 512,     // Batch size
  scheduledDelayMillis: 5000,  // Export interval
  exportTimeoutMillis: 30000,  // Timeout
});

High traffic:

  • Increase maxQueueSize
  • Increase maxExportBatchSize
  • Reduce scheduledDelayMillis

Low traffic:

  • Decrease maxExportBatchSize
  • Increase scheduledDelayMillis

Troubleshooting ​

Spans not appearing ​

bash
# Check exporter endpoint
curl http://localhost:4318/v1/traces

# Check logs
docker logs <container-id>

Authentication errors ​

typescript
{
  exporter: {
    headers: {
      'authorization': `Bearer ${process.env.API_TOKEN}`,
    },
  }
}

Next Steps ​

Released under the MIT License.