lib_instrumentation-descriptor.js
/*
* Copyright 2024 New Relic Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
*/
'use strict'
const IdGen = require('./util/idgen')
const idGen = new IdGen()
/**
* @typedef {function} InstrumentationOnRequire
* @param {Shim} shim The shim instance to use for the instrumentation.
* @param {object} resolvedNodule The module being instrumented as returned by
* Node's `require` function.
* @param {string} moduleName The simple name of the module, i.e. the value
* passed to the `require` function.
* @throws {Error|object}
*/
/**
* @typedef {function} InstrumentationOnError
* @param {Error|object} error The error thrown by `onRequire` when there was
* an issue registering the instrumentation.
*/
/* eslint-disable jsdoc/require-property-description */
/**
* @typedef {object} InstrumentationDescriptorParams
* @property {string} absolutePath
* @property {string} module
* @property {string} moduleName
* @property {string} shimName
* @property {InstrumentationOnError} onError
* @property {InstrumentationOnRequire} onRequire
* @property {string} resolvedName
* @property {string} type
*/
/**
* Describes the configuration for an instrumentation. An instrumentation
* is what `newrelic` uses to wrap Node.js modules. In particular, a description
* details the name of the module, the path on disk to the module, and the
* hooks (`onRequire` and `onError`) to apply to the module.
*/
class InstrumentationDescriptor {
/**
* Utility/generic module.
* @type {string}
*/
static TYPE_GENERIC = 'generic'
/**
* @private
* @type {string}
*/
static TYPE_CONGLOMERATE = 'conglomerate'
/**
* Database module, such as the MongoDB or MySQL drivers.
* @type {string}
*/
static TYPE_DATASTORE = 'datastore'
/**
* Messaging module, such as AMQP.
* @type {string}
*/
static TYPE_MESSAGE = 'message'
/**
* Promise module, such as Bluebird.
* @type {string}
*/
static TYPE_PROMISE = 'promise'
/**
* @private
* @type {string}
*/
static TYPE_TRANSACTION = 'transaction'
/**
* Web server framework module, such as Express or Fastify.
* @type {string}
*/
static TYPE_WEB_FRAMEWORK = 'web-framework'
/**
* Used to load supportability metrics on installed versions of packages
* that the Node.js agent does not instrument (e.g. OTEL instrumentation or
* top logging libraries).
* @type {string}
*/
static TYPE_TRACKING = 'tracking'
/**
* The type of the module being instrumented. See the static `TYPE_` fields.
* @type {string|null}
*/
type
/**
* The name of the module being instrumented, i.e. the string used to require
* the module. This must map to a directory in `lib/instrumentations` which
* contains an `nr-hooks.js` file.
*
* This takes precedence over `moduleName`.
* @type {string}
*/
module
/**
* The name of the module being instrumented, i.e. the string used to require
* the module. This must map to a JavaScript file of the same name in the
* `lib/instrumentations` directory.
* @type {string}
*/
moduleName
/**
* Used when instrumenting a module to determine if a module has already
* been wrapped by a specific shim instance. It is used in conjunction with
* the `shim.id` value.
* @type {string}
*/
shimName
/**
* The absolute path to the module to instrument. This should only be set
* when the module being instrumented does not reside in a `node_modules`
* directory; for example, when someone is instrumenting a module of their
* own through the public API.
*
* The `moduleName` property still needs to be set to the simple name, i.e.
* the string passed to `require`, for instrumentation tracking purposes.
*
* Note: this value takes precedence over `moduleName`.
*/
absolutePath
/**
* The fully resolved path to the module, e.g. `/opt/app/node_modules/foo`.
* If the module is a core module, the special value `.` should be used.
* @type {string}
*/
resolvedName
/**
* Hook to invoke when the module is required. This is the actual
* implementation of the instrumentation.
* @type {InstrumentationOnRequire}
*/
onRequire
/**
* Hook to invoke when the `onRequire` hook throws an error.
* @type {InstrumentationOnError}
*/
onError
/**
* @type {number}
*/
#id
/* eslint-disable jsdoc/require-param-description */
/**
* @param {InstrumentationDescriptorParams} params
*/
constructor(params) {
this.absolutePath = params.absolutePath
this.module = params.module
this.moduleName = params.moduleName
this.shimName = params.shimName
this.onError = params.onError
this.onRequire = params.onRequire
this.resolvedName = params.resolvedName
this.type = params.type
this.#id = idGen.idFor(this.moduleName)
}
/**
* Identifier for the instrumentation. Used by the internal instrumentation
* tracker to distinguish between different instrumentations targeting the
* same module.
*
* @returns {number} The identifier.
*/
get instrumentationId() {
return this.#id
}
}
module.exports = InstrumentationDescriptor
// This export is for backward compatibility in the public API. The
// public API object simply re-exports this object that was originally
// in a `constants.js` file prior to the creation of the
// `InstrumentationDescriptor`.
module.exports.TYPES = {
GENERIC: InstrumentationDescriptor.TYPE_GENERIC,
DATASTORE: InstrumentationDescriptor.TYPE_DATASTORE,
MESSAGE: InstrumentationDescriptor.TYPE_MESSAGE,
PROMISE: InstrumentationDescriptor.TYPE_PROMISE,
WEB_FRAMEWORK: InstrumentationDescriptor.TYPE_WEB_FRAMEWORK,
TRACKING: InstrumentationDescriptor.TYPE_TRACKING,
/** @private */
CONGLOMERATE: InstrumentationDescriptor.TYPE_CONGLOMERATE,
/** @private */
TRANSACTION: InstrumentationDescriptor.TYPE_TRANSACTION
}