dd-trace 2.11.0 → 2.12.1
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/LICENSE-3rdparty.csv +0 -1
- package/index.d.ts +3 -3
- package/package.json +4 -5
- package/packages/datadog-core/src/storage/async_hooks.js +4 -4
- package/packages/datadog-core/src/storage/async_resource.js +14 -4
- package/packages/datadog-instrumentations/src/connect.js +4 -4
- package/packages/datadog-instrumentations/src/couchbase.js +166 -61
- package/packages/datadog-instrumentations/src/fastify.js +12 -25
- package/packages/datadog-instrumentations/src/graphql.js +17 -5
- package/packages/datadog-instrumentations/src/koa.js +4 -4
- package/packages/datadog-instrumentations/src/mocha.js +88 -18
- package/packages/datadog-instrumentations/src/restify.js +4 -8
- package/packages/datadog-instrumentations/src/router.js +4 -4
- package/packages/datadog-plugin-couchbase/src/index.js +8 -10
- package/packages/datadog-plugin-graphql/src/resolve.js +2 -0
- package/packages/datadog-plugin-http/src/server.js +3 -8
- package/packages/datadog-plugin-mocha/src/index.js +80 -3
- package/packages/datadog-plugin-next/src/index.js +1 -1
- package/packages/datadog-plugin-router/src/index.js +39 -10
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +111 -15
- package/packages/dd-trace/src/plugin_manager.js +49 -33
- package/packages/dd-trace/src/plugins/util/test.js +32 -1
- package/packages/dd-trace/src/plugins/util/web.js +25 -17
- package/packages/dd-trace/src/profiling/config.js +10 -2
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -2
- package/packages/dd-trace/src/profiling/exporters/form-data.js +53 -0
- package/packages/dd-trace/src/profiling/index.js +2 -0
- package/packages/dd-trace/src/profiling/profiler.js +6 -1
- package/packages/dd-trace/src/profiling/profilers/cpu.js +126 -0
|
@@ -6,8 +6,31 @@ 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
8
|
const parameterizedTestCh = channel('ci:mocha:test:parameterize')
|
|
9
|
+
|
|
10
|
+
const testRunStartCh = channel('ci:mocha:run:start')
|
|
9
11
|
const testRunFinishCh = channel('ci:mocha:run:finish')
|
|
10
12
|
|
|
13
|
+
const testSuiteStartCh = channel('ci:mocha:test-suite:start')
|
|
14
|
+
const testSuiteFinishCh = channel('ci:mocha:test-suite:finish')
|
|
15
|
+
const testSuiteErrorCh = channel('ci:mocha:test-suite:error')
|
|
16
|
+
|
|
17
|
+
// TODO: remove when root hooks and fixtures are implemented
|
|
18
|
+
const patched = new WeakSet()
|
|
19
|
+
|
|
20
|
+
const testToAr = new WeakMap()
|
|
21
|
+
const originalFns = new WeakMap()
|
|
22
|
+
const testSuiteToAr = new WeakMap()
|
|
23
|
+
|
|
24
|
+
function getTestStatus (test) {
|
|
25
|
+
if (test.pending) {
|
|
26
|
+
return 'skip'
|
|
27
|
+
}
|
|
28
|
+
if (test.state !== 'failed' && !test.timedOut) {
|
|
29
|
+
return 'pass'
|
|
30
|
+
}
|
|
31
|
+
return 'fail'
|
|
32
|
+
}
|
|
33
|
+
|
|
11
34
|
function isRetry (test) {
|
|
12
35
|
return test._currentRetry !== undefined && test._currentRetry !== 0
|
|
13
36
|
}
|
|
@@ -23,12 +46,6 @@ function getTestAsyncResource (test) {
|
|
|
23
46
|
return testToAr.get(originalFn)
|
|
24
47
|
}
|
|
25
48
|
|
|
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
|
-
|
|
32
49
|
function mochaHook (Runner) {
|
|
33
50
|
if (patched.has(Runner)) return Runner
|
|
34
51
|
|
|
@@ -39,6 +56,59 @@ function mochaHook (Runner) {
|
|
|
39
56
|
return run.apply(this, arguments)
|
|
40
57
|
}
|
|
41
58
|
|
|
59
|
+
const testRunAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
60
|
+
|
|
61
|
+
this.once('end', testRunAsyncResource.bind(function () {
|
|
62
|
+
let status = 'pass'
|
|
63
|
+
if (this.stats) {
|
|
64
|
+
status = this.stats.failures === 0 ? 'pass' : 'fail'
|
|
65
|
+
} else if (this.failures !== 0) {
|
|
66
|
+
status = 'fail'
|
|
67
|
+
}
|
|
68
|
+
testRunFinishCh.publish(status)
|
|
69
|
+
}))
|
|
70
|
+
|
|
71
|
+
this.once('start', testRunAsyncResource.bind(function () {
|
|
72
|
+
const processArgv = process.argv.slice(2).join(' ')
|
|
73
|
+
const command = `mocha ${processArgv}`
|
|
74
|
+
testRunStartCh.publish(command)
|
|
75
|
+
}))
|
|
76
|
+
|
|
77
|
+
this.on('suite', function (suite) {
|
|
78
|
+
if (suite.root) {
|
|
79
|
+
return
|
|
80
|
+
}
|
|
81
|
+
const asyncResource = new AsyncResource('bound-anonymous-fn')
|
|
82
|
+
|
|
83
|
+
testSuiteToAr.set(suite, asyncResource)
|
|
84
|
+
|
|
85
|
+
asyncResource.runInAsyncScope(() => {
|
|
86
|
+
testSuiteStartCh.publish(suite)
|
|
87
|
+
})
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
this.on('suite end', function (suite) {
|
|
91
|
+
if (suite.root) {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
let status = 'pass'
|
|
95
|
+
if (suite.pending) {
|
|
96
|
+
status = 'skip'
|
|
97
|
+
} else {
|
|
98
|
+
suite.eachTest(test => {
|
|
99
|
+
if (test.state === 'failed' || test.timedOut) {
|
|
100
|
+
status = 'fail'
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const asyncResource = testSuiteToAr.get(suite)
|
|
106
|
+
asyncResource.runInAsyncScope(() => {
|
|
107
|
+
// get suite status
|
|
108
|
+
testSuiteFinishCh.publish(status)
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
42
112
|
this.on('test', (test) => {
|
|
43
113
|
if (isRetry(test)) {
|
|
44
114
|
return
|
|
@@ -52,14 +122,7 @@ function mochaHook (Runner) {
|
|
|
52
122
|
|
|
53
123
|
this.on('test end', (test) => {
|
|
54
124
|
const asyncResource = getTestAsyncResource(test)
|
|
55
|
-
|
|
56
|
-
if (test.pending) {
|
|
57
|
-
status = 'skip'
|
|
58
|
-
} else if (test.state !== 'failed' && !test.timedOut) {
|
|
59
|
-
status = 'pass'
|
|
60
|
-
} else {
|
|
61
|
-
status = 'fail'
|
|
62
|
-
}
|
|
125
|
+
const status = getTestStatus(test)
|
|
63
126
|
|
|
64
127
|
// if there are afterEach to be run, we don't finish the test yet
|
|
65
128
|
if (!test.parent._afterEach.length) {
|
|
@@ -75,9 +138,10 @@ function mochaHook (Runner) {
|
|
|
75
138
|
if (test && hook.parent._afterEach.includes(hook)) { // only if it's an afterEach
|
|
76
139
|
const isLastAfterEach = hook.parent._afterEach.indexOf(hook) === hook.parent._afterEach.length - 1
|
|
77
140
|
if (isLastAfterEach) {
|
|
141
|
+
const status = getTestStatus(test)
|
|
78
142
|
const asyncResource = getTestAsyncResource(test)
|
|
79
143
|
asyncResource.runInAsyncScope(() => {
|
|
80
|
-
testFinishCh.publish(
|
|
144
|
+
testFinishCh.publish(status)
|
|
81
145
|
})
|
|
82
146
|
}
|
|
83
147
|
}
|
|
@@ -100,6 +164,15 @@ function mochaHook (Runner) {
|
|
|
100
164
|
} else {
|
|
101
165
|
errorCh.publish(err)
|
|
102
166
|
}
|
|
167
|
+
// we propagate the error to the suite
|
|
168
|
+
const testSuiteAsyncResource = testSuiteToAr.get(test.parent)
|
|
169
|
+
if (testSuiteAsyncResource) {
|
|
170
|
+
const testSuiteError = new Error(`Test "${test.fullTitle()}" failed with message "${err.message}"`)
|
|
171
|
+
testSuiteError.stack = err.stack
|
|
172
|
+
testSuiteAsyncResource.runInAsyncScope(() => {
|
|
173
|
+
testSuiteErrorCh.publish(testSuiteError)
|
|
174
|
+
})
|
|
175
|
+
}
|
|
103
176
|
})
|
|
104
177
|
}
|
|
105
178
|
})
|
|
@@ -127,9 +200,6 @@ function mochaHook (Runner) {
|
|
|
127
200
|
if (!testRunFinishCh.hasSubscribers) {
|
|
128
201
|
return runTests.apply(this, arguments)
|
|
129
202
|
}
|
|
130
|
-
this.once('end', AsyncResource.bind(() => {
|
|
131
|
-
testRunFinishCh.publish()
|
|
132
|
-
}))
|
|
133
203
|
return runTests.apply(this, arguments)
|
|
134
204
|
})
|
|
135
205
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel
|
|
4
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
5
5
|
const handlers = ['use', 'pre']
|
|
6
6
|
const methods = ['del', 'get', 'head', 'opts', 'post', 'put', 'patch']
|
|
7
7
|
|
|
@@ -9,14 +9,14 @@ const handleChannel = channel('apm:restify:request:handle')
|
|
|
9
9
|
const routeChannel = channel('apm:restify:request:route')
|
|
10
10
|
|
|
11
11
|
function wrapSetupRequest (setupRequest) {
|
|
12
|
-
return function
|
|
12
|
+
return function (req, res) {
|
|
13
13
|
handleChannel.publish({ req, res })
|
|
14
14
|
return setupRequest.apply(this, arguments)
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
function wrapMethod (method) {
|
|
19
|
-
return function
|
|
19
|
+
return function (path) {
|
|
20
20
|
const middleware = wrapMiddleware(Array.prototype.slice.call(arguments, 1))
|
|
21
21
|
|
|
22
22
|
return method.apply(this, [path].concat(middleware))
|
|
@@ -24,7 +24,7 @@ function wrapMethod (method) {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
function wrapHandler (method) {
|
|
27
|
-
return function
|
|
27
|
+
return function () {
|
|
28
28
|
return method.apply(this, wrapMiddleware(arguments))
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -37,10 +37,6 @@ function wrapFn (fn) {
|
|
|
37
37
|
if (Array.isArray(fn)) return wrapMiddleware(fn)
|
|
38
38
|
|
|
39
39
|
return function (req, res, next) {
|
|
40
|
-
if (typeof next === 'function') {
|
|
41
|
-
arguments[2] = AsyncResource.bind(next)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
40
|
if (req.route) {
|
|
45
41
|
routeChannel.publish({ req, route: req.route })
|
|
46
42
|
}
|
|
@@ -49,12 +49,12 @@ function createWrapRouterMethod (name) {
|
|
|
49
49
|
|
|
50
50
|
try {
|
|
51
51
|
return original.apply(this, arguments)
|
|
52
|
-
} catch (
|
|
53
|
-
errorChannel.publish(
|
|
52
|
+
} catch (error) {
|
|
53
|
+
errorChannel.publish({ req, error })
|
|
54
54
|
nextChannel.publish({ req })
|
|
55
55
|
exitChannel.publish({ req })
|
|
56
56
|
|
|
57
|
-
throw
|
|
57
|
+
throw error
|
|
58
58
|
}
|
|
59
59
|
})
|
|
60
60
|
})
|
|
@@ -91,7 +91,7 @@ function createWrapRouterMethod (name) {
|
|
|
91
91
|
function wrapNext (req, next) {
|
|
92
92
|
return function (error) {
|
|
93
93
|
if (error) {
|
|
94
|
-
errorChannel.publish(error)
|
|
94
|
+
errorChannel.publish({ req, error })
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
nextChannel.publish({ req })
|
|
@@ -11,11 +11,11 @@ class CouchBasePlugin extends Plugin {
|
|
|
11
11
|
|
|
12
12
|
addSubs (func, start, finish = defaultFinish) {
|
|
13
13
|
this.addSub(`apm:couchbase:${func}:start`, start)
|
|
14
|
-
this.addSub(`apm:couchbase:${func}:error`,
|
|
14
|
+
this.addSub(`apm:couchbase:${func}:error`, this.addError)
|
|
15
15
|
this.addSub(`apm:couchbase:${func}:finish`, finish)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
startSpan (operation, customTags, store, bucket) {
|
|
18
|
+
startSpan (operation, customTags, store, { bucket, collection }) {
|
|
19
19
|
const tags = {
|
|
20
20
|
'db.type': 'couchbase',
|
|
21
21
|
'component': 'couchbase',
|
|
@@ -32,7 +32,8 @@ class CouchBasePlugin extends Plugin {
|
|
|
32
32
|
tags
|
|
33
33
|
})
|
|
34
34
|
|
|
35
|
-
span.setTag(
|
|
35
|
+
if (bucket) span.setTag(`couchbase.bucket.name`, bucket.name)
|
|
36
|
+
if (collection) span.setTag(`couchbase.collection.name`, collection.name)
|
|
36
37
|
|
|
37
38
|
analyticsSampler.sample(span, this.config.measured)
|
|
38
39
|
return span
|
|
@@ -43,7 +44,8 @@ class CouchBasePlugin extends Plugin {
|
|
|
43
44
|
|
|
44
45
|
this.addSubs('query', ({ resource, bucket }) => {
|
|
45
46
|
const store = storage.getStore()
|
|
46
|
-
const span = this.startSpan('query', { 'span.type': 'sql', 'resource.name': resource },
|
|
47
|
+
const span = this.startSpan('query', { 'span.type': 'sql', 'resource.name': resource },
|
|
48
|
+
store, { bucket })
|
|
47
49
|
this.enter(span, store)
|
|
48
50
|
})
|
|
49
51
|
|
|
@@ -54,9 +56,9 @@ class CouchBasePlugin extends Plugin {
|
|
|
54
56
|
this._addCommandSubs('prepend')
|
|
55
57
|
}
|
|
56
58
|
_addCommandSubs (name) {
|
|
57
|
-
this.addSubs(name, ({ bucket }) => {
|
|
59
|
+
this.addSubs(name, ({ bucket, collection }) => {
|
|
58
60
|
const store = storage.getStore()
|
|
59
|
-
const span = this.startSpan(name, {}, store, bucket)
|
|
61
|
+
const span = this.startSpan(name, {}, store, { bucket, collection })
|
|
60
62
|
this.enter(span, store)
|
|
61
63
|
})
|
|
62
64
|
}
|
|
@@ -66,8 +68,4 @@ function defaultFinish () {
|
|
|
66
68
|
storage.getStore().span.finish()
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
function errorHandler (error) {
|
|
70
|
-
storage.getStore().span.setTag('error', error)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
71
|
module.exports = CouchBasePlugin
|
|
@@ -17,7 +17,7 @@ class HttpServerPlugin extends Plugin {
|
|
|
17
17
|
const store = storage.getStore()
|
|
18
18
|
const span = web.startSpan(this.tracer, this.config, req, res, 'http.request')
|
|
19
19
|
|
|
20
|
-
this.enter(span, store)
|
|
20
|
+
this.enter(span, { ...store, req })
|
|
21
21
|
|
|
22
22
|
const context = web.getContext(req)
|
|
23
23
|
|
|
@@ -32,12 +32,7 @@ class HttpServerPlugin extends Plugin {
|
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
this.addSub('apm:http:server:request:error', (error) => {
|
|
35
|
-
|
|
36
|
-
span.addTags({
|
|
37
|
-
'error.type': error.name,
|
|
38
|
-
'error.msg': error.message,
|
|
39
|
-
'error.stack': error.stack
|
|
40
|
-
})
|
|
35
|
+
web.addError(error)
|
|
41
36
|
})
|
|
42
37
|
|
|
43
38
|
this.addSub('apm:http:server:request:finish', ({ req }) => {
|
|
@@ -45,7 +40,7 @@ class HttpServerPlugin extends Plugin {
|
|
|
45
40
|
|
|
46
41
|
if (!context || !context.res) return // Not created by a http.Server instance.
|
|
47
42
|
|
|
48
|
-
web.
|
|
43
|
+
web.finishAll(context)
|
|
49
44
|
})
|
|
50
45
|
}
|
|
51
46
|
|
|
@@ -16,7 +16,12 @@ const {
|
|
|
16
16
|
getTestParametersString,
|
|
17
17
|
getCodeOwnersFileEntries,
|
|
18
18
|
getCodeOwnersForFilename,
|
|
19
|
-
getTestCommonTags
|
|
19
|
+
getTestCommonTags,
|
|
20
|
+
getTestSessionCommonTags,
|
|
21
|
+
getTestSuiteCommonTags,
|
|
22
|
+
TEST_SUITE_ID,
|
|
23
|
+
TEST_SESSION_ID,
|
|
24
|
+
TEST_COMMAND
|
|
20
25
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
21
26
|
|
|
22
27
|
function getTestSpanMetadata (tracer, test, sourceRoot) {
|
|
@@ -42,11 +47,63 @@ class MochaPlugin extends Plugin {
|
|
|
42
47
|
constructor (...args) {
|
|
43
48
|
super(...args)
|
|
44
49
|
|
|
50
|
+
this._testSuites = new WeakMap()
|
|
45
51
|
this._testNameToParams = {}
|
|
46
52
|
this.testEnvironmentMetadata = getTestEnvironmentMetadata('mocha', this.config)
|
|
47
53
|
this.sourceRoot = process.cwd()
|
|
48
54
|
this.codeOwnersEntries = getCodeOwnersFileEntries(this.sourceRoot)
|
|
49
55
|
|
|
56
|
+
this.addSub('ci:mocha:run:start', (command) => {
|
|
57
|
+
if (!this.config.isAgentlessEnabled) {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
const childOf = getTestParentSpan(this.tracer)
|
|
61
|
+
const testSessionSpanMetadata = getTestSessionCommonTags(command, this.tracer._version)
|
|
62
|
+
|
|
63
|
+
this.command = command
|
|
64
|
+
this.testSessionSpan = this.tracer.startSpan('mocha.test_session', {
|
|
65
|
+
childOf,
|
|
66
|
+
tags: {
|
|
67
|
+
...this.testEnvironmentMetadata,
|
|
68
|
+
...testSessionSpanMetadata
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
this.addSub('ci:mocha:test-suite:start', (suite) => {
|
|
74
|
+
if (!this.config.isAgentlessEnabled) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
const store = storage.getStore()
|
|
78
|
+
const testSuiteMetadata = getTestSuiteCommonTags(this.command, this.tracer._version, suite.fullTitle())
|
|
79
|
+
const testSuiteSpan = this.tracer.startSpan('mocha.test_suite', {
|
|
80
|
+
childOf: this.testSessionSpan,
|
|
81
|
+
tags: {
|
|
82
|
+
...this.testEnvironmentMetadata,
|
|
83
|
+
...testSuiteMetadata
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
this.enter(testSuiteSpan, store)
|
|
87
|
+
this._testSuites.set(suite, testSuiteSpan)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
this.addSub('ci:mocha:test-suite:finish', (status) => {
|
|
91
|
+
if (!this.config.isAgentlessEnabled) {
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
const span = storage.getStore().span
|
|
95
|
+
span.setTag(TEST_STATUS, status)
|
|
96
|
+
span.finish()
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
this.addSub('ci:mocha:test-suite:error', (err) => {
|
|
100
|
+
if (!this.config.isAgentlessEnabled) {
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
const span = storage.getStore().span
|
|
104
|
+
span.setTag('error', err)
|
|
105
|
+
})
|
|
106
|
+
|
|
50
107
|
this.addSub('ci:mocha:test:start', (test) => {
|
|
51
108
|
const store = storage.getStore()
|
|
52
109
|
const span = this.startTestSpan(test)
|
|
@@ -89,12 +146,31 @@ class MochaPlugin extends Plugin {
|
|
|
89
146
|
this._testNameToParams[name] = params
|
|
90
147
|
})
|
|
91
148
|
|
|
92
|
-
this.addSub('ci:mocha:run:finish', () => {
|
|
149
|
+
this.addSub('ci:mocha:run:finish', (status) => {
|
|
150
|
+
if (this.testSessionSpan) {
|
|
151
|
+
this.testSessionSpan.setTag(TEST_STATUS, status)
|
|
152
|
+
this.testSessionSpan.finish()
|
|
153
|
+
finishAllTraceSpans(this.testSessionSpan)
|
|
154
|
+
}
|
|
93
155
|
this.tracer._exporter._writer.flush()
|
|
94
156
|
})
|
|
95
157
|
}
|
|
96
158
|
|
|
97
159
|
startTestSpan (test) {
|
|
160
|
+
const testSuiteTags = {}
|
|
161
|
+
const testSuiteSpan = this._testSuites.get(test.parent)
|
|
162
|
+
|
|
163
|
+
if (testSuiteSpan) {
|
|
164
|
+
const testSuiteId = testSuiteSpan.context()._spanId.toString('hex')
|
|
165
|
+
testSuiteTags[TEST_SUITE_ID] = testSuiteId
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (this.testSessionSpan) {
|
|
169
|
+
const testSessionId = this.testSessionSpan.context()._traceId.toString('hex')
|
|
170
|
+
testSuiteTags[TEST_SESSION_ID] = testSessionId
|
|
171
|
+
testSuiteTags[TEST_COMMAND] = this.command
|
|
172
|
+
}
|
|
173
|
+
|
|
98
174
|
const { childOf, ...testSpanMetadata } = getTestSpanMetadata(this.tracer, test, this.sourceRoot)
|
|
99
175
|
|
|
100
176
|
const testParametersString = getTestParametersString(this._testNameToParams, test.title)
|
|
@@ -112,7 +188,8 @@ class MochaPlugin extends Plugin {
|
|
|
112
188
|
childOf,
|
|
113
189
|
tags: {
|
|
114
190
|
...this.testEnvironmentMetadata,
|
|
115
|
-
...testSpanMetadata
|
|
191
|
+
...testSpanMetadata,
|
|
192
|
+
...testSuiteTags
|
|
116
193
|
}
|
|
117
194
|
})
|
|
118
195
|
testSpan.context()._trace.origin = CI_APP_ORIGIN
|
|
@@ -16,11 +16,18 @@ class RouterPlugin extends WebPlugin {
|
|
|
16
16
|
this._contexts = new WeakMap()
|
|
17
17
|
|
|
18
18
|
this.addSub(`apm:${this.constructor.name}:middleware:enter`, ({ req, name, route }) => {
|
|
19
|
-
const
|
|
20
|
-
const context = this._createContext(req, route)
|
|
21
|
-
const span = this._getMiddlewareSpan(context, store, name)
|
|
19
|
+
const childOf = this._getActive(req) || this._getStoreSpan()
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
if (!childOf) return
|
|
22
|
+
|
|
23
|
+
const span = this._getMiddlewareSpan(name, childOf)
|
|
24
|
+
const context = this._createContext(req, route, childOf)
|
|
25
|
+
|
|
26
|
+
if (childOf !== span) {
|
|
27
|
+
context.middleware.push(span)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.enter(span)
|
|
24
31
|
|
|
25
32
|
web.patch(req)
|
|
26
33
|
web.setRoute(req, context.route)
|
|
@@ -42,7 +49,17 @@ class RouterPlugin extends WebPlugin {
|
|
|
42
49
|
context.middleware.pop().finish()
|
|
43
50
|
})
|
|
44
51
|
|
|
45
|
-
this.addSub(`apm:${this.constructor.name}:middleware:error`,
|
|
52
|
+
this.addSub(`apm:${this.constructor.name}:middleware:error`, ({ req, error }) => {
|
|
53
|
+
web.addError(req, error)
|
|
54
|
+
|
|
55
|
+
if (!this.config.middleware) return
|
|
56
|
+
|
|
57
|
+
const span = this._getActive(req)
|
|
58
|
+
|
|
59
|
+
if (!span) return
|
|
60
|
+
|
|
61
|
+
span.setTag('error', error)
|
|
62
|
+
})
|
|
46
63
|
|
|
47
64
|
this.addSub(`apm:http:server:request:finish`, ({ req }) => {
|
|
48
65
|
const context = this._contexts.get(req)
|
|
@@ -57,9 +74,22 @@ class RouterPlugin extends WebPlugin {
|
|
|
57
74
|
})
|
|
58
75
|
}
|
|
59
76
|
|
|
60
|
-
|
|
61
|
-
const
|
|
77
|
+
_getActive (req) {
|
|
78
|
+
const context = this._contexts.get(req)
|
|
79
|
+
|
|
80
|
+
if (!context) return
|
|
81
|
+
if (context.middleware.length === 0) return context.span
|
|
82
|
+
|
|
83
|
+
return context.middleware[context.middleware.length - 1]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
_getStoreSpan () {
|
|
87
|
+
const store = storage.getStore()
|
|
88
|
+
|
|
89
|
+
return store && store.span
|
|
90
|
+
}
|
|
62
91
|
|
|
92
|
+
_getMiddlewareSpan (name, childOf) {
|
|
63
93
|
if (this.config.middleware === false) {
|
|
64
94
|
return childOf
|
|
65
95
|
}
|
|
@@ -71,14 +101,12 @@ class RouterPlugin extends WebPlugin {
|
|
|
71
101
|
}
|
|
72
102
|
})
|
|
73
103
|
|
|
74
|
-
context.middleware.push(span)
|
|
75
|
-
|
|
76
104
|
analyticsSampler.sample(span, this.config.measured)
|
|
77
105
|
|
|
78
106
|
return span
|
|
79
107
|
}
|
|
80
108
|
|
|
81
|
-
_createContext (req, route) {
|
|
109
|
+
_createContext (req, route, span) {
|
|
82
110
|
let context = this._contexts.get(req)
|
|
83
111
|
|
|
84
112
|
if (!route || route === '/' || route === '*') {
|
|
@@ -96,6 +124,7 @@ class RouterPlugin extends WebPlugin {
|
|
|
96
124
|
}
|
|
97
125
|
} else {
|
|
98
126
|
context = {
|
|
127
|
+
span,
|
|
99
128
|
stack: [route],
|
|
100
129
|
route,
|
|
101
130
|
middleware: []
|