CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-opentelemetry--instrumentation

Base class for node which OpenTelemetry instrumentation modules extend

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

auto-registration.mddocs/

Auto-Registration

The auto-registration system provides centralized management for loading, configuring, and lifecycle control of multiple instrumentations with provider integration.

Capabilities

registerInstrumentations Function

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();
});

AutoLoaderOptions Interface

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()
});

AutoLoaderResult Interface

Result interface for auto-loader operations (used internally).

/**
 * Result of auto-loader operations
 */
interface AutoLoaderResult {
  /** Flattened array of all instrumentations */
  instrumentations: Instrumentation[];
}

Lifecycle Management

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);
});

Dynamic Registration

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();
  }
}

Error Handling and Resilience

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

docs

auto-registration.md

base-instrumentation.md

index.md

module-definitions.md

semconv-stability.md

utilities.md

tile.json