dd-trace 2.9.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -6
- package/packages/datadog-instrumentations/index.js +5 -0
- package/packages/datadog-instrumentations/src/connect.js +3 -0
- package/packages/datadog-instrumentations/src/fastify.js +21 -15
- package/packages/datadog-instrumentations/src/graphql.js +354 -0
- package/packages/datadog-instrumentations/src/grpc/client.js +250 -0
- package/packages/datadog-instrumentations/src/grpc/server.js +144 -0
- package/packages/{datadog-plugin-grpc/src/kinds.js → datadog-instrumentations/src/grpc/types.js} +0 -0
- package/packages/datadog-instrumentations/src/grpc.js +4 -0
- package/packages/datadog-instrumentations/src/http/client.js +1 -1
- package/packages/datadog-instrumentations/src/http2/client.js +67 -0
- package/packages/datadog-instrumentations/src/http2/server.js +3 -0
- package/packages/datadog-instrumentations/src/http2.js +4 -0
- package/packages/datadog-instrumentations/src/jest.js +14 -14
- package/packages/datadog-instrumentations/src/koa.js +12 -3
- package/packages/datadog-instrumentations/src/microgateway-core.js +66 -0
- package/packages/datadog-instrumentations/src/mocha.js +129 -63
- package/packages/datadog-instrumentations/src/next.js +140 -0
- package/packages/datadog-instrumentations/src/router.js +3 -0
- package/packages/datadog-instrumentations/src/tedious.js +1 -1
- package/packages/datadog-plugin-graphql/src/index.js +123 -412
- package/packages/datadog-plugin-graphql/src/resolve.js +120 -0
- package/packages/datadog-plugin-grpc/src/client.js +54 -283
- package/packages/datadog-plugin-grpc/src/index.js +31 -3
- package/packages/datadog-plugin-grpc/src/server.js +50 -145
- package/packages/datadog-plugin-http/src/client.js +10 -7
- package/packages/datadog-plugin-http2/src/client.js +72 -120
- package/packages/datadog-plugin-http2/src/index.js +32 -3
- package/packages/datadog-plugin-http2/src/server.js +6 -214
- package/packages/datadog-plugin-jest/src/util.js +13 -1
- package/packages/datadog-plugin-microgateway-core/src/index.js +14 -145
- package/packages/datadog-plugin-mocha/src/index.js +8 -36
- package/packages/datadog-plugin-next/src/index.js +56 -168
- package/packages/datadog-plugin-router/src/index.js +7 -3
- package/packages/dd-trace/src/config.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
- package/packages/dd-trace/src/opentracing/span.js +6 -3
- package/packages/dd-trace/src/plugin_manager.js +21 -0
- package/packages/dd-trace/src/plugins/plugin.js +3 -1
- package/packages/dd-trace/src/plugins/util/test.js +3 -0
- package/packages/dd-trace/src/plugins/util/web.js +0 -7
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -1
- package/packages/dd-trace/src/startup-log.js +1 -1
- package/packages/dd-trace/src/telemetry.js +1 -1
- package/packages/dd-trace/lib/version.js +0 -1
|
@@ -5,101 +5,132 @@ const testStartCh = channel('ci:mocha:test:start')
|
|
|
5
5
|
const errorCh = channel('ci:mocha:test:error')
|
|
6
6
|
const skipCh = channel('ci:mocha:test:skip')
|
|
7
7
|
const testFinishCh = channel('ci:mocha:test:finish')
|
|
8
|
-
const suiteFinishCh = channel('ci:mocha:suite:finish')
|
|
9
|
-
const hookErrorCh = channel('ci:mocha:hook:error')
|
|
10
8
|
const parameterizedTestCh = channel('ci:mocha:test:parameterize')
|
|
11
9
|
const testRunFinishCh = channel('ci:mocha:run:finish')
|
|
12
10
|
|
|
13
|
-
// TODO: remove when root hooks and fixtures are implemented
|
|
14
|
-
const patched = new WeakSet()
|
|
15
|
-
|
|
16
11
|
function isRetry (test) {
|
|
17
12
|
return test._currentRetry !== undefined && test._currentRetry !== 0
|
|
18
13
|
}
|
|
19
14
|
|
|
20
|
-
function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
suiteOrTest.tests.forEach(test => {
|
|
24
|
-
tests.push(test)
|
|
25
|
-
})
|
|
26
|
-
suiteOrTest.suites.forEach(suite => {
|
|
27
|
-
getTests(suite)
|
|
28
|
-
})
|
|
15
|
+
function getTestAsyncResource (test) {
|
|
16
|
+
if (!test.fn) {
|
|
17
|
+
return testToAr.get(test)
|
|
29
18
|
}
|
|
30
|
-
|
|
31
|
-
|
|
19
|
+
if (!test.fn.asyncResource) {
|
|
20
|
+
return testToAr.get(test.fn)
|
|
21
|
+
}
|
|
22
|
+
const originalFn = originalFns.get(test.fn)
|
|
23
|
+
return testToAr.get(originalFn)
|
|
32
24
|
}
|
|
33
25
|
|
|
26
|
+
// TODO: remove when root hooks and fixtures are implemented
|
|
27
|
+
const patched = new WeakSet()
|
|
28
|
+
|
|
29
|
+
const testToAr = new WeakMap()
|
|
30
|
+
const originalFns = new WeakMap()
|
|
31
|
+
|
|
34
32
|
function mochaHook (Runner) {
|
|
35
33
|
if (patched.has(Runner)) return Runner
|
|
36
34
|
|
|
37
35
|
patched.add(Runner)
|
|
38
36
|
|
|
39
|
-
shimmer.wrap(Runner.prototype, '
|
|
40
|
-
if (!testStartCh.hasSubscribers
|
|
41
|
-
return
|
|
37
|
+
shimmer.wrap(Runner.prototype, 'run', run => function () {
|
|
38
|
+
if (!testStartCh.hasSubscribers) {
|
|
39
|
+
return run.apply(this, arguments)
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
this.on('test', (test) => {
|
|
43
|
+
if (isRetry(test)) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
47
|
+
testToAr.set(test.fn, asyncResource)
|
|
48
|
+
asyncResource.runInAsyncScope(() => {
|
|
49
|
+
testStartCh.publish(test)
|
|
50
|
+
})
|
|
51
|
+
})
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
this.on('test end', (test) => {
|
|
54
|
+
const asyncResource = getTestAsyncResource(test)
|
|
55
|
+
let status
|
|
56
|
+
if (test.pending) {
|
|
57
|
+
status = 'skip'
|
|
58
|
+
} else if (test.state !== 'failed' && !test.timedOut) {
|
|
59
|
+
status = 'pass'
|
|
60
|
+
} else {
|
|
61
|
+
status = 'fail'
|
|
62
|
+
}
|
|
58
63
|
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
// if there are afterEach to be run, we don't finish the test yet
|
|
65
|
+
if (!test.parent._afterEach.length) {
|
|
66
|
+
asyncResource.runInAsyncScope(() => {
|
|
67
|
+
testFinishCh.publish(status)
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
})
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
// If the hook passes, 'hook end' will be emitted. Otherwise, 'fail' will be emitted
|
|
73
|
+
this.on('hook end', (hook) => {
|
|
74
|
+
const test = hook.ctx.currentTest
|
|
75
|
+
if (test && hook.parent._afterEach.includes(hook)) { // only if it's an afterEach
|
|
76
|
+
const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
|
|
77
|
+
if (isLastAfterEach) {
|
|
78
|
+
const asyncResource = getTestAsyncResource(test)
|
|
79
|
+
asyncResource.runInAsyncScope(() => {
|
|
80
|
+
testFinishCh.publish('pass')
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
})
|
|
65
85
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
86
|
+
this.on('fail', (testOrHook, err) => {
|
|
87
|
+
let test = testOrHook
|
|
88
|
+
const isHook = testOrHook.type === 'hook'
|
|
89
|
+
if (isHook && testOrHook.ctx) {
|
|
90
|
+
test = testOrHook.ctx.currentTest
|
|
91
|
+
}
|
|
92
|
+
const asyncResource = getTestAsyncResource(test)
|
|
93
|
+
if (asyncResource) {
|
|
94
|
+
asyncResource.runInAsyncScope(() => {
|
|
95
|
+
if (isHook) {
|
|
96
|
+
err.message = `${testOrHook.title}: ${err.message}`
|
|
97
|
+
errorCh.publish(err)
|
|
98
|
+
// if it's a hook and it has failed, 'test end' will not be called
|
|
99
|
+
testFinishCh.publish('fail')
|
|
100
|
+
} else {
|
|
101
|
+
errorCh.publish(err)
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
})
|
|
69
106
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
107
|
+
this.on('pending', (test) => {
|
|
108
|
+
const asyncResource = getTestAsyncResource(test)
|
|
109
|
+
if (asyncResource) {
|
|
110
|
+
asyncResource.runInAsyncScope(() => {
|
|
111
|
+
skipCh.publish(test)
|
|
112
|
+
})
|
|
113
|
+
} else {
|
|
114
|
+
// if there is no async resource, the test has been skipped through `test.skip``
|
|
115
|
+
const skippedTestAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
116
|
+
testToAr.set(test, skippedTestAsyncResource)
|
|
117
|
+
skippedTestAsyncResource.runInAsyncScope(() => {
|
|
118
|
+
skipCh.publish(test)
|
|
119
|
+
})
|
|
75
120
|
}
|
|
76
121
|
})
|
|
122
|
+
|
|
123
|
+
return run.apply(this, arguments)
|
|
77
124
|
})
|
|
78
125
|
|
|
79
126
|
shimmer.wrap(Runner.prototype, 'runTests', runTests => function () {
|
|
80
|
-
if (!
|
|
127
|
+
if (!testRunFinishCh.hasSubscribers) {
|
|
81
128
|
return runTests.apply(this, arguments)
|
|
82
129
|
}
|
|
83
130
|
this.once('end', AsyncResource.bind(() => {
|
|
84
131
|
testRunFinishCh.publish()
|
|
85
132
|
}))
|
|
86
|
-
runTests.apply(this, arguments)
|
|
87
|
-
const suite = arguments[0]
|
|
88
|
-
// We call `getAllTestsInSuite` with the root suite so every skipped test
|
|
89
|
-
// should already have an associated test span.
|
|
90
|
-
const tests = getAllTestsInSuite(suite)
|
|
91
|
-
suiteFinishCh.publish(tests)
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
shimmer.wrap(Runner.prototype, 'fail', fail => function (hook, error) {
|
|
95
|
-
if (!hookErrorCh.hasSubscribers) {
|
|
96
|
-
return fail.apply(this, arguments)
|
|
97
|
-
}
|
|
98
|
-
if (error && hook.ctx && hook.ctx.currentTest) {
|
|
99
|
-
error.message = `${hook.title}: ${error.message}`
|
|
100
|
-
hookErrorCh.publish({ test: hook.ctx.currentTest, error })
|
|
101
|
-
}
|
|
102
|
-
return fail.apply(this, arguments)
|
|
133
|
+
return runTests.apply(this, arguments)
|
|
103
134
|
})
|
|
104
135
|
|
|
105
136
|
return Runner
|
|
@@ -129,6 +160,41 @@ addHook({
|
|
|
129
160
|
file: 'lib/runner.js'
|
|
130
161
|
}, mochaHook)
|
|
131
162
|
|
|
163
|
+
addHook({
|
|
164
|
+
name: 'mocha',
|
|
165
|
+
versions: ['>=5.2.0'],
|
|
166
|
+
file: 'lib/runnable.js'
|
|
167
|
+
}, (Runnable) => {
|
|
168
|
+
shimmer.wrap(Runnable.prototype, 'run', run => function () {
|
|
169
|
+
const isBeforeEach = this.parent._beforeEach.includes(this)
|
|
170
|
+
const isAfterEach = this.parent._afterEach.includes(this)
|
|
171
|
+
|
|
172
|
+
const isTestHook = isBeforeEach || isAfterEach
|
|
173
|
+
|
|
174
|
+
// we restore the original user defined function
|
|
175
|
+
if (this.fn.asyncResource) {
|
|
176
|
+
const originalFn = originalFns.get(this.fn)
|
|
177
|
+
this.fn = originalFn
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (isTestHook || this.type === 'test') {
|
|
181
|
+
const test = isTestHook ? this.ctx.currentTest : this
|
|
182
|
+
const asyncResource = getTestAsyncResource(test)
|
|
183
|
+
|
|
184
|
+
// we bind the test fn to the correct async resource
|
|
185
|
+
const newFn = asyncResource.bind(this.fn)
|
|
186
|
+
|
|
187
|
+
// we store the original function, not to lose it
|
|
188
|
+
originalFns.set(newFn, this.fn)
|
|
189
|
+
|
|
190
|
+
this.fn = newFn
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return run.apply(this, arguments)
|
|
194
|
+
})
|
|
195
|
+
return Runnable
|
|
196
|
+
})
|
|
197
|
+
|
|
132
198
|
addHook({
|
|
133
199
|
name: 'mocha-each',
|
|
134
200
|
versions: ['>=2.0.1']
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// TODO: either instrument all or none of the render functions
|
|
4
|
+
|
|
5
|
+
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
|
|
6
|
+
const shimmer = require('../../datadog-shimmer')
|
|
7
|
+
|
|
8
|
+
const startChannel = channel('apm:next:request:start')
|
|
9
|
+
const finishChannel = channel('apm:next:request:finish')
|
|
10
|
+
const errorChannel = channel('apm:next:request:error')
|
|
11
|
+
const pageLoadChannel = channel('apm:next:page:load')
|
|
12
|
+
|
|
13
|
+
const requestResources = new WeakMap()
|
|
14
|
+
|
|
15
|
+
function wrapHandleRequest (handleRequest) {
|
|
16
|
+
return function (req, res, pathname, query) {
|
|
17
|
+
return instrument(req, res, () => handleRequest.apply(this, arguments))
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function wrapHandleApiRequest (handleApiRequest) {
|
|
22
|
+
return function (req, res, pathname, query) {
|
|
23
|
+
return instrument(req, res, () => {
|
|
24
|
+
const promise = handleApiRequest.apply(this, arguments)
|
|
25
|
+
|
|
26
|
+
return promise.then(handled => {
|
|
27
|
+
if (!handled) return handled
|
|
28
|
+
|
|
29
|
+
const page = getPageFromPath(pathname, this.dynamicRoutes)
|
|
30
|
+
|
|
31
|
+
pageLoadChannel.publish({ page })
|
|
32
|
+
|
|
33
|
+
return handled
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function wrapRenderToResponse (renderToResponse) {
|
|
40
|
+
return function (ctx) {
|
|
41
|
+
return instrument(ctx.req, ctx.res, () => renderToResponse.apply(this, arguments))
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function wrapRenderErrorToResponse (renderErrorToResponse) {
|
|
46
|
+
return function (ctx) {
|
|
47
|
+
return instrument(ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments))
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function wrapRenderToHTML (renderToHTML) {
|
|
52
|
+
return function (req, res, pathname, query, parsedUrl) {
|
|
53
|
+
return instrument(req, res, () => renderToHTML.apply(this, arguments))
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function wrapRenderErrorToHTML (renderErrorToHTML) {
|
|
58
|
+
return function (err, req, res, pathname, query) {
|
|
59
|
+
return instrument(req, res, () => renderErrorToHTML.apply(this, arguments))
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function wrapFindPageComponents (findPageComponents) {
|
|
64
|
+
return function (pathname, query) {
|
|
65
|
+
const result = findPageComponents.apply(this, arguments)
|
|
66
|
+
|
|
67
|
+
if (result) {
|
|
68
|
+
pageLoadChannel.publish({ page: pathname })
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return result
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function getPageFromPath (page, dynamicRoutes = []) {
|
|
76
|
+
for (const dynamicRoute of dynamicRoutes) {
|
|
77
|
+
if (dynamicRoute.page.startsWith('/api') && dynamicRoute.match(page)) {
|
|
78
|
+
return dynamicRoute.page
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return page
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function instrument (req, res, handler) {
|
|
86
|
+
if (requestResources.has(req)) return handler()
|
|
87
|
+
|
|
88
|
+
const requestResource = new AsyncResource('bound-anonymous-fn')
|
|
89
|
+
|
|
90
|
+
requestResources.set(req, requestResource)
|
|
91
|
+
|
|
92
|
+
return requestResource.runInAsyncScope(() => {
|
|
93
|
+
startChannel.publish({ req, res })
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const promise = handler()
|
|
97
|
+
|
|
98
|
+
return promise.then(
|
|
99
|
+
result => finish(req, res, result),
|
|
100
|
+
err => finish(req, res, null, err)
|
|
101
|
+
)
|
|
102
|
+
} catch (e) {
|
|
103
|
+
finish(req, res, null, e)
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function finish (req, res, result, err) {
|
|
109
|
+
if (err) {
|
|
110
|
+
errorChannel.publish(err)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
finishChannel.publish({ req, res })
|
|
114
|
+
|
|
115
|
+
return result || err
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
addHook({ name: 'next', versions: ['>=11.1'], file: 'dist/server/next-server.js' }, nextServer => {
|
|
119
|
+
const Server = nextServer.default
|
|
120
|
+
|
|
121
|
+
shimmer.wrap(Server.prototype, 'handleRequest', wrapHandleRequest)
|
|
122
|
+
shimmer.wrap(Server.prototype, 'handleApiRequest', wrapHandleApiRequest)
|
|
123
|
+
shimmer.wrap(Server.prototype, 'renderToResponse', wrapRenderToResponse)
|
|
124
|
+
shimmer.wrap(Server.prototype, 'renderErrorToResponse', wrapRenderErrorToResponse)
|
|
125
|
+
shimmer.wrap(Server.prototype, 'findPageComponents', wrapFindPageComponents)
|
|
126
|
+
|
|
127
|
+
return nextServer
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
addHook({ name: 'next', versions: ['>=9.5 <11.1'], file: 'dist/next-server/server/next-server.js' }, nextServer => {
|
|
131
|
+
const Server = nextServer.default
|
|
132
|
+
|
|
133
|
+
shimmer.wrap(Server.prototype, 'handleRequest', wrapHandleRequest)
|
|
134
|
+
shimmer.wrap(Server.prototype, 'handleApiRequest', wrapHandleApiRequest)
|
|
135
|
+
shimmer.wrap(Server.prototype, 'renderToHTML', wrapRenderToHTML)
|
|
136
|
+
shimmer.wrap(Server.prototype, 'renderErrorToHTML', wrapRenderErrorToHTML)
|
|
137
|
+
shimmer.wrap(Server.prototype, 'findPageComponents', wrapFindPageComponents)
|
|
138
|
+
|
|
139
|
+
return nextServer
|
|
140
|
+
})
|
|
@@ -7,6 +7,7 @@ const { addHook, channel, AsyncResource } = require('./helpers/instrument')
|
|
|
7
7
|
|
|
8
8
|
function createWrapRouterMethod (name) {
|
|
9
9
|
const enterChannel = channel(`apm:${name}:middleware:enter`)
|
|
10
|
+
const exitChannel = channel(`apm:${name}:middleware:exit`)
|
|
10
11
|
const errorChannel = channel(`apm:${name}:middleware:error`)
|
|
11
12
|
const nextChannel = channel(`apm:${name}:middleware:next`)
|
|
12
13
|
|
|
@@ -51,6 +52,7 @@ function createWrapRouterMethod (name) {
|
|
|
51
52
|
} catch (e) {
|
|
52
53
|
errorChannel.publish(e)
|
|
53
54
|
nextChannel.publish({ req })
|
|
55
|
+
exitChannel.publish({ req })
|
|
54
56
|
|
|
55
57
|
throw e
|
|
56
58
|
}
|
|
@@ -93,6 +95,7 @@ function createWrapRouterMethod (name) {
|
|
|
93
95
|
}
|
|
94
96
|
|
|
95
97
|
nextChannel.publish({ req })
|
|
98
|
+
exitChannel.publish({ req })
|
|
96
99
|
|
|
97
100
|
next.apply(null, arguments)
|
|
98
101
|
}
|
|
@@ -13,7 +13,7 @@ addHook({ name: 'tedious', versions: [ '>=1.0.0' ] }, tedious => {
|
|
|
13
13
|
const errorCh = channel('apm:tedious:request:error')
|
|
14
14
|
shimmer.wrap(tedious.Connection.prototype, 'makeRequest', makeRequest => function (request) {
|
|
15
15
|
if (!startCh.hasSubscribers) {
|
|
16
|
-
return
|
|
16
|
+
return makeRequest.apply(this, arguments)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
const queryOrProcedure = getQueryOrProcedure(request)
|