Langfuse instrumentation methods based on OpenTelemetry
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.
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');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');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();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');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);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();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);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);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);
});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
}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();
});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
});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();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();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;
}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
}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