OpenTelemetry Migration

This guide covers migrating from existing OpenTelemetry setups to LangWatch while maintaining all your custom configurations, instrumentations, and advanced features.

Overview

The LangWatch observability SDK is built on OpenTelemetry and passes through all NodeSDK configuration options, making it easy to migrate from existing OpenTelemetry setups while maintaining all your custom configuration.
LangWatch supports all OpenTelemetry NodeSDK configuration options, so you can migrate without losing any functionality or custom settings.
For consistent attribute naming and semantic conventions, see our Semantic Conventions guide which covers both OpenTelemetry standards and LangWatch’s custom attributes.

Complete NodeSDK Configuration

LangWatch supports all OpenTelemetry NodeSDK configuration options:
import { setupObservability } from "langwatch/observability/setup/node";
import { TraceIdRatioBasedSampler } from "@opentelemetry/sdk-trace-base";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { W3CTraceContextPropagator } from "@opentelemetry/core";
import { envDetector, processDetector, hostDetector } from "@opentelemetry/resources";

const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY,
    processorType: 'batch'
  },
  serviceName: "my-service",
  
  // All NodeSDK options are supported
  autoDetectResources: true,
  contextManager: undefined, // Use default
  textMapPropagator: new W3CTraceContextPropagator(),
  resourceDetectors: [envDetector, processDetector, hostDetector],
  
  // Sampling strategy
  sampler: new TraceIdRatioBasedSampler(0.1), // Sample 10% of traces
  
  // Span limits
  spanLimits: {
    attributeCountLimit: 128,
    eventCountLimit: 128,
    linkCountLimit: 128
  },
  
  // Auto-instrumentations
  instrumentations: [
    new HttpInstrumentation(),
    // Add other instrumentations as needed
  ],
  
  // Advanced options
  advanced: {
    throwOnSetupError: false, // Don't throw on setup errors
    skipOpenTelemetrySetup: false, // Handle setup yourself
    UNSAFE_forceOpenTelemetryReinitialization: false // Force reinit (dangerous)
  }
});

Migration Example: From NodeSDK to LangWatch

1

Before: Direct NodeSDK Usage

import { NodeSDK } from "@opentelemetry/sdk-node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { JaegerExporter } from "@opentelemetry/exporter-jaeger";

const sdk = new NodeSDK({
  serviceName: "my-service",
  spanProcessors: [
    new BatchSpanProcessor(new JaegerExporter())
  ],
  instrumentations: [new HttpInstrumentation()],
  sampler: new TraceIdRatioBasedSampler(0.1),
  spanLimits: { attributeCountLimit: 128 }
});

sdk.start();
2

After: Using LangWatch with Same Configuration

import { setupObservability } from "langwatch/observability/setup/node";
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
import { JaegerExporter } from "@opentelemetry/exporter-jaeger";

const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY
  },
  serviceName: "my-service",
  spanProcessors: [
    new BatchSpanProcessor(new JaegerExporter())
  ],
  instrumentations: [new HttpInstrumentation()],
  sampler: new TraceIdRatioBasedSampler(0.1),
  spanLimits: { attributeCountLimit: 128 }
});

// Graceful shutdown
process.on('SIGTERM', async () => {
  await handle.shutdown();
  process.exit(0);
});

Advanced Sampling Strategies

Implement sophisticated sampling strategies for different use cases:
import { TraceIdRatioBasedSampler, ParentBasedSampler } from "@opentelemetry/sdk-trace-base";

// Sample based on trace ID ratio
const ratioSampler = new TraceIdRatioBasedSampler(0.1); // 10% sampling

// Parent-based sampling (respect parent span sampling decision)
const parentBasedSampler = new ParentBasedSampler({
  root: ratioSampler,
  remoteParentSampled: new AlwaysOnSampler(),
  remoteParentNotSampled: new AlwaysOffSampler(),
  localParentSampled: new AlwaysOnSampler(),
  localParentNotSampled: new AlwaysOffSampler(),
});

const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY
  },
  serviceName: "my-service",
  sampler: parentBasedSampler
});

Custom Resource Detection

Configure custom resource detection for better service identification:
import { Resource } from "@opentelemetry/resources";
import { SemanticResourceAttributes } from "@opentelemetry/semantic-conventions";

const customResource = new Resource({
  [SemanticResourceAttributes.SERVICE_NAME]: "my-service",
  [SemanticResourceAttributes.SERVICE_VERSION]: "1.0.0",
  [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV,
  "custom.team": "ai-platform",
  "custom.datacenter": "us-west-2"
});

const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY
  },
  serviceName: "my-service",
  resource: customResource
});
For consistent attribute naming and TypeScript autocomplete support, consider using LangWatch’s semantic conventions. See our Semantic Conventions guide for details.

Custom Instrumentations

Add custom instrumentations for specific libraries or frameworks:
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
import { MongoDBInstrumentation } from "@opentelemetry/instrumentation-mongodb";

const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY
  },
  serviceName: "my-service",
  instrumentations: [
    new HttpInstrumentation({
      ignoreIncomingPaths: ['/health', '/metrics'],
      ignoreOutgoingUrls: ['https://external-service.com/health']
    }),
    new ExpressInstrumentation(),
    new MongoDBInstrumentation()
  ]
});

Context Propagation Configuration

Configure custom context propagation for distributed tracing:
import { W3CTraceContextPropagator, W3CBaggagePropagator } from "@opentelemetry/core";
import { CompositePropagator } from "@opentelemetry/core";

const compositePropagator = new CompositePropagator({
  propagators: [
    new W3CTraceContextPropagator(),
    new W3CBaggagePropagator()
  ]
});

const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY
  },
  serviceName: "my-service",
  textMapPropagator: compositePropagator
});

Environment-Specific Configuration

Create different configurations for different environments:
const getObservabilityConfig = (environment: string) => {
  const baseConfig = {
    serviceName: "my-service",
    langwatch: {
      apiKey: process.env.LANGWATCH_API_KEY
    }
  };

  switch (environment) {
    case 'development':
      return {
        ...baseConfig,
        langwatch: {
          ...baseConfig.langwatch,
          processorType: 'simple'
        },
        debug: {
          consoleTracing: true,
          logLevel: 'debug'
        }
      };
    
    case 'staging':
      return {
        ...baseConfig,
        langwatch: {
          ...baseConfig.langwatch,
          processorType: 'batch'
        },
        sampler: new TraceIdRatioBasedSampler(0.5), // 50% sampling
        debug: {
          consoleTracing: false,
          logLevel: 'info'
        }
      };
    
    case 'production':
      return {
        ...baseConfig,
        langwatch: {
          ...baseConfig.langwatch,
          processorType: 'batch'
        },
        sampler: new TraceIdRatioBasedSampler(0.1), // 10% sampling
        debug: {
          consoleTracing: false,
          logLevel: 'warn'
        }
      };
    
    default:
      return baseConfig;
  }
};

const handle = await setupObservability(
  getObservabilityConfig(process.env.NODE_ENV)
);

Performance Tuning

Optimize performance for high-volume applications:
const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY,
    processorType: 'batch'
  },
  serviceName: "my-service",
  
  // Performance tuning
  spanLimits: {
    attributeCountLimit: 64, // Reduce attribute count
    eventCountLimit: 32,     // Reduce event count
    linkCountLimit: 32       // Reduce link count
  },
  
  // Sampling for high volume
  sampler: new TraceIdRatioBasedSampler(0.05), // 5% sampling
  
  // Batch processing configuration
  spanProcessors: [
    new BatchSpanProcessor(new LangWatchExporter({
      apiKey: process.env.LANGWATCH_API_KEY
    }), {
      maxQueueSize: 4096,
      maxExportBatchSize: 1024,
      scheduledDelayMillis: 1000,
      exportTimeoutMillis: 30000
    })
  ]
});

Migration Checklist

1

Inventory Current Setup

Document all current instrumentations, exporters, and configurations in your OpenTelemetry setup.
2

Test in Development

Start with development environment migration to validate the configuration.
3

Verify Data Flow

Ensure traces are appearing in LangWatch dashboard with correct attributes and structure.
4

Performance Testing

Monitor application performance impact and adjust sampling/processing settings as needed.
5

Gradual Rollout

Migrate environments one at a time, starting with staging before production.
6

Fallback Plan

Keep existing OpenTelemetry setup as backup during transition period.
7

Documentation

Update team documentation and runbooks with new observability configuration.

Troubleshooting Migration Issues

Common Migration Problems

Debugging Migration

Enable detailed logging during migration to identify issues:
// Enable detailed logging during migration
const handle = await setupObservability({
  langwatch: {
    apiKey: process.env.LANGWATCH_API_KEY
  },
  serviceName: "my-service",
  debug: {
    consoleTracing: true,
    consoleLogging: true,
    logLevel: 'debug'
  },
  advanced: {
    throwOnSetupError: true
  }
});

Migration Benefits

Zero Configuration Loss

All your existing OpenTelemetry configurations, instrumentations, and custom settings are preserved.

Enhanced Features

Gain access to LangWatch’s specialized LLM observability features while keeping your existing setup.

Gradual Migration

Migrate at your own pace with the ability to run both systems in parallel during transition.

Production Ready

LangWatch is built on OpenTelemetry standards, ensuring production-grade reliability and performance.
The migration process is designed to be non-disruptive. You can run your existing OpenTelemetry setup alongside LangWatch during the transition period to ensure everything works correctly.