CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-langfuse--tracing

Langfuse instrumentation methods based on OpenTelemetry

Overview
Eval results
Files

tracer-provider.mddocs/

Tracer Provider

Tracer provider functions enable configuration of OpenTelemetry tracer instances for Langfuse tracing operations. These utilities allow you to isolate Langfuse tracing from other OpenTelemetry instrumentation in your application.

Core Functions

setLangfuseTracerProvider

Sets an isolated TracerProvider for Langfuse tracing operations, separate from the global OpenTelemetry TracerProvider.

/**
 * Sets an isolated TracerProvider for Langfuse tracing operations.
 *
 * This allows Langfuse to use its own TracerProvider instance, separate from
 * the global OpenTelemetry TracerProvider. This is useful for avoiding conflicts
 * with other OpenTelemetry instrumentation in the application.
 *
 * ⚠️  Limitation: Span Context Sharing
 *
 * While this function isolates span processing and export, it does NOT provide
 * complete trace isolation. OpenTelemetry context (trace IDs, parent spans) is
 * still shared between the global and isolated providers.
 *
 * @param provider - The TracerProvider instance to use, or null to clear
 */
function setLangfuseTracerProvider(provider: TracerProvider | null): void;

Usage:

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

// Create provider with Langfuse span processor
const langfuseProvider = new NodeTracerProvider({
  spanProcessors: [new LangfuseSpanProcessor()]
});

// Set as isolated provider for Langfuse
setLangfuseTracerProvider(langfuseProvider);

// Now all Langfuse tracing uses this provider
import { startObservation } from '@langfuse/tracing';
const span = startObservation('my-operation');

getLangfuseTracerProvider

Gets the TracerProvider for Langfuse tracing operations, returning the isolated provider if set, otherwise the global provider.

/**
 * Gets the TracerProvider for Langfuse tracing operations.
 *
 * Returns the isolated TracerProvider if one has been set via setLangfuseTracerProvider(),
 * otherwise falls back to the global OpenTelemetry TracerProvider.
 *
 * @returns The TracerProvider instance to use for Langfuse tracing
 */
function getLangfuseTracerProvider(): TracerProvider;

Usage:

import { getLangfuseTracerProvider } from '@langfuse/tracing';

const provider = getLangfuseTracerProvider();

// Use provider directly if needed
const tracer = provider.getTracer('my-tracer', '1.0.0');
const span = tracer.startSpan('custom-span');

getLangfuseTracer

Gets the OpenTelemetry tracer instance specifically configured for Langfuse with the correct tracer name and version.

/**
 * Gets the OpenTelemetry tracer instance for Langfuse.
 *
 * This function returns a tracer specifically configured for Langfuse
 * with the correct tracer name and version. Used internally by all
 * Langfuse tracing functions to ensure consistent trace creation.
 *
 * @returns The Langfuse OpenTelemetry tracer instance
 */
function getLangfuseTracer(): Tracer;

Usage:

import { getLangfuseTracer } from '@langfuse/tracing';

const tracer = getLangfuseTracer();

// Create custom span using Langfuse tracer
const span = tracer.startSpan('custom-operation', {
  startTime: new Date()
});

// Perform operation
span.setAttributes({
  'custom.attribute': 'value'
});

span.end();

Use Cases

Isolating Langfuse Tracing

Separate Langfuse traces from other OpenTelemetry instrumentation in your application.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { setLangfuseTracerProvider } from '@langfuse/tracing';
import { trace } from '@opentelemetry/api';

// Global provider for general application tracing
const globalProvider = new NodeTracerProvider();
globalProvider.addSpanProcessor(
  new BatchSpanProcessor(new OTLPTraceExporter({
    url: 'https://your-otel-collector.com/v1/traces'
  }))
);
trace.setGlobalTracerProvider(globalProvider);

// Isolated provider for Langfuse tracing
const langfuseProvider = new NodeTracerProvider({
  spanProcessors: [
    new LangfuseSpanProcessor({
      publicKey: process.env.LANGFUSE_PUBLIC_KEY,
      secretKey: process.env.LANGFUSE_SECRET_KEY
    })
  ]
});

setLangfuseTracerProvider(langfuseProvider);

// Now application traces go to OTLP, Langfuse traces go to Langfuse
import { startObservation } from '@langfuse/tracing';
const langfuseSpan = startObservation('langfuse-operation');

const appTracer = trace.getTracer('app');
const appSpan = appTracer.startSpan('app-operation');

Multiple Span Processors

Configure multiple span processors for Langfuse provider.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { BatchSpanProcessor, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { ConsoleSpanExporter } from '@opentelemetry/sdk-trace-base';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

const provider = new NodeTracerProvider();

// Add Langfuse processor
provider.addSpanProcessor(
  new LangfuseSpanProcessor({
    publicKey: process.env.LANGFUSE_PUBLIC_KEY,
    secretKey: process.env.LANGFUSE_SECRET_KEY,
    baseUrl: 'https://cloud.langfuse.com'
  })
);

// Add console exporter for debugging
if (process.env.DEBUG) {
  provider.addSpanProcessor(
    new SimpleSpanProcessor(new ConsoleSpanExporter())
  );
}

setLangfuseTracerProvider(provider);

Environment-Based Configuration

Configure tracer provider based on environment.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

function configureLangfuseTracing() {
  if (process.env.LANGFUSE_ENABLED !== 'true') {
    // Disable Langfuse tracing
    setLangfuseTracerProvider(null);
    return;
  }

  const provider = new NodeTracerProvider({
    spanProcessors: [
      new LangfuseSpanProcessor({
        publicKey: process.env.LANGFUSE_PUBLIC_KEY,
        secretKey: process.env.LANGFUSE_SECRET_KEY,
        baseUrl: process.env.LANGFUSE_BASE_URL,
        flushAt: process.env.NODE_ENV === 'production' ? 15 : 1,
        flushInterval: process.env.NODE_ENV === 'production' ? 10000 : 1000
      })
    ]
  });

  setLangfuseTracerProvider(provider);
}

configureLangfuseTracing();

Custom Sampling

Implement custom sampling strategies for Langfuse traces.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { ParentBasedSampler, TraceIdRatioBasedSampler } from '@opentelemetry/sdk-trace-base';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

// Sample 10% of traces in production, 100% in development
const samplingRatio = process.env.NODE_ENV === 'production' ? 0.1 : 1.0;

const provider = new NodeTracerProvider({
  sampler: new ParentBasedSampler({
    root: new TraceIdRatioBasedSampler(samplingRatio)
  }),
  spanProcessors: [
    new LangfuseSpanProcessor({
      publicKey: process.env.LANGFUSE_PUBLIC_KEY,
      secretKey: process.env.LANGFUSE_SECRET_KEY
    })
  ]
});

setLangfuseTracerProvider(provider);

Custom Resource Attributes

Add custom resource attributes to all Langfuse traces.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { Resource } from '@opentelemetry/resources';
import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

const provider = new NodeTracerProvider({
  resource: new Resource({
    [SemanticResourceAttributes.SERVICE_NAME]: 'my-ai-service',
    [SemanticResourceAttributes.SERVICE_VERSION]: '1.2.3',
    [SemanticResourceAttributes.DEPLOYMENT_ENVIRONMENT]: process.env.NODE_ENV,
    'custom.attribute': 'custom-value'
  }),
  spanProcessors: [
    new LangfuseSpanProcessor({
      publicKey: process.env.LANGFUSE_PUBLIC_KEY,
      secretKey: process.env.LANGFUSE_SECRET_KEY
    })
  ]
});

setLangfuseTracerProvider(provider);

Graceful Shutdown

Properly shutdown tracer provider on application exit.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider, getLangfuseTracerProvider } from '@langfuse/tracing';

const provider = new NodeTracerProvider({
  spanProcessors: [
    new LangfuseSpanProcessor({
      publicKey: process.env.LANGFUSE_PUBLIC_KEY,
      secretKey: process.env.LANGFUSE_SECRET_KEY
    })
  ]
});

setLangfuseTracerProvider(provider);

// Graceful shutdown
async function shutdown() {
  const provider = getLangfuseTracerProvider();

  if (provider && 'shutdown' in provider) {
    await (provider as NodeTracerProvider).shutdown();
    console.log('Tracer provider shut down successfully');
  }
}

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

process.on('SIGINT', async () => {
  await shutdown();
  process.exit(0);
});

Testing Configuration

Configure different providers for testing environments.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { InMemorySpanExporter, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

function setupTracingForTesting() {
  if (process.env.NODE_ENV === 'test') {
    // Use in-memory exporter for tests
    const exporter = new InMemorySpanExporter();
    const provider = new NodeTracerProvider({
      spanProcessors: [new SimpleSpanProcessor(exporter)]
    });

    setLangfuseTracerProvider(provider);

    // Return exporter for assertions in tests
    return exporter;
  } else {
    // Production configuration
    const provider = new NodeTracerProvider({
      spanProcessors: [
        new LangfuseSpanProcessor({
          publicKey: process.env.LANGFUSE_PUBLIC_KEY,
          secretKey: process.env.LANGFUSE_SECRET_KEY
        })
      ]
    });

    setLangfuseTracerProvider(provider);
    return null;
  }
}

const testExporter = setupTracingForTesting();

// In tests
if (testExporter) {
  const spans = testExporter.getFinishedSpans();
  // Assert on captured spans
}

Advanced Patterns

Provider Registry

Manage multiple tracer providers for different purposes.

import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

class TracerProviderRegistry {
  private providers: Map<string, NodeTracerProvider> = new Map();

  register(name: string, provider: NodeTracerProvider) {
    this.providers.set(name, provider);
  }

  get(name: string): NodeTracerProvider | undefined {
    return this.providers.get(name);
  }

  async shutdownAll() {
    for (const [name, provider] of this.providers) {
      await provider.shutdown();
      console.log(`Shutdown provider: ${name}`);
    }
  }
}

const registry = new TracerProviderRegistry();

// Register Langfuse provider
const langfuseProvider = new NodeTracerProvider({
  spanProcessors: [new LangfuseSpanProcessor()]
});
registry.register('langfuse', langfuseProvider);
setLangfuseTracerProvider(langfuseProvider);

// Shutdown all on exit
process.on('SIGTERM', async () => {
  await registry.shutdownAll();
});

Dynamic Provider Switching

Switch tracer providers based on runtime conditions.

import { getLangfuseTracerProvider, setLangfuseTracerProvider } from '@langfuse/tracing';

let currentProvider: NodeTracerProvider | null = null;

async function switchProvider(config: {
  publicKey: string;
  secretKey: string;
  baseUrl?: string;
}) {
  // Shutdown current provider
  if (currentProvider) {
    await currentProvider.shutdown();
  }

  // Create new provider
  const provider = new NodeTracerProvider({
    spanProcessors: [
      new LangfuseSpanProcessor({
        publicKey: config.publicKey,
        secretKey: config.secretKey,
        baseUrl: config.baseUrl
      })
    ]
  });

  setLangfuseTracerProvider(provider);
  currentProvider = provider;

  console.log('Switched to new tracer provider');
}

// Switch providers at runtime
await switchProvider({
  publicKey: process.env.NEW_PUBLIC_KEY,
  secretKey: process.env.NEW_SECRET_KEY
});

Context Sharing Limitation

The isolated tracer provider shares OpenTelemetry context with the global provider.

import { trace } from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { setLangfuseTracerProvider } from '@langfuse/tracing';
import { startObservation } from '@langfuse/tracing';

// Setup isolated Langfuse provider
const langfuseProvider = new NodeTracerProvider();
setLangfuseTracerProvider(langfuseProvider);

// Setup global provider
const globalProvider = new NodeTracerProvider();
trace.setGlobalTracerProvider(globalProvider);

// Create global span
const globalTracer = trace.getTracer('global');
const globalSpan = globalTracer.startSpan('global-operation');

// Set global span as active
const ctx = trace.setSpan(trace.context.active(), globalSpan);

// Langfuse span created within global span context
trace.context.with(ctx, () => {
  // This Langfuse span inherits the trace ID from globalSpan
  const langfuseSpan = startObservation('langfuse-operation');
  console.log('Same trace ID:', langfuseSpan.traceId === globalSpan.spanContext().traceId);
  langfuseSpan.end();
});

globalSpan.end();

Best Practices

Initialize Early

Set up the tracer provider early in application lifecycle, before creating any observations.

// app.ts or index.ts
import { initializeLangfuseTracing } from './tracing-setup';

// Initialize before any imports that use tracing
initializeLangfuseTracing();

// Now import and use application code
import { startServer } from './server';
startServer();

Single Provider Instance

Create only one tracer provider instance for Langfuse in your application.

// tracing-config.ts
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { LangfuseSpanProcessor } from '@langfuse/otel';
import { setLangfuseTracerProvider } from '@langfuse/tracing';

let providerInitialized = false;

export function initializeLangfuseTracing() {
  if (providerInitialized) {
    console.warn('Langfuse tracer provider already initialized');
    return;
  }

  const provider = new NodeTracerProvider({
    spanProcessors: [new LangfuseSpanProcessor()]
  });

  setLangfuseTracerProvider(provider);
  providerInitialized = true;
}

Configuration Validation

Validate configuration before creating provider.

function validateConfig() {
  const required = ['LANGFUSE_PUBLIC_KEY', 'LANGFUSE_SECRET_KEY'];
  const missing = required.filter(key => !process.env[key]);

  if (missing.length > 0) {
    throw new Error(`Missing required env vars: ${missing.join(', ')}`);
  }
}

try {
  validateConfig();

  const provider = new NodeTracerProvider({
    spanProcessors: [
      new LangfuseSpanProcessor({
        publicKey: process.env.LANGFUSE_PUBLIC_KEY!,
        secretKey: process.env.LANGFUSE_SECRET_KEY!
      })
    ]
  });

  setLangfuseTracerProvider(provider);
} catch (error) {
  console.error('Failed to initialize Langfuse tracing:', error);
  // Decide whether to exit or continue without tracing
}

Proper Cleanup

Always register shutdown handlers for tracer providers.

import { getLangfuseTracerProvider } from '@langfuse/tracing';

async function gracefulShutdown(signal: string) {
  console.log(`Received ${signal}, shutting down gracefully`);

  const provider = getLangfuseTracerProvider();
  if (provider && 'shutdown' in provider) {
    try {
      await (provider as NodeTracerProvider).shutdown();
      console.log('Tracer provider shut down successfully');
    } catch (error) {
      console.error('Error shutting down tracer provider:', error);
    }
  }

  process.exit(0);
}

process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
process.on('SIGINT', () => gracefulShutdown('SIGINT'));

Install with Tessl CLI

npx tessl i tessl/npm-langfuse--tracing

docs

active-observations.md

attribute-creation.md

context-management.md

index.md

manual-observations.md

observation-types.md

observe-decorator.md

otel-span-attributes.md

trace-id-generation.md

tracer-provider.md

tile.json