Skip to content

Commit 3a9b66f

Browse files
committed
Merge branch 'master' into mario.vidal/support_happy_dom_jest
2 parents 750c6a5 + 7b9b5cf commit 3a9b66f

File tree

32 files changed

+618
-354
lines changed

32 files changed

+618
-354
lines changed

.github/workflows/test-optimization.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,22 @@ jobs:
1919
benchmarks-e2e:
2020
name: Performance and correctness tests
2121
runs-on: ubuntu-latest
22+
permissions:
23+
id-token: write
2224
steps:
23-
- uses: actions/create-github-app-token@df432ceedc7162793a195dd1713ff69aefc7379e # v2.0.6
24-
id: app-token
25+
- uses: DataDog/dd-octo-sts-action@08f2144903ced3254a3dafec2592563409ba2aa0 # v1.0.1
26+
id: octo-sts
2527
with:
26-
app-id: ${{ vars.APP_ID }}
27-
private-key: ${{ secrets.PRIVATE_KEY }}
28-
repositories: |
29-
dd-trace-js
30-
test-environment
28+
scope: DataDog/test-environment
29+
policy: dd-trace-js
3130
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
3231
with:
33-
token: ${{ steps.app-token.outputs.token }}
32+
token: ${{ steps.octo-sts.outputs.token }}
3433
- uses: ./.github/actions/node/oldest-maintenance-lts
3534
- name: Test Optimization Performance Overhead Test
3635
run: yarn bench:e2e:test-optimization
3736
env:
38-
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
37+
GITHUB_TOKEN: ${{ steps.octo-sts.outputs.token }}
3938

4039
integration:
4140
strategy:

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,5 +121,7 @@ packages/datadog-plugin-next/test/yarn.lock
121121
packages/dd-trace/test/appsec/next/*/package.json
122122
packages/dd-trace/test/appsec/next/*/node_modules
123123
packages/dd-trace/test/appsec/next/*/yarn.lock
124+
packages/dd-trace/test/plugins/versions/node_modules
125+
packages/dd-trace/test/plugins/versions/yarn.lock
124126
!packages/dd-trace/**/telemetry/logs
125127
packages/datadog-plugin-azure-functions/test/integration-test/fixtures/node_modules

integration-tests/appsec/graphql.spec.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ describe('graphql', () => {
1414
let sandbox, cwd, agent, webFile, proc
1515

1616
before(async function () {
17-
sandbox = await createSandbox(['@apollo/server@4', 'graphql', 'koalas'])
17+
sandbox = await createSandbox(['@apollo/server', 'graphql', 'koalas'])
1818
cwd = sandbox.folder
1919
webFile = path.join(cwd, 'graphql/index.js')
2020
})
@@ -43,7 +43,8 @@ describe('graphql', () => {
4343
assert.propertyVal(headers, 'host', `127.0.0.1:${agent.port}`)
4444
assert.isArray(payload)
4545
assert.strictEqual(payload.length, 2)
46-
assert.propertyVal(payload[1][0], 'name', 'express.request')
46+
// Apollo server 5 is using Node.js http server instead of express
47+
assert.propertyVal(payload[1][0], 'name', 'web.request')
4748
assert.propertyVal(payload[1][0].metrics, '_dd.appsec.enabled', 1)
4849
assert.property(payload[1][0].metrics, '_dd.appsec.waf.duration')
4950
assert.notProperty(payload[1][0].meta, '_dd.appsec.event')
@@ -104,7 +105,8 @@ describe('graphql', () => {
104105
assert.propertyVal(headers, 'host', `127.0.0.1:${agent.port}`)
105106
assert.isArray(payload)
106107
assert.strictEqual(payload.length, 2)
107-
assert.propertyVal(payload[1][0], 'name', 'express.request')
108+
// Apollo server 5 is using Node.js http server instead of express
109+
assert.propertyVal(payload[1][0], 'name', 'web.request')
108110
assert.propertyVal(payload[1][0].metrics, '_dd.appsec.enabled', 1)
109111
assert.property(payload[1][0].metrics, '_dd.appsec.waf.duration')
110112
assert.propertyVal(payload[1][0].meta, 'appsec.event', 'true')

integration-tests/helpers/index.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ const { fork, spawn } = childProcess
66
const exec = promisify(childProcess.exec)
77
const http = require('http')
88
const fs = require('fs')
9+
const { builtinModules } = require('module')
910
const os = require('os')
1011
const path = require('path')
1112
const assert = require('assert')
1213
const rimraf = promisify(require('rimraf'))
1314
const FakeAgent = require('./fake-agent')
1415
const id = require('../../packages/dd-trace/src/id')
1516
const { version } = require('../../package.json')
17+
const { getCappedRange } = require('../../packages/dd-trace/test/plugins/versions')
1618

1719
const hookFile = 'dd-trace/loader-hook.mjs'
1820

@@ -169,6 +171,17 @@ function spawnProc (filename, options = {}, stdioHandler, stderrHandler) {
169171

170172
async function createSandbox (dependencies = [], isGitRepo = false,
171173
integrationTestsPaths = ['./integration-tests/*'], followUpCommand) {
174+
const cappedDependencies = dependencies.map(dep => {
175+
if (builtinModules.includes(dep)) return dep
176+
177+
const match = dep.replaceAll(/['"]/g, '').match(/^(@?[^@]+)(@(.+))?$/)
178+
const name = match[1]
179+
const range = match[3] || ''
180+
const cappedRange = getCappedRange(name, range)
181+
182+
return `"${name}@${cappedRange}"`
183+
})
184+
172185
// We might use NODE_OPTIONS to init the tracer. We don't want this to affect this operations
173186
const { NODE_OPTIONS, ...restOfEnv } = process.env
174187
const noSandbox = String(process.env.TESTING_NO_INTEGRATION_SANDBOX)
@@ -184,7 +197,7 @@ async function createSandbox (dependencies = [], isGitRepo = false,
184197
}
185198
const folder = path.join(os.tmpdir(), id().toString())
186199
const out = path.join(folder, `dd-trace-${version}.tgz`)
187-
const allDependencies = [`file:${out}`].concat(dependencies)
200+
const allDependencies = [`file:${out}`].concat(cappedDependencies)
188201

189202
fs.mkdirSync(folder)
190203
const preferOfflineFlag = process.env.OFFLINE === '1' || process.env.OFFLINE === 'true' ? ' --prefer-offline' : ''

packages/datadog-instrumentations/src/apollo-server.js

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const { addHook } = require('./helpers/instrument')
66
const shimmer = require('../../datadog-shimmer')
77

88
const graphqlMiddlewareChannel = dc.tracingChannel('datadog:apollo:middleware')
9+
const apolloHttpServerChannel = dc.tracingChannel('datadog:apollo:httpserver')
910

1011
const requestChannel = dc.tracingChannel('datadog:apollo:request')
1112

@@ -77,17 +78,58 @@ function apolloServerHook (apolloServer) {
7778
return apolloServer
7879
}
7980

80-
addHook(
81-
{ name: '@apollo/server', file: 'dist/cjs/ApolloServer.js', versions: ['>=4.0.0 <5.0.0'] },
82-
apolloServerHook
83-
)
81+
function wrapEmit (emit) {
82+
return function wrappedEmit (event, req, res) {
83+
if (event === 'request' && req && res && apolloHttpServerChannel.start.hasSubscribers) {
84+
return apolloHttpServerChannel.traceSync(emit, { req }, this, ...arguments)
85+
}
86+
87+
return emit.apply(this, arguments)
88+
}
89+
}
90+
91+
function wrapListen (originalListen) {
92+
return function wrappedListen () {
93+
shimmer.wrap(this, 'emit', wrapEmit)
94+
95+
return originalListen.apply(this, arguments)
96+
}
97+
}
98+
99+
function wrapHttpServer (original) {
100+
return function wrappedHttpServer (options) {
101+
if (options.httpServer && typeof options.httpServer.listen === 'function') {
102+
shimmer.wrap(options.httpServer, 'listen', wrapListen)
103+
}
104+
105+
return original.apply(this, arguments)
106+
}
107+
}
108+
109+
function apolloDrainHttpServerHook (drainModule) {
110+
shimmer.wrap(drainModule, 'ApolloServerPluginDrainHttpServer', wrapHttpServer)
111+
112+
return drainModule
113+
}
114+
115+
addHook({ name: '@apollo/server', file: 'dist/cjs/ApolloServer.js', versions: ['4'] }, apolloServerHook)
116+
117+
addHook({ name: '@apollo/server', file: 'dist/cjs/express4/index.js', versions: ['4'] }, apolloExpress4Hook)
118+
119+
addHook({ name: '@apollo/server', file: 'dist/cjs/utils/HeaderMap.js', versions: ['4'] }, apolloHeaderMapHook)
84120

85121
addHook(
86-
{ name: '@apollo/server', file: 'dist/cjs/express4/index.js', versions: ['>=4.0.0 <5.0.0'] },
87-
apolloExpress4Hook
122+
{ name: '@apollo/server', file: 'dist/cjs/plugin/drainHttpServer/index.js', versions: ['>=5.0.0'] },
123+
apolloDrainHttpServerHook
88124
)
89125

90126
addHook(
91-
{ name: '@apollo/server', file: 'dist/cjs/utils/HeaderMap.js', versions: ['>=4.0.0 <5.0.0'] },
92-
apolloHeaderMapHook
127+
{ name: '@apollo/server', file: 'dist/cjs/runHttpQuery.js', versions: ['>=5.0.0'] },
128+
(runHttpQueryModule) => {
129+
shimmer.wrap(runHttpQueryModule, 'runHttpQuery', function wrapRunHttpQuery (originalRunHttpQuery) {
130+
return wrapExecuteHTTPGraphQLRequest(originalRunHttpQuery)
131+
})
132+
133+
return runHttpQueryModule
134+
}
93135
)

packages/datadog-instrumentations/src/http2/server.js

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55

66
const {
77
channel,
8-
addHook,
9-
AsyncResource
8+
addHook
109
} = require('../helpers/instrument')
1110
const shimmer = require('../../../datadog-shimmer')
1211

1312
const startServerCh = channel('apm:http2:server:request:start')
1413
const errorServerCh = channel('apm:http2:server:request:error')
15-
const finishServerCh = channel('apm:http2:server:request:finish')
14+
const emitCh = channel('apm:http2:server:response:emit')
1615

1716
const names = ['http2', 'node:http2']
1817

@@ -30,18 +29,14 @@ function wrapCreateServer (createServer) {
3029
}
3130
}
3231

33-
function wrapResponseEmit (emit) {
34-
const asyncResource = new AsyncResource('bound-anonymous-fn')
32+
function wrapResponseEmit (emit, ctx) {
3533
return function (eventName, event) {
36-
return asyncResource.runInAsyncScope(() => {
37-
if (eventName === 'close' && finishServerCh.hasSubscribers) {
38-
finishServerCh.publish({ req: this.req })
39-
}
40-
41-
return emit.apply(this, arguments)
42-
})
34+
ctx.req = this.req
35+
ctx.eventName = eventName
36+
return emitCh.runStores(ctx, emit, this, ...arguments)
4337
}
4438
}
39+
4540
function wrapEmit (emit) {
4641
return function (eventName, req, res) {
4742
if (!startServerCh.hasSubscribers) {
@@ -51,18 +46,17 @@ function wrapEmit (emit) {
5146
if (eventName === 'request') {
5247
res.req = req
5348

54-
const asyncResource = new AsyncResource('bound-anonymous-fn')
55-
return asyncResource.runInAsyncScope(() => {
56-
startServerCh.publish({ req, res })
57-
58-
shimmer.wrap(res, 'emit', wrapResponseEmit)
49+
const ctx = { req, res }
50+
return startServerCh.runStores(ctx, () => {
51+
shimmer.wrap(res, 'emit', emit => wrapResponseEmit(emit, ctx))
5952

6053
try {
6154
return emit.apply(this, arguments)
62-
} catch (err) {
63-
errorServerCh.publish(err)
55+
} catch (error) {
56+
ctx.error = error
57+
errorServerCh.publish(ctx)
6458

65-
throw err
59+
throw error
6660
}
6761
})
6862
}

packages/datadog-instrumentations/src/mongodb-core.js

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -148,61 +148,66 @@ function wrapCommand (command, operation, name) {
148148
return wrapped
149149
}
150150

151-
function instrument (operation, command, ctx, args, server, ns, ops, options = {}) {
151+
function instrument (operation, command, instance, args, server, ns, ops, options = {}) {
152152
const name = options.name || (ops && Object.keys(ops)[0])
153153
const index = args.length - 1
154-
let callback = args[index]
154+
const callback = args[index]
155155

156-
if (typeof callback !== 'function') return command.apply(ctx, args)
156+
if (typeof callback !== 'function') return command.apply(instance, args)
157157

158158
const serverInfo = server && server.s && server.s.options
159-
const callbackResource = new AsyncResource('bound-anonymous-fn')
160-
const asyncResource = new AsyncResource('bound-anonymous-fn')
161159

162-
callback = callbackResource.bind(callback)
163-
164-
return asyncResource.runInAsyncScope(() => {
165-
startCh.publish({ ns, ops, options: serverInfo, name })
166-
167-
args[index] = shimmer.wrapFunction(callback, callback => asyncResource.bind(function (err, res) {
160+
const ctx = {
161+
ns,
162+
ops,
163+
options: serverInfo,
164+
name
165+
}
166+
return startCh.runStores(ctx, () => {
167+
args[index] = shimmer.wrapFunction(callback, callback => function (err, res) {
168168
if (err) {
169-
errorCh.publish(err)
169+
ctx.error = err
170+
errorCh.publish(ctx)
170171
}
171172

172-
finishCh.publish()
173-
174-
if (callback) {
175-
return callback.apply(this, arguments)
176-
}
177-
}))
173+
return finishCh.runStores(ctx, callback, this, ...arguments)
174+
})
178175

179176
try {
180-
return command.apply(ctx, args)
177+
return command.apply(instance, args)
181178
} catch (err) {
182-
errorCh.publish(err)
179+
ctx.error = err
180+
errorCh.publish(ctx)
183181

184182
throw err
185183
}
186184
})
187185
}
188186

189-
function instrumentPromise (operation, command, ctx, args, server, ns, ops, options = {}) {
187+
function instrumentPromise (operation, command, instance, args, server, ns, ops, options = {}) {
190188
const name = options.name || (ops && Object.keys(ops)[0])
191189

192190
const serverInfo = server && server.s && server.s.options
193-
const asyncResource = new AsyncResource('bound-anonymous-fn')
194191

195-
return asyncResource.runInAsyncScope(() => {
196-
startCh.publish({ ns, ops, options: serverInfo, name })
192+
const ctx = {
193+
ns,
194+
ops,
195+
options: serverInfo,
196+
name
197+
}
197198

198-
const promise = command.apply(ctx, args)
199+
return startCh.runStores(ctx, () => {
200+
const promise = command.apply(instance, args)
199201

200202
return promise.then(function (res) {
201-
finishCh.publish()
202-
return res
203+
ctx.result = res
204+
return finishCh.runStores(ctx, () => {
205+
return res
206+
})
203207
}, function (err) {
204-
errorCh.publish(err)
205-
finishCh.publish()
208+
ctx.error = err
209+
errorCh.publish(ctx)
210+
finishCh.publish(ctx)
206211

207212
throw err
208213
})

packages/datadog-instrumentations/src/mongodb.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@ require('./mongodb-core')
44

55
const {
66
channel,
7-
addHook,
8-
AsyncResource
7+
addHook
98
} = require('./helpers/instrument')
109
const shimmer = require('../../datadog-shimmer')
1110

@@ -41,19 +40,16 @@ addHook({ name: 'mongodb', versions: ['>=3.3 <5', '5', '>=6'] }, mongodb => {
4140
return method.apply(this, arguments)
4241
}
4342

44-
const asyncResource = new AsyncResource('bound-anonymous-fn')
45-
46-
return asyncResource.runInAsyncScope(() => {
47-
const filters = [arguments[0]]
48-
if (useTwoArguments) {
49-
filters.push(arguments[1])
50-
}
43+
const ctx = {
44+
filters: [arguments[0]],
45+
methodName
46+
}
5147

52-
startCh.publish({
53-
filters,
54-
methodName
55-
})
48+
if (useTwoArguments) {
49+
ctx.filters.push(arguments[1])
50+
}
5651

52+
return startCh.runStores(ctx, () => {
5753
return method.apply(this, arguments)
5854
})
5955
}

0 commit comments

Comments
 (0)