Skip to content

Commit 448bca2

Browse files
uurientlhunter
authored andcommitted
Fix same dependency detection (#3386)
* Fix same dependency detection * Do not send same dependency:version twice * Clear map on stop * Update savedDependencies to savedDependenciesToSend to improve understanding
1 parent bd7618f commit 448bca2

File tree

2 files changed

+91
-12
lines changed

2 files changed

+91
-12
lines changed

packages/dd-trace/src/telemetry/dependencies.js

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ const { sendData } = require('./send-data')
77
const dc = require('../../../diagnostics_channel')
88
const { fileURLToPath } = require('url')
99

10-
const savedDependencies = new Set()
11-
const detectedDependencyNames = new Set()
10+
const savedDependenciesToSend = new Set()
11+
const detectedDependencyKeys = new Set()
12+
const detectedDependencyVersions = new Set()
13+
1214
const FILE_URI_START = `file://`
1315
const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
1416

@@ -18,14 +20,14 @@ function waitAndSend (config, application, host) {
1820
if (!immediate) {
1921
immediate = setImmediate(() => {
2022
immediate = null
21-
if (savedDependencies.size > 0) {
22-
const dependencies = Array.from(savedDependencies.values()).splice(0, 1000).map(pair => {
23-
savedDependencies.delete(pair)
23+
if (savedDependenciesToSend.size > 0) {
24+
const dependencies = Array.from(savedDependenciesToSend.values()).splice(0, 1000).map(pair => {
25+
savedDependenciesToSend.delete(pair)
2426
const [name, version] = pair.split(' ')
2527
return { name, version }
2628
})
2729
sendData(config, application, host, 'app-dependencies-loaded', { dependencies })
28-
if (savedDependencies.size > 0) {
30+
if (savedDependenciesToSend.size > 0) {
2931
waitAndSend(config, application, host)
3032
}
3133
}
@@ -46,15 +48,24 @@ function onModuleLoad (data) {
4648
}
4749
const parseResult = filename && parse(filename)
4850
const request = data.request || (parseResult && parseResult.name)
49-
if (filename && request && isDependency(filename, request) && !detectedDependencyNames.has(request)) {
50-
detectedDependencyNames.add(request)
51+
const dependencyKey = parseResult && parseResult.basedir ? parseResult.basedir : request
52+
53+
if (filename && request && isDependency(filename, request) && !detectedDependencyKeys.has(dependencyKey)) {
54+
detectedDependencyKeys.add(dependencyKey)
55+
5156
if (parseResult) {
5257
const { name, basedir } = parseResult
5358
if (basedir) {
5459
try {
5560
const { version } = requirePackageJson(basedir, module)
56-
savedDependencies.add(`${name} ${version}`)
57-
waitAndSend(config, application, host)
61+
const dependencyAndVersion = `${name} ${version}`
62+
63+
if (!detectedDependencyVersions.has(dependencyAndVersion)) {
64+
savedDependenciesToSend.add(dependencyAndVersion)
65+
detectedDependencyVersions.add(dependencyAndVersion)
66+
67+
waitAndSend(config, application, host)
68+
}
5869
} catch (e) {
5970
// can not read the package.json, do nothing
6071
}
@@ -88,8 +99,9 @@ function stop () {
8899
config = null
89100
application = null
90101
host = null
91-
detectedDependencyNames.clear()
92-
savedDependencies.clear()
102+
detectedDependencyKeys.clear()
103+
savedDependenciesToSend.clear()
104+
detectedDependencyVersions.clear()
93105
if (moduleLoadStartChannel.hasSubscribers) {
94106
moduleLoadStartChannel.unsubscribe(onModuleLoad)
95107
}

packages/dd-trace/test/telemetry/dependencies.spec.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,73 @@ describe('dependencies', () => {
198198
.to.have.been.calledOnceWith(config, application, host, 'app-dependencies-loaded', expectedDependencies)
199199
})
200200

201+
it('should include two dependencies when they are in different paths', () => {
202+
const moduleName = 'custom-module'
203+
const packageVersion = '1.0.0'
204+
const nestedPackageVersion = '0.5.0'
205+
const firstLevelDependency = [fileURIWithoutNodeModules, 'node_modules', moduleName, 'index1.js'].join('/')
206+
const nestedDependency =
207+
[fileURIWithoutNodeModules, 'node_modules', 'dependency', 'node_modules', moduleName, 'index1.js'].join('/')
208+
209+
requirePackageJson.callsFake(function (dependencyPath) {
210+
if (dependencyPath.includes(path.join('node_modules', 'dependency', 'node_modules'))) {
211+
return { version: nestedPackageVersion }
212+
} else {
213+
return { version: packageVersion }
214+
}
215+
})
216+
217+
dependencies.start(config, application, host)
218+
moduleLoadStartChannel.publish({ request: moduleName, filename: firstLevelDependency })
219+
moduleLoadStartChannel.publish({ request: moduleName, filename: nestedDependency })
220+
221+
const expectedDependencies1 = {
222+
dependencies: [
223+
{ name: moduleName, version: packageVersion }
224+
]
225+
}
226+
const expectedDependencies2 = {
227+
dependencies: [
228+
{ name: moduleName, version: nestedPackageVersion }
229+
]
230+
}
231+
expect(sendData).to.have.been.calledTwice
232+
233+
expect(sendData.firstCall)
234+
.to.have.been.calledWith(config, application, host, 'app-dependencies-loaded', expectedDependencies1)
235+
236+
expect(sendData.secondCall)
237+
.to.have.been.calledWith(config, application, host, 'app-dependencies-loaded', expectedDependencies2)
238+
})
239+
240+
it('should include only one dependency when they are in different paths but the version number is the same', () => {
241+
const moduleName = 'custom-module'
242+
const packageVersion = '1.0.0'
243+
const firstLevelDependency = [fileURIWithoutNodeModules, 'node_modules', moduleName, 'index1.js'].join('/')
244+
const nestedDependency =
245+
[fileURIWithoutNodeModules, 'node_modules', 'dependency', 'node_modules', moduleName, 'index1.js'].join('/')
246+
247+
requirePackageJson.callsFake(function (dependencyPath) {
248+
if (dependencyPath.includes(path.join('node_modules', 'dependency', 'node_modules'))) {
249+
return { version: packageVersion }
250+
} else {
251+
return { version: packageVersion }
252+
}
253+
})
254+
255+
dependencies.start(config, application, host)
256+
moduleLoadStartChannel.publish({ request: moduleName, filename: firstLevelDependency })
257+
moduleLoadStartChannel.publish({ request: moduleName, filename: nestedDependency })
258+
259+
const expectedDependencies = {
260+
dependencies: [
261+
{ name: moduleName, version: packageVersion }
262+
]
263+
}
264+
expect(sendData).to.have.been
265+
.calledOnceWith(config, application, host, 'app-dependencies-loaded', expectedDependencies)
266+
})
267+
201268
it('should call sendData only once with duplicated dependency', () => {
202269
const request = 'custom-module'
203270
requirePackageJson.returns({ version: '1.0.0' })

0 commit comments

Comments
 (0)