Base class for node which OpenTelemetry instrumentation modules extend
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Utility functions for safe execution, function wrapping detection, and error handling in instrumentation code.
Functions for executing code safely with error handling and recovery mechanisms.
/**
* Execute function safely with error handling
* @param execute Function to execute
* @param onFinish Callback executed after completion (success or failure)
* @param preventThrowingError If true, prevents rethrowing errors
* @returns Result of execution
*/
function safeExecuteInTheMiddle<T>(
execute: () => T,
onFinish: (e: Error | undefined, result: T | undefined) => void,
preventThrowingError?: boolean
): T;
/**
* Execute async function safely with error handling
* @param execute Async function to execute
* @param onFinish Callback executed after completion (success or failure)
* @param preventThrowingError If true, prevents rethrowing errors
* @returns Promise with result of execution
*/
function safeExecuteInTheMiddleAsync<T>(
execute: () => T,
onFinish: (e: Error | undefined, result: T | undefined) => void,
preventThrowingError?: boolean
): Promise<T>;Usage Examples:
import { safeExecuteInTheMiddle, safeExecuteInTheMiddleAsync } from "@opentelemetry/instrumentation";
// Synchronous safe execution
const result = safeExecuteInTheMiddle(
() => {
// Potentially risky operation
return JSON.parse(someJsonString);
},
(error, result) => {
if (error) {
console.error('JSON parsing failed:', error);
// Log or handle error
} else {
console.log('JSON parsed successfully:', result);
}
},
true // Prevent throwing error, handle gracefully
);
// Asynchronous safe execution
const asyncResult = await safeExecuteInTheMiddleAsync(
async () => {
// Potentially risky async operation
const response = await fetch('https://api.example.com/data');
return response.json();
},
(error, result) => {
if (error) {
console.error('API request failed:', error);
// Could emit metrics or traces here
} else {
console.log('API request successful');
}
}
);
// Use in instrumentation context
class HttpInstrumentation extends InstrumentationBase {
private _patchRequest(original: Function) {
const instrumentation = this;
return function(this: any, ...args: any[]) {
return safeExecuteInTheMiddle(
() => {
// Create span and add instrumentation
const span = instrumentation.tracer.startSpan('http.request');
const result = original.apply(this, args);
span.end();
return result;
},
(error, result) => {
if (error) {
instrumentation._diag.error('Failed to instrument HTTP request:', error);
}
},
true // Don't break original functionality on instrumentation errors
);
};
}
}Utility to check if a function has been wrapped by the shimmer library.
/**
* Check if a function has been wrapped by shimmer
* @param func Function to check
* @returns True if function is wrapped
*/
function isWrapped(func: unknown): func is ShimWrapped;
/**
* Interface for wrapped functions with shimmer metadata
*/
interface ShimWrapped extends Function {
/** Indicates the function is wrapped */
__wrapped: boolean;
/** Unwrap function to restore original */
__unwrap: Function;
/** Reference to original function */
__original: Function;
}Usage Examples:
import { isWrapped } from "@opentelemetry/instrumentation";
import * as shimmer from "shimmer";
class InstrumentationExample extends InstrumentationBase {
enable() {
const http = require('http');
// Check if already wrapped to avoid double-wrapping
if (!isWrapped(http.request)) {
shimmer.wrap(http, 'request', this._wrapRequest.bind(this));
} else {
this._diag.debug('http.request is already wrapped');
}
}
disable() {
const http = require('http');
// Only unwrap if it's actually wrapped
if (isWrapped(http.request)) {
shimmer.unwrap(http, 'request');
}
}
private _inspectWrapping() {
const http = require('http');
if (isWrapped(http.request)) {
const wrapped = http.request as ShimWrapped;
console.log('Function is wrapped:', wrapped.__wrapped);
console.log('Original function available:', typeof wrapped.__original);
console.log('Unwrap function available:', typeof wrapped.__unwrap);
// Could access original if needed
const originalRequest = wrapped.__original;
}
}
private _conditionalWrap(target: any, property: string, wrapper: Function) {
// Defensive wrapping pattern
if (target && typeof target[property] === 'function') {
if (!isWrapped(target[property])) {
shimmer.wrap(target, property, wrapper);
this._diag.debug(`Wrapped ${property}`);
} else {
this._diag.debug(`${property} already wrapped, skipping`);
}
} else {
this._diag.warn(`Cannot wrap ${property}: not a function or target invalid`);
}
}
}Advanced patterns for instrumentation error handling and recovery.
Usage Examples:
import { safeExecuteInTheMiddle } from "@opentelemetry/instrumentation";
class RobustInstrumentation extends InstrumentationBase {
private _metrics = {
instrumentationErrors: this.meter.createCounter('instrumentation_errors_total'),
executionTime: this.meter.createHistogram('instrumentation_execution_duration')
};
private _safeWrap(target: any, property: string, wrapper: Function) {
return safeExecuteInTheMiddle(
() => {
const original = target[property];
if (typeof original !== 'function') {
throw new Error(`${property} is not a function`);
}
target[property] = wrapper(original);
return target[property];
},
(error, result) => {
if (error) {
this._metrics.instrumentationErrors.add(1, {
operation: 'wrap',
target: property,
error: error.message
});
this._diag.error(`Failed to wrap ${property}:`, error);
} else {
this._diag.debug(`Successfully wrapped ${property}`);
}
},
true // Don't throw, allow application to continue
);
}
private _createTimedWrapper(name: string, original: Function) {
const instrumentation = this;
return function(this: any, ...args: any[]) {
const startTime = Date.now();
return safeExecuteInTheMiddle(
() => {
// Execute original with instrumentation
const span = instrumentation.tracer.startSpan(`${name}.call`);
try {
const result = original.apply(this, args);
span.setStatus({ code: 1 }); // OK
return result;
} catch (error) {
span.recordException(error as Error);
span.setStatus({ code: 2, message: (error as Error).message }); // ERROR
throw error;
} finally {
span.end();
}
},
(error, result) => {
const duration = Date.now() - startTime;
instrumentation._metrics.executionTime.record(duration, {
operation: name,
success: error ? 'false' : 'true'
});
if (error) {
instrumentation._diag.error(`Error in ${name}:`, error);
}
}
);
};
}
}Combining safe execution with wrapping detection for robust instrumentation.
Usage Example:
import { safeExecuteInTheMiddle, isWrapped } from "@opentelemetry/instrumentation";
class CompositeInstrumentation extends InstrumentationBase {
enable() {
this._instrumentModuleSafely('http', ['request', 'get']);
this._instrumentModuleSafely('https', ['request', 'get']);
}
disable() {
this._uninstrumentModuleSafely('http', ['request', 'get']);
this._uninstrumentModuleSafely('https', ['request', 'get']);
}
private _instrumentModuleSafely(moduleName: string, methods: string[]) {
safeExecuteInTheMiddle(
() => {
const module = require(moduleName);
methods.forEach(method => {
if (module[method] && !isWrapped(module[method])) {
shimmer.wrap(module, method, this._createWrapper(method));
this._diag.debug(`Wrapped ${moduleName}.${method}`);
} else if (isWrapped(module[method])) {
this._diag.debug(`${moduleName}.${method} already wrapped`);
} else {
this._diag.warn(`${moduleName}.${method} not found or not a function`);
}
});
return module;
},
(error) => {
if (error) {
this._diag.error(`Failed to instrument ${moduleName}:`, error);
}
},
true // Don't fail application startup on instrumentation errors
);
}
private _uninstrumentModuleSafely(moduleName: string, methods: string[]) {
safeExecuteInTheMiddle(
() => {
const module = require(moduleName);
methods.forEach(method => {
if (isWrapped(module[method])) {
shimmer.unwrap(module, method);
this._diag.debug(`Unwrapped ${moduleName}.${method}`);
}
});
return module;
},
(error) => {
if (error) {
this._diag.error(`Failed to uninstrument ${moduleName}:`, error);
}
},
true
);
}
private _createWrapper(methodName: string) {
return (original: Function) => {
const instrumentation = this;
return function(this: any, ...args: any[]) {
return safeExecuteInTheMiddleAsync(
async () => {
const span = instrumentation.tracer.startSpan(`${methodName}.call`);
try {
const result = await original.apply(this, args);
return result;
} finally {
span.end();
}
},
(error) => {
if (error) {
instrumentation._diag.error(`Error in wrapped ${methodName}:`, error);
}
}
);
};
};
}
}Install with Tessl CLI
npx tessl i tessl/npm-opentelemetry--instrumentation