Skip to content

Commit 59a5f36

Browse files
authored
fix loading of instrumentations (#5544)
1 parent af40a87 commit 59a5f36

File tree

1 file changed

+41
-1
lines changed
  • packages/datadog-instrumentations/src/helpers

1 file changed

+41
-1
lines changed

packages/datadog-instrumentations/src/helpers/register.js

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ if (DD_TRACE_DEBUG && DD_TRACE_DEBUG.toLowerCase() !== 'false') {
5151
}
5252

5353
const seenCombo = new Set()
54+
const allInstrumentations = {}
5455

5556
// TODO: make this more efficient
5657
for (const packageName of names) {
@@ -67,6 +68,9 @@ for (const packageName of names) {
6768
hook = hook.fn
6869
}
6970

71+
// get the instrumentation file name to save all hooked versions
72+
const instrumentationFileName = parseHookInstrumentationFileName(packageName)
73+
7074
Hook([packageName], hookOptions, (moduleExports, moduleName, moduleBaseDir, moduleVersion) => {
7175
moduleName = moduleName.replace(pathSepExpr, '/')
7276

@@ -105,6 +109,7 @@ for (const packageName of names) {
105109
let version = moduleVersion
106110
try {
107111
version = version || getVersion(moduleBaseDir)
112+
allInstrumentations[instrumentationFileName] = allInstrumentations[instrumentationFileName] || false
108113
} catch (e) {
109114
log.error('Error getting version for "%s": %s', name, e.message, e)
110115
continue
@@ -114,6 +119,8 @@ for (const packageName of names) {
114119
}
115120

116121
if (matchVersion(version, versions)) {
122+
allInstrumentations[instrumentationFileName] = true
123+
117124
// Check if the hook already has a set moduleExport
118125
if (hook[HOOK_SYMBOL].has(moduleExports)) {
119126
namesAndSuccesses[`${name}@${version}`] = true
@@ -143,7 +150,8 @@ for (const packageName of names) {
143150
for (const nameVersion of Object.keys(namesAndSuccesses)) {
144151
const [name, version] = nameVersion.split('@')
145152
const success = namesAndSuccesses[nameVersion]
146-
if (!success && !seenCombo.has(nameVersion)) {
153+
// we check allVersions to see if any version of the integration was successfully instrumented
154+
if (!success && !seenCombo.has(nameVersion) && !allInstrumentations[instrumentationFileName]) {
147155
telemetry('abort.integration', [
148156
`integration:${name}`,
149157
`integration_version:${version}`
@@ -171,6 +179,38 @@ function filename (name, file) {
171179
return [name, file].filter(val => val).join('/')
172180
}
173181

182+
// This function captures the instrumentation file name for a given package by parsing the hook require
183+
// function given the module name. It is used to ensure that instrumentations such as redis
184+
// that have several different modules being hooked, ie: 'redis' main package, and @redis/client submodule
185+
// return a consistent instrumentation name. This is used later to ensure that atleast some portion of
186+
// the integration was successfully instrumented. Prevents incorrect `Found incompatible integration version: ` messages
187+
// Example:
188+
// redis -> "() => require('../redis')" -> redis
189+
// @redis/client -> "() => require('../redis')" -> redis
190+
//
191+
function parseHookInstrumentationFileName (packageName) {
192+
let hook = hooks[packageName]
193+
if (hook.fn) {
194+
hook = hook.fn
195+
}
196+
const hookString = hook.toString()
197+
198+
const regex = /require\('([^']*)'\)/
199+
const match = hookString.match(regex)
200+
201+
// try to capture the hook require file location.
202+
if (match && match[1]) {
203+
let moduleName = match[1]
204+
// Remove leading '../' if present
205+
if (moduleName.startsWith('../')) {
206+
moduleName = moduleName.substring(3)
207+
}
208+
return moduleName
209+
}
210+
211+
return null
212+
}
213+
174214
module.exports = {
175215
filename,
176216
pathSepExpr,

0 commit comments

Comments
 (0)