CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-newrelic

Application Performance Monitoring (APM) agent for Node.js applications with transaction tracing, error tracking, custom metrics, and distributed tracing capabilities.

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

custom-instrumentation.mddocs/

Custom Instrumentation

Register custom instrumentation for third-party modules and application-specific code patterns.

Capabilities

Basic Instrumentation

Register generic instrumentation for any module.

/**
 * Register generic instrumentation for a module
 * @param {string|object} moduleName - Module name or instrumentation options
 * @param {Function} onRequire - Function called when module is loaded
 * @param {Function} [onError] - Error handler for instrumentation failures
 */
function instrument(moduleName, onRequire, onError);

Specialized Instrumentation

/**
 * Register datastore-specific instrumentation
 */
function instrumentDatastore(moduleName, onRequire, onError);

/**
 * Register web framework instrumentation
 */
function instrumentWebframework(moduleName, onRequire, onError);

/**
 * Register message broker instrumentation
 */
function instrumentMessages(moduleName, onRequire, onError);

/**
 * Register conglomerate (multi-module) instrumentation
 */
function instrumentConglomerate(moduleName, onRequire, onError);

/**
 * Apply instrumentation to already loaded modules
 * @param {string} moduleName - Module name
 * @param {object} module - Already loaded module
 * @returns {boolean} Success status
 */
function instrumentLoadedModule(moduleName, module);

Instrumentation Specification Object

For advanced instrumentation scenarios, pass an object instead of a string:

interface InstrumentationSpec {
  /** Module name to instrument */
  moduleName: string;
  /** Absolute path for specific module location */
  absolutePath?: string;
  /** Function called when module loads */
  onRequire: Function;
  /** Error handler for instrumentation failures */
  onError?: Function;
  /** Mark as ESM module (for ES Modules) */
  isEsm?: boolean;
}

Shim Types and Methods

The shim object provides different recording methods based on the instrumentation type:

Generic Shim Methods

// Record a function call with timing
shim.record(target, methodName, recordSpec);

// Wrap a function with custom logic
shim.wrap(target, methodName, wrapperFunction);

// Segment timing without recording
shim.createSegment(name, recorder, parentSegment);

Datastore Shim Methods

// Record database operations
shim.recordOperation(target, methodNames, operationSpec);

// Record query operations with SQL
shim.recordQuery(target, methodNames, querySpec);

// Record batch operations
shim.recordBatchQuery(target, methodNames, batchSpec);

Web Framework Shim Methods

// Record middleware functions
shim.recordMiddleware(target, methodName, middlewareSpec);

// Record route handlers
shim.recordRender(target, methodName, renderSpec);

// Wrap request/response handling
shim.wrapMiddlewareMounter(target, methodName, spec);

Message Shim Methods

// Record message producer operations
shim.recordProduce(target, methodName, produceSpec);

// Record message consumer operations
shim.recordConsume(target, methodName, consumeSpec);

// Record subscription operations
shim.recordSubscribedConsume(target, methodName, subscribeSpec);

Usage Examples:

const newrelic = require('newrelic');

// Basic instrumentation with error handling
newrelic.instrument('my-custom-db', function(shim, module, moduleName) {
  // Record all query methods
  shim.record(module.prototype, ['query', 'find', 'update'], function(shim, fn, name, args) {
    return {
      name: `Database/${moduleName}/${name}`,
      callback: shim.LAST,
      parameters: {
        query: args[0]
      }
    };
  });
  
  // Wrap connection method for additional context
  shim.wrap(module.prototype, 'connect', function(shim, original) {
    return function wrappedConnect() {
      const result = original.apply(this, arguments);
      shim.logger.debug('Database connection established');
      return result;
    };
  });
}, function onError(error) {
  console.error('Failed to instrument my-custom-db:', error);
});

// Advanced datastore instrumentation
newrelic.instrumentDatastore('redis-custom', function(shim, redis, moduleName) {
  // Record standard operations
  shim.recordOperation(redis.RedisClient.prototype, ['get', 'set', 'del'], {
    name: function(shim, fn, fnName, args) {
      return fnName.toUpperCase(); // GET, SET, DEL
    },
    parameters: {
      key: shim.FIRST,
      database_name: function(shim, fn, fnName, args, client) {
        return client.selectedDb || 0;
      }
    },
    callback: function(shim, fn, fnName, args) {
      // Find callback in arguments
      for (let i = args.length - 1; i >= 0; i--) {
        if (typeof args[i] === 'function') {
          return i;
        }
      }
      return null;
    }
  });
  
  // Record complex query operations
  shim.recordQuery(redis.RedisClient.prototype, ['eval', 'evalsha'], {
    name: 'EVAL',
    parameters: {
      script: shim.FIRST,
      key_count: function(shim, fn, fnName, args) {
        return args[1] || 0;
      }
    },
    callback: shim.LAST
  });
});

// Web framework instrumentation
newrelic.instrumentWebframework('my-web-framework', function(shim, framework, moduleName) {
  // Record middleware registration
  shim.recordMiddleware(framework.prototype, 'use', {
    name: function(shim, fn, fnName, args) {
      if (typeof args[0] === 'string') {
        return `Middleware/${args[0]}`;
      }
      return 'Middleware/anonymous';
    },
    type: shim.MIDDLEWARE,
    route: function(shim, fn, fnName, args) {
      return typeof args[0] === 'string' ? args[0] : null;
    },
    wrapper: function(shim, middleware, name) {
      return shim.recordMiddleware(middleware, {
        name: name,
        type: shim.MIDDLEWARE
      });
    }
  });
  
  // Record route handlers
  shim.recordRender(framework.prototype, ['get', 'post', 'put', 'delete'], {
    name: function(shim, fn, fnName, args) {
      const route = args[0] || '/';
      return `Route/${fnName.toUpperCase()} ${route}`;
    },
    callback: function(shim, fn, fnName, args) {
      // Last argument is typically the handler
      return args.length - 1;
    }
  });
});

// Message queue instrumentation
newrelic.instrumentMessages('my-queue-lib', function(shim, queueLib, moduleName) {
  // Record message publishing
  shim.recordProduce(queueLib.prototype, 'publish', {
    name: function(shim, fn, fnName, args) {
      const queueName = args[0] || 'unknown';
      return `MessageBroker/${moduleName}/Queue/Produce/Named/${queueName}`;
    },
    parameters: {
      routing_key: shim.FIRST,
      reply_to: function(shim, fn, fnName, args) {
        return args[1] && args[1].replyTo;
      }
    },
    callback: shim.LAST
  });
  
  // Record message consumption
  shim.recordConsume(queueLib.prototype, 'subscribe', {
    name: function(shim, fn, fnName, args) {
      const queueName = args[0] || 'unknown';
      return `MessageBroker/${moduleName}/Queue/Consume/Named/${queueName}`;
    },
    parameters: {
      routing_key: shim.FIRST
    },
    messageHandler: function(shim, fn, fnName, args) {
      // Find the message handler function
      for (let i = 1; i < args.length; i++) {
        if (typeof args[i] === 'function') {
          return i;
        }
      }
      return null;
    }
  });
});

// Already loaded module instrumentation
const customModule = require('my-module');
const success = newrelic.instrumentLoadedModule('my-module', customModule);
if (success) {
  console.log('Successfully instrumented already-loaded module');
} else {
  console.warn('Failed to instrument already-loaded module');
}

// ESM module instrumentation
newrelic.instrument({
  moduleName: 'esm-module',
  isEsm: true,
  onRequire: function(shim, module, moduleName) {
    shim.record(module.default, 'process', {
      name: `Custom/${moduleName}/process`,
      callback: shim.LAST
    });
  },
  onError: function(error) {
    console.error('ESM instrumentation failed:', error);
  }
});

Recording Specifications

Basic Record Spec

interface RecordSpec {
  /** Segment/metric name (string or function) */
  name: string | Function;
  /** Callback argument index or function to find it */
  callback?: number | Function;
  /** Additional parameters to capture */
  parameters?: object;
  /** Whether to record as a metric */
  record?: boolean;
  /** Segment recorder function */
  recorder?: Function;
}

Datastore Operation Spec

interface DatastoreOperationSpec {
  /** Operation name */
  name: string | Function;
  /** Callback position */
  callback?: number | Function;
  /** Parameters to capture (database_name, collection_name, etc.) */
  parameters?: object;
  /** Promise handling */
  promise?: boolean;
  /** Query/command to capture */
  query?: Function;
}

Middleware Spec

interface MiddlewareSpec {
  /** Middleware name */
  name: string | Function;
  /** Middleware type (shim.MIDDLEWARE, shim.ROUTER, etc.) */
  type: string;
  /** Route pattern */
  route?: string | Function;
  /** Request object position */
  req?: number | Function;
  /** Response object position */
  res?: number | Function;
  /** Next function position */
  next?: number | Function;
  /** Wrapper function for the middleware */
  wrapper?: Function;
}

Common Patterns and Best Practices

Error Handling

newrelic.instrument('unreliable-module', function(shim, module) {
  try {
    shim.record(module, 'riskyMethod', {
      name: 'RiskyOperation',
      callback: shim.LAST
    });
  } catch (error) {
    shim.logger.warn('Could not instrument riskyMethod:', error);
  }
}, function onError(error) {
  console.error('Module instrumentation failed completely:', error);
});

Conditional Instrumentation

newrelic.instrument('optional-module', function(shim, module) {
  if (module.version && parseFloat(module.version) >= 2.0) {
    // Use v2+ API
    shim.record(module, 'newMethod', {
      name: 'NewAPI/newMethod',
      callback: shim.LAST
    });
  } else {
    // Use legacy API
    shim.record(module, 'oldMethod', {
      name: 'LegacyAPI/oldMethod',
      callback: shim.LAST
    });
  }
});

Promise-Based Libraries

newrelic.instrument('promise-based-lib', function(shim, lib) {
  shim.record(lib.prototype, 'asyncOperation', {
    name: 'AsyncOperation',
    promise: true, // Handle promise-based methods
    parameters: {
      input: shim.FIRST
    }
  });
});

Class Method Instrumentation

newrelic.instrument('class-based-lib', function(shim, lib) {
  // Instrument instance methods
  shim.record(lib.MyClass.prototype, ['method1', 'method2'], {
    name: function(shim, fn, fnName) {
      return `MyClass/${fnName}`;
    },
    callback: shim.LAST
  });
  
  // Instrument static methods
  shim.record(lib.MyClass, 'staticMethod', {
    name: 'MyClass/staticMethod',
    callback: shim.LAST
  });
});

Troubleshooting

Common Issues

  1. Module not found: Ensure the module name matches exactly (case-sensitive)
  2. Methods not instrumented: Check if methods exist on the target object
  3. Callback not found: Verify callback position or provide callback finder function
  4. ESM modules: Use isEsm: true and ensure proper import handling
  5. Already loaded modules: Use instrumentLoadedModule for modules loaded before instrumentation

Debugging Instrumentation

newrelic.instrument('debug-module', function(shim, module, moduleName) {
  shim.logger.debug('Instrumenting module:', moduleName);
  shim.logger.debug('Module methods:', Object.getOwnPropertyNames(module));
  
  shim.record(module, 'targetMethod', {
    name: 'DebugOperation',
    callback: function(shim, fn, fnName, args) {
      shim.logger.debug('Callback search in args:', args.map(arg => typeof arg));
      return shim.LAST;
    }
  });
});

docs

aws-lambda.md

browser-monitoring.md

custom-attributes.md

custom-instrumentation.md

distributed-tracing.md

error-handling.md

index.md

llm-monitoring.md

metrics-events.md

segments-timing.md

transaction-management.md

url-naming-rules.md

utilities.md

tile.json