Base class for node which OpenTelemetry instrumentation modules extend
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The auto-registration system provides centralized management for loading, configuring, and lifecycle control of multiple instrumentations with provider integration.
Main registration function that activates instrumentations and configures them with OpenTelemetry providers.
/**
* Register instrumentations and plugins with providers
* @param options Configuration options for registration
* @returns Function to unregister all instrumentations
*/
function registerInstrumentations(options: AutoLoaderOptions): () => void;Usage Example:
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { HttpInstrumentation } from "@opentelemetry/instrumentation-http";
import { ExpressInstrumentation } from "@opentelemetry/instrumentation-express";
import { trace, metrics } from "@opentelemetry/api";
import { logs } from "@opentelemetry/api-logs";
// Basic registration
const unregister = registerInstrumentations({
instrumentations: [
new HttpInstrumentation(),
new ExpressInstrumentation()
]
});
// Registration with custom providers
const unregisterWithProviders = registerInstrumentations({
instrumentations: [
new HttpInstrumentation({
requestHook: (span, request) => {
span.setAttributes({ 'http.custom': 'value' });
}
})
],
tracerProvider: trace.getTracerProvider(),
meterProvider: metrics.getMeterProvider(),
loggerProvider: logs.getLoggerProvider()
});
// Unregister when done
process.on('SIGTERM', () => {
unregister();
unregisterWithProviders();
});Configuration options for the registration system.
/**
* Options for registerInstrumentations function
*/
interface AutoLoaderOptions {
/** Array of instrumentations to register (can be nested arrays) */
instrumentations?: (Instrumentation | Instrumentation[])[];
/** Tracer provider to use (defaults to global provider) */
tracerProvider?: TracerProvider;
/** Meter provider to use (defaults to global provider) */
meterProvider?: MeterProvider;
/** Logger provider to use (defaults to global provider) */
loggerProvider?: LoggerProvider;
}Usage Examples:
// Minimal registration
registerInstrumentations({
instrumentations: [new HttpInstrumentation()]
});
// Registration with nested arrays
registerInstrumentations({
instrumentations: [
[new HttpInstrumentation(), new ExpressInstrumentation()],
new RedisInstrumentation(),
[new DatabaseInstrumentation(), new GraphQLInstrumentation()]
]
});
// Registration with all providers
registerInstrumentations({
instrumentations: [new HttpInstrumentation()],
tracerProvider: customTracerProvider,
meterProvider: customMeterProvider,
loggerProvider: customLoggerProvider
});
// Using global providers (default behavior)
registerInstrumentations({
instrumentations: [new HttpInstrumentation()]
// Providers will be obtained from:
// - trace.getTracerProvider()
// - metrics.getMeterProvider()
// - logs.getLoggerProvider()
});Result interface for auto-loader operations (used internally).
/**
* Result of auto-loader operations
*/
interface AutoLoaderResult {
/** Flattened array of all instrumentations */
instrumentations: Instrumentation[];
}Complete example showing instrumentation lifecycle management in an application.
Usage Example:
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { NodeSDK } from "@opentelemetry/auto-instrumentations-node";
class InstrumentationManager {
private unregisterFn?: () => void;
async initialize() {
// Configure and register instrumentations
this.unregisterFn = registerInstrumentations({
instrumentations: [
new HttpInstrumentation({
enabled: true,
requestHook: this.onHttpRequest.bind(this),
responseHook: this.onHttpResponse.bind(this)
}),
new ExpressInstrumentation({
enabled: true,
ignoreLayers: [
(name, info) => name === 'router' && info.request.url?.includes('/health')
]
})
]
});
console.log('Instrumentations registered');
}
async shutdown() {
if (this.unregisterFn) {
this.unregisterFn();
console.log('Instrumentations unregistered');
}
}
private onHttpRequest(span: Span, request: IncomingMessage) {
// Add custom attributes
span.setAttributes({
'http.request.custom': 'value',
'http.user_agent': request.headers['user-agent'] || 'unknown'
});
}
private onHttpResponse(span: Span, response: ServerResponse) {
// Add response attributes
span.setAttributes({
'http.response.custom': 'value'
});
}
}
// Application startup
const instrumentationManager = new InstrumentationManager();
await instrumentationManager.initialize();
// Graceful shutdown
process.on('SIGTERM', async () => {
await instrumentationManager.shutdown();
process.exit(0);
});Advanced patterns for conditional and dynamic instrumentation registration.
Usage Example:
import { registerInstrumentations } from "@opentelemetry/instrumentation";
class DynamicInstrumentationLoader {
private registrations: Map<string, () => void> = new Map();
registerByEnvironment() {
const environment = process.env.NODE_ENV || 'development';
// Base instrumentations for all environments
const baseInstrumentations = [
new HttpInstrumentation(),
new FsInstrumentation()
];
// Environment-specific instrumentations
const envInstrumentations: Instrumentation[] = [];
if (environment === 'production') {
envInstrumentations.push(
new RedisInstrumentation(),
new DatabaseInstrumentation()
);
}
if (environment === 'development') {
envInstrumentations.push(
new DebugInstrumentation({ verbose: true })
);
}
const unregister = registerInstrumentations({
instrumentations: [...baseInstrumentations, ...envInstrumentations]
});
this.registrations.set(environment, unregister);
return unregister;
}
registerConditionally() {
const instrumentations: Instrumentation[] = [];
// Register based on available modules
try {
require.resolve('express');
instrumentations.push(new ExpressInstrumentation());
} catch {
// Express not available
}
try {
require.resolve('redis');
instrumentations.push(new RedisInstrumentation());
} catch {
// Redis not available
}
if (instrumentations.length > 0) {
const unregister = registerInstrumentations({ instrumentations });
this.registrations.set('conditional', unregister);
return unregister;
}
}
unregisterAll() {
for (const [key, unregister] of this.registrations.entries()) {
unregister();
console.log(`Unregistered instrumentations for: ${key}`);
}
this.registrations.clear();
}
}Best practices for handling registration failures and instrumentation errors.
Usage Example:
import { registerInstrumentations } from "@opentelemetry/instrumentation";
import { diag, DiagConsoleLogger, DiagLogLevel } from "@opentelemetry/api";
// Enable diagnostic logging
diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.DEBUG);
function safeRegisterInstrumentations(instrumentations: Instrumentation[]) {
// Filter out any failed instrumentations
const validInstrumentations = instrumentations.filter(instrumentation => {
try {
// Basic validation
if (!instrumentation.instrumentationName || !instrumentation.instrumentationVersion) {
console.warn(`Invalid instrumentation: ${instrumentation.constructor.name}`);
return false;
}
return true;
} catch (error) {
console.error(`Failed to validate instrumentation: ${error}`);
return false;
}
});
if (validInstrumentations.length === 0) {
console.warn('No valid instrumentations to register');
return () => {}; // No-op unregister function
}
try {
const unregister = registerInstrumentations({
instrumentations: validInstrumentations
});
console.log(`Successfully registered ${validInstrumentations.length} instrumentations`);
return unregister;
} catch (error) {
console.error('Failed to register instrumentations:', error);
return () => {}; // No-op unregister function
}
}
// Usage with error handling
const instrumentations = [
new HttpInstrumentation(),
new ExpressInstrumentation(),
// This might fail if Redis is not available
new RedisInstrumentation()
];
const unregister = safeRegisterInstrumentations(instrumentations);Install with Tessl CLI
npx tessl i tessl/npm-opentelemetry--instrumentation