dd-trace 1.4.0 → 1.5.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 +1 -1
- package/package.json +6 -6
- package/packages/datadog-plugin-cucumber/src/index.js +6 -13
- package/packages/datadog-plugin-graphql/src/index.js +16 -10
- package/packages/datadog-plugin-grpc/src/client.js +1 -1
- package/packages/datadog-plugin-jest/src/jest-environment.js +3 -2
- package/packages/datadog-plugin-jest/src/jest-jasmine2.js +4 -3
- package/packages/datadog-plugin-mocha/src/index.js +12 -5
- package/packages/dd-trace/lib/version.js +1 -1
- package/packages/dd-trace/src/encode/0.4.js +84 -23
- package/packages/dd-trace/src/encode/chunk.js +12 -14
- package/packages/dd-trace/src/id.js +22 -18
- package/packages/dd-trace/src/instrumenter.js +2 -2
- package/packages/dd-trace/src/loader.js +16 -50
- package/packages/dd-trace/src/opentracing/span.js +8 -0
- package/packages/dd-trace/src/plugins/util/redis.js +1 -1
- package/packages/dd-trace/src/plugins/util/test.js +17 -1
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +11 -4
- package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -3
- package/packages/dd-trace/src/proxy.js +1 -1
- package/packages/dd-trace/src/span_processor.js +76 -2
- package/NOTICE +0 -4
package/LICENSE-3rdparty.csv
CHANGED
|
@@ -18,6 +18,7 @@ require,multer,MIT,Copyright 2014 Hage Yaapa
|
|
|
18
18
|
require,opentracing,MIT,Copyright 2016 Resonance Labs Inc
|
|
19
19
|
require,path-to-regexp,MIT,Copyright 2014 Blake Embrey
|
|
20
20
|
require,performance-now,MIT,Copyright 2013 Braveg1rl
|
|
21
|
+
require,retry,MIT,Copyright 2011 Tim Koschützki Felix Geisendörfer
|
|
21
22
|
require,semver,ISC,Copyright Isaac Z. Schlueter and Contributors
|
|
22
23
|
require,source-map,BSD-3-Clause,Copyright 2009-2011 Mozilla Foundation and contributors
|
|
23
24
|
require,source-map-resolve,MIT,Copyright 2014-2020 Simon Lydell 2019 Jinxiang
|
|
@@ -51,7 +52,6 @@ dev,msgpack-lite,MIT,Copyright 2015 Yusuke Kawasaki
|
|
|
51
52
|
dev,nock,MIT,Copyright 2017 Pedro Teixeira and other contributors
|
|
52
53
|
dev,nyc,ISC,Copyright 2015 Contributors
|
|
53
54
|
dev,proxyquire,MIT,Copyright 2013 Thorsten Lorenz
|
|
54
|
-
dev,retry,MIT,Copyright 2011 Tim Koschützki Felix Geisendörfer
|
|
55
55
|
dev,rimraf,ISC,Copyright Isaac Z. Schlueter and Contributors
|
|
56
56
|
dev,sinon,BSD-3-Clause,Copyright 2010-2017 Christian Johansen
|
|
57
57
|
dev,sinon-chai,WTFPL and BSD-2-Clause,Copyright 2004 Sam Hocevar 2012–2017 Domenic Denicola
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -56,13 +56,13 @@
|
|
|
56
56
|
"node": ">=12"
|
|
57
57
|
},
|
|
58
58
|
"dependencies": {
|
|
59
|
-
"@datadog/native-metrics": "^1.0.
|
|
60
|
-
"@datadog/pprof": "^0.
|
|
59
|
+
"@datadog/native-metrics": "^1.0.1",
|
|
60
|
+
"@datadog/pprof": "^0.3.0",
|
|
61
61
|
"@datadog/sketches-js": "^1.0.4",
|
|
62
62
|
"@types/node": "^10.12.18",
|
|
63
63
|
"crypto-randomuuid": "^1.0.0",
|
|
64
64
|
"form-data": "^3.0.0",
|
|
65
|
-
"import-in-the-middle": "^1.1.
|
|
65
|
+
"import-in-the-middle": "^1.1.2",
|
|
66
66
|
"koalas": "^1.0.2",
|
|
67
67
|
"limiter": "^1.1.4",
|
|
68
68
|
"lodash.kebabcase": "^4.1.1",
|
|
@@ -75,13 +75,14 @@
|
|
|
75
75
|
"opentracing": ">=0.12.1",
|
|
76
76
|
"path-to-regexp": "^0.1.2",
|
|
77
77
|
"performance-now": "^2.1.0",
|
|
78
|
+
"retry": "^0.10.1",
|
|
78
79
|
"semver": "^5.5.0",
|
|
79
80
|
"source-map": "^0.7.3",
|
|
80
81
|
"source-map-resolve": "^0.6.0"
|
|
81
82
|
},
|
|
82
83
|
"devDependencies": {
|
|
83
84
|
"autocannon": "^4.5.2",
|
|
84
|
-
"axios": "^0.21.
|
|
85
|
+
"axios": "^0.21.2",
|
|
85
86
|
"benchmark": "^2.1.4",
|
|
86
87
|
"body-parser": "^1.18.2",
|
|
87
88
|
"chai": "^4.2.0",
|
|
@@ -110,7 +111,6 @@
|
|
|
110
111
|
"nock": "^11.3.3",
|
|
111
112
|
"nyc": "^15.1.0",
|
|
112
113
|
"proxyquire": "^1.8.0",
|
|
113
|
-
"retry": "^0.10.1",
|
|
114
114
|
"rimraf": "^3.0.0",
|
|
115
115
|
"sinon": "^11.1.2",
|
|
116
116
|
"sinon-chai": "^3.7.0",
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
const { relative } = require('path')
|
|
2
|
-
|
|
3
1
|
const { SAMPLING_RULE_DECISION } = require('../../dd-trace/src/constants')
|
|
4
2
|
|
|
5
3
|
const {
|
|
@@ -11,7 +9,8 @@ const {
|
|
|
11
9
|
CI_APP_ORIGIN,
|
|
12
10
|
ERROR_MESSAGE,
|
|
13
11
|
getTestEnvironmentMetadata,
|
|
14
|
-
finishAllTraceSpans
|
|
12
|
+
finishAllTraceSpans,
|
|
13
|
+
getTestSuitePath
|
|
15
14
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
16
15
|
|
|
17
16
|
function setStatusFromResult (span, result, tag) {
|
|
@@ -42,11 +41,11 @@ function setStatusFromResultLatest (span, result, tag) {
|
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
|
|
45
|
-
function createWrapRun (tracer, testEnvironmentMetadata,
|
|
44
|
+
function createWrapRun (tracer, testEnvironmentMetadata, sourceRoot, setStatus) {
|
|
46
45
|
return function wrapRun (run) {
|
|
47
46
|
return function handleRun () {
|
|
48
47
|
const testName = this.pickle.name
|
|
49
|
-
const testSuite =
|
|
48
|
+
const testSuite = getTestSuitePath(this.pickle.uri, sourceRoot)
|
|
50
49
|
|
|
51
50
|
const commonSpanTags = {
|
|
52
51
|
[TEST_TYPE]: 'test',
|
|
@@ -105,14 +104,11 @@ module.exports = [
|
|
|
105
104
|
patch (PickleRunner, tracer) {
|
|
106
105
|
const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber')
|
|
107
106
|
const sourceRoot = process.cwd()
|
|
108
|
-
const getTestSuiteName = (pickleUri) => {
|
|
109
|
-
return relative(sourceRoot, pickleUri)
|
|
110
|
-
}
|
|
111
107
|
const pl = PickleRunner.default
|
|
112
108
|
this.wrap(
|
|
113
109
|
pl.prototype,
|
|
114
110
|
'run',
|
|
115
|
-
createWrapRun(tracer, testEnvironmentMetadata,
|
|
111
|
+
createWrapRun(tracer, testEnvironmentMetadata, sourceRoot, setStatusFromResult)
|
|
116
112
|
)
|
|
117
113
|
const getResourceName = (testStep) => {
|
|
118
114
|
return testStep.isHook ? 'hook' : testStep.pickleStep.text
|
|
@@ -132,14 +128,11 @@ module.exports = [
|
|
|
132
128
|
patch (TestCaseRunner, tracer) {
|
|
133
129
|
const testEnvironmentMetadata = getTestEnvironmentMetadata('cucumber')
|
|
134
130
|
const sourceRoot = process.cwd()
|
|
135
|
-
const getTestSuiteName = (pickleUri) => {
|
|
136
|
-
return relative(sourceRoot, pickleUri)
|
|
137
|
-
}
|
|
138
131
|
const pl = TestCaseRunner.default
|
|
139
132
|
this.wrap(
|
|
140
133
|
pl.prototype,
|
|
141
134
|
'run',
|
|
142
|
-
createWrapRun(tracer, testEnvironmentMetadata,
|
|
135
|
+
createWrapRun(tracer, testEnvironmentMetadata, sourceRoot, setStatusFromResultLatest)
|
|
143
136
|
)
|
|
144
137
|
const getResourceName = (testStep) => {
|
|
145
138
|
return testStep.text
|
|
@@ -9,20 +9,17 @@ let tools
|
|
|
9
9
|
function createWrapExecute (tracer, config, defaultFieldResolver) {
|
|
10
10
|
return function wrapExecute (execute) {
|
|
11
11
|
return function executeWithTrace () {
|
|
12
|
-
const args = normalizeArgs(arguments)
|
|
12
|
+
const args = normalizeArgs(arguments, tracer, config, defaultFieldResolver)
|
|
13
13
|
const schema = args.schema
|
|
14
14
|
const document = args.document
|
|
15
15
|
const source = document && document._datadog_source
|
|
16
|
-
const
|
|
17
|
-
const contextValue = args.contextValue = args.contextValue || {}
|
|
16
|
+
const contextValue = args.contextValue
|
|
18
17
|
const operation = getOperation(document, args.operationName)
|
|
19
18
|
|
|
20
19
|
if (contextValue._datadog_graphql) {
|
|
21
20
|
return execute.apply(this, arguments)
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
args.fieldResolver = wrapResolve(fieldResolver, tracer, config)
|
|
25
|
-
|
|
26
23
|
if (schema) {
|
|
27
24
|
wrapFields(schema._queryType, tracer, config)
|
|
28
25
|
wrapFields(schema._mutationType, tracer, config)
|
|
@@ -32,7 +29,7 @@ function createWrapExecute (tracer, config, defaultFieldResolver) {
|
|
|
32
29
|
|
|
33
30
|
contextValue._datadog_graphql = { source, span, fields: {} }
|
|
34
31
|
|
|
35
|
-
return call(execute, span, this,
|
|
32
|
+
return call(execute, span, this, arguments, (err, res) => {
|
|
36
33
|
finishResolvers(contextValue, config)
|
|
37
34
|
|
|
38
35
|
setError(span, err || (res && res.errors && res.errors[0]))
|
|
@@ -212,10 +209,19 @@ function getField (contextValue, path) {
|
|
|
212
209
|
return contextValue._datadog_graphql.fields[path.join('.')]
|
|
213
210
|
}
|
|
214
211
|
|
|
215
|
-
function normalizeArgs (args) {
|
|
216
|
-
if (args.length
|
|
217
|
-
|
|
218
|
-
}
|
|
212
|
+
function normalizeArgs (args, tracer, config, defaultFieldResolver) {
|
|
213
|
+
if (args.length !== 1) return normalizePositional(args, tracer, config, defaultFieldResolver)
|
|
214
|
+
|
|
215
|
+
args[0].contextValue = args[0].contextValue || {}
|
|
216
|
+
args[0].fieldResolver = wrapResolve(args[0].fieldResolver || defaultFieldResolver, tracer, config)
|
|
217
|
+
|
|
218
|
+
return args[0]
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function normalizePositional (args, tracer, config, defaultFieldResolver) {
|
|
222
|
+
args[3] = args[3] || {} // contextValue
|
|
223
|
+
args[6] = wrapResolve(args[6] || defaultFieldResolver, tracer, config) // fieldResolver
|
|
224
|
+
args.length = Math.max(args.length, 7)
|
|
219
225
|
|
|
220
226
|
return {
|
|
221
227
|
schema: args[0],
|
|
@@ -48,7 +48,7 @@ function createWrapMakeClientConstructor (tracer, config) {
|
|
|
48
48
|
function wrapPackageDefinition (tracer, config, def) {
|
|
49
49
|
for (const name in def) {
|
|
50
50
|
if (def[name].format) continue
|
|
51
|
-
if (def[name].service) {
|
|
51
|
+
if (def[name].service && def[name].prototype) {
|
|
52
52
|
wrapClientConstructor(tracer, config, def[name], def[name].service)
|
|
53
53
|
} else {
|
|
54
54
|
wrapPackageDefinition(tracer, config, def[name])
|
|
@@ -11,7 +11,8 @@ const {
|
|
|
11
11
|
CI_APP_ORIGIN,
|
|
12
12
|
getTestEnvironmentMetadata,
|
|
13
13
|
getTestParametersString,
|
|
14
|
-
finishAllTraceSpans
|
|
14
|
+
finishAllTraceSpans,
|
|
15
|
+
getTestSuitePath
|
|
15
16
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
16
17
|
const {
|
|
17
18
|
getFormattedJestTestParameters,
|
|
@@ -30,7 +31,7 @@ function wrapEnvironment (BaseEnvironment) {
|
|
|
30
31
|
return class DatadogJestEnvironment extends BaseEnvironment {
|
|
31
32
|
constructor (config, context) {
|
|
32
33
|
super(config, context)
|
|
33
|
-
this.testSuite = context.testPath
|
|
34
|
+
this.testSuite = getTestSuitePath(context.testPath, config.rootDir)
|
|
34
35
|
this.testSpansByTestName = {}
|
|
35
36
|
this.originalTestFnByTestName = {}
|
|
36
37
|
}
|
|
@@ -7,7 +7,8 @@ const {
|
|
|
7
7
|
TEST_STATUS,
|
|
8
8
|
CI_APP_ORIGIN,
|
|
9
9
|
getTestEnvironmentMetadata,
|
|
10
|
-
finishAllTraceSpans
|
|
10
|
+
finishAllTraceSpans,
|
|
11
|
+
getTestSuitePath
|
|
11
12
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
12
13
|
const { getTestSpanTags, setSuppressedErrors } = require('./util')
|
|
13
14
|
|
|
@@ -21,7 +22,7 @@ function createWrapIt (tracer, globalConfig, globalInput, testEnvironmentMetadat
|
|
|
21
22
|
|
|
22
23
|
const { childOf, commonSpanTags } = getTestSpanTags(tracer, testEnvironmentMetadata)
|
|
23
24
|
|
|
24
|
-
const testSuite = globalInput.jasmine.testPath
|
|
25
|
+
const testSuite = getTestSuitePath(globalInput.jasmine.testPath, globalConfig.rootDir)
|
|
25
26
|
|
|
26
27
|
const newSpecFunction = tracer.wrap(
|
|
27
28
|
'jest.test',
|
|
@@ -107,7 +108,7 @@ function createWrapItSkip (tracer, globalConfig, globalInput, testEnvironmentMet
|
|
|
107
108
|
return function itSkipWithTrace () {
|
|
108
109
|
const { childOf, commonSpanTags } = getTestSpanTags(tracer, testEnvironmentMetadata)
|
|
109
110
|
|
|
110
|
-
const testSuite = globalInput.jasmine.testPath
|
|
111
|
+
const testSuite = getTestSuitePath(globalInput.jasmine.testPath, globalConfig.rootDir)
|
|
111
112
|
|
|
112
113
|
const spec = it.apply(this, arguments)
|
|
113
114
|
|
|
@@ -13,22 +13,23 @@ const {
|
|
|
13
13
|
getTestEnvironmentMetadata,
|
|
14
14
|
getTestParametersString,
|
|
15
15
|
finishAllTraceSpans,
|
|
16
|
-
getTestParentSpan
|
|
16
|
+
getTestParentSpan,
|
|
17
|
+
getTestSuitePath
|
|
17
18
|
} = require('../../dd-trace/src/plugins/util/test')
|
|
18
19
|
|
|
19
20
|
function getTestSpanMetadata (tracer, test, sourceRoot) {
|
|
20
21
|
const childOf = getTestParentSpan(tracer)
|
|
21
22
|
|
|
22
|
-
const { file:
|
|
23
|
+
const { file: testSuiteAbsolutePath } = test
|
|
23
24
|
const fullTestName = test.fullTitle()
|
|
24
|
-
const
|
|
25
|
+
const testSuite = getTestSuitePath(testSuiteAbsolutePath, sourceRoot)
|
|
25
26
|
|
|
26
27
|
return {
|
|
27
28
|
childOf,
|
|
28
|
-
resource: `${
|
|
29
|
+
resource: `${testSuite}.${fullTestName}`,
|
|
29
30
|
[TEST_TYPE]: 'test',
|
|
30
31
|
[TEST_NAME]: fullTestName,
|
|
31
|
-
[TEST_SUITE]:
|
|
32
|
+
[TEST_SUITE]: testSuite,
|
|
32
33
|
[SAMPLING_RULE_DECISION]: 1,
|
|
33
34
|
[SAMPLING_PRIORITY]: AUTO_KEEP
|
|
34
35
|
}
|
|
@@ -37,6 +38,12 @@ function getTestSpanMetadata (tracer, test, sourceRoot) {
|
|
|
37
38
|
function createWrapRunTest (tracer, testEnvironmentMetadata, sourceRoot) {
|
|
38
39
|
return function wrapRunTest (runTest) {
|
|
39
40
|
return async function runTestWithTrace () {
|
|
41
|
+
// `runTest` is rerun when retries are configured through `this.retries` and the test fails.
|
|
42
|
+
// This clause prevents rewrapping `this.test.fn` when it has already been wrapped.
|
|
43
|
+
if (this.test._currentRetry !== undefined && this.test._currentRetry !== 0) {
|
|
44
|
+
return runTest.apply(this, arguments)
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
let specFunction = this.test.fn
|
|
41
48
|
if (specFunction.length) {
|
|
42
49
|
specFunction = promisify(specFunction)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = '1.
|
|
1
|
+
module.exports = '1.5.1'
|
|
@@ -61,13 +61,15 @@ class AgentEncoder {
|
|
|
61
61
|
this._encodeArrayPrefix(bytes, trace)
|
|
62
62
|
|
|
63
63
|
for (const span of trace) {
|
|
64
|
+
bytes.reserve(1)
|
|
65
|
+
|
|
64
66
|
if (span.type) {
|
|
65
|
-
bytes.
|
|
67
|
+
bytes.buffer[bytes.length++] = 0x8c
|
|
66
68
|
|
|
67
69
|
this._encodeString(bytes, 'type')
|
|
68
70
|
this._encodeString(bytes, span.type)
|
|
69
71
|
} else {
|
|
70
|
-
bytes.
|
|
72
|
+
bytes.buffer[bytes.length++] = 0x8b
|
|
71
73
|
}
|
|
72
74
|
|
|
73
75
|
this._encodeString(bytes, 'trace_id')
|
|
@@ -107,52 +109,105 @@ class AgentEncoder {
|
|
|
107
109
|
|
|
108
110
|
_encodeArrayPrefix (bytes, value) {
|
|
109
111
|
const length = value.length
|
|
112
|
+
const buffer = bytes.buffer
|
|
113
|
+
const offset = bytes.length
|
|
114
|
+
|
|
115
|
+
bytes.reserve(5)
|
|
116
|
+
bytes.length += 5
|
|
110
117
|
|
|
111
|
-
|
|
118
|
+
buffer[offset] = 0xdd
|
|
119
|
+
buffer[offset + 1] = length >> 24
|
|
120
|
+
buffer[offset + 2] = length >> 16
|
|
121
|
+
buffer[offset + 3] = length >> 8
|
|
122
|
+
buffer[offset + 4] = length
|
|
112
123
|
}
|
|
113
124
|
|
|
114
125
|
_encodeByte (bytes, value) {
|
|
115
|
-
bytes.
|
|
126
|
+
const buffer = bytes.buffer
|
|
127
|
+
|
|
128
|
+
bytes.reserve(1)
|
|
129
|
+
|
|
130
|
+
buffer[bytes.length++] = value
|
|
116
131
|
}
|
|
117
132
|
|
|
118
133
|
_encodeId (bytes, id) {
|
|
134
|
+
const buffer = bytes.buffer
|
|
135
|
+
const offset = bytes.length
|
|
136
|
+
|
|
137
|
+
bytes.reserve(9)
|
|
138
|
+
bytes.length += 9
|
|
139
|
+
|
|
119
140
|
id = id.toArray()
|
|
120
|
-
|
|
141
|
+
|
|
142
|
+
buffer[offset] = 0xcf
|
|
143
|
+
buffer[offset + 1] = id[0]
|
|
144
|
+
buffer[offset + 2] = id[1]
|
|
145
|
+
buffer[offset + 3] = id[2]
|
|
146
|
+
buffer[offset + 4] = id[3]
|
|
147
|
+
buffer[offset + 5] = id[4]
|
|
148
|
+
buffer[offset + 6] = id[5]
|
|
149
|
+
buffer[offset + 7] = id[6]
|
|
150
|
+
buffer[offset + 8] = id[7]
|
|
121
151
|
}
|
|
122
152
|
|
|
123
153
|
_encodeInteger (bytes, value) {
|
|
124
|
-
|
|
154
|
+
const buffer = bytes.buffer
|
|
155
|
+
const offset = bytes.length
|
|
156
|
+
|
|
157
|
+
bytes.reserve(5)
|
|
158
|
+
bytes.length += 5
|
|
159
|
+
|
|
160
|
+
buffer[offset] = 0xce
|
|
161
|
+
buffer[offset + 1] = value >> 24
|
|
162
|
+
buffer[offset + 2] = value >> 16
|
|
163
|
+
buffer[offset + 3] = value >> 8
|
|
164
|
+
buffer[offset + 4] = value
|
|
125
165
|
}
|
|
126
166
|
|
|
127
167
|
_encodeLong (bytes, value) {
|
|
168
|
+
const buffer = bytes.buffer
|
|
169
|
+
const offset = bytes.length
|
|
128
170
|
const hi = (value / Math.pow(2, 32)) >> 0
|
|
129
171
|
const lo = value >>> 0
|
|
130
172
|
|
|
131
|
-
bytes.
|
|
173
|
+
bytes.reserve(9)
|
|
174
|
+
bytes.length += 9
|
|
175
|
+
|
|
176
|
+
buffer[offset] = 0xcf
|
|
177
|
+
buffer[offset + 1] = hi >> 24
|
|
178
|
+
buffer[offset + 2] = hi >> 16
|
|
179
|
+
buffer[offset + 3] = hi >> 8
|
|
180
|
+
buffer[offset + 4] = hi
|
|
181
|
+
buffer[offset + 5] = lo >> 24
|
|
182
|
+
buffer[offset + 6] = lo >> 16
|
|
183
|
+
buffer[offset + 7] = lo >> 8
|
|
184
|
+
buffer[offset + 8] = lo
|
|
132
185
|
}
|
|
133
186
|
|
|
134
187
|
_encodeMap (bytes, value) {
|
|
135
|
-
const keys =
|
|
136
|
-
const
|
|
188
|
+
const keys = Object.keys(value)
|
|
189
|
+
const buffer = bytes.buffer
|
|
190
|
+
const offset = bytes.length
|
|
137
191
|
|
|
138
|
-
|
|
192
|
+
bytes.reserve(5)
|
|
193
|
+
bytes.length += 5
|
|
139
194
|
|
|
140
|
-
|
|
141
|
-
key = allKeys[i]
|
|
142
|
-
if (typeof value[key] !== 'function') {
|
|
143
|
-
keys.push(key)
|
|
144
|
-
}
|
|
145
|
-
}
|
|
195
|
+
let length = 0
|
|
146
196
|
|
|
147
|
-
const
|
|
197
|
+
for (const key of keys) {
|
|
198
|
+
if (typeof value[key] !== 'string' && typeof value[key] !== 'number') return
|
|
148
199
|
|
|
149
|
-
|
|
200
|
+
length++
|
|
150
201
|
|
|
151
|
-
for (let i = 0; i < length; i++) {
|
|
152
|
-
key = keys[i]
|
|
153
202
|
this._encodeString(bytes, key)
|
|
154
203
|
this._encodeValue(bytes, value[key])
|
|
155
204
|
}
|
|
205
|
+
|
|
206
|
+
buffer[offset] = 0xdf
|
|
207
|
+
buffer[offset + 1] = length >> 24
|
|
208
|
+
buffer[offset + 2] = length >> 16
|
|
209
|
+
buffer[offset + 3] = length >> 8
|
|
210
|
+
buffer[offset + 4] = length
|
|
156
211
|
}
|
|
157
212
|
|
|
158
213
|
_encodeValue (bytes, value) {
|
|
@@ -179,15 +234,21 @@ class AgentEncoder {
|
|
|
179
234
|
_encodeFloat (bytes, value) {
|
|
180
235
|
float64Array[0] = value
|
|
181
236
|
|
|
182
|
-
bytes.
|
|
237
|
+
const buffer = bytes.buffer
|
|
238
|
+
const offset = bytes.length
|
|
239
|
+
|
|
240
|
+
bytes.reserve(9)
|
|
241
|
+
bytes.length += 9
|
|
242
|
+
|
|
243
|
+
buffer[offset] = 0xcb
|
|
183
244
|
|
|
184
245
|
if (bigEndian) {
|
|
185
246
|
for (let i = 0; i <= 7; i++) {
|
|
186
|
-
|
|
247
|
+
buffer[offset + i + 1] = uInt8Float64Array[i]
|
|
187
248
|
}
|
|
188
249
|
} else {
|
|
189
250
|
for (let i = 7; i >= 0; i--) {
|
|
190
|
-
bytes.
|
|
251
|
+
buffer[bytes.length - i - 1] = uInt8Float64Array[i]
|
|
191
252
|
}
|
|
192
253
|
}
|
|
193
254
|
}
|
|
@@ -14,26 +14,24 @@ class Chunk {
|
|
|
14
14
|
this._minSize = minSize
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
push (...bytes) {
|
|
18
|
-
this._reserve(bytes.length)
|
|
19
|
-
|
|
20
|
-
for (const byte of bytes) {
|
|
21
|
-
this.buffer[this.length++] = byte
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
17
|
write (value) {
|
|
26
18
|
const length = Buffer.byteLength(value)
|
|
27
19
|
const offset = this.length
|
|
28
20
|
|
|
29
21
|
if (length < 0x20) { // fixstr
|
|
30
|
-
this.
|
|
22
|
+
this.reserve(length + 1)
|
|
23
|
+
this.length += 1
|
|
24
|
+
this.buffer[offset] = length | 0xa0
|
|
31
25
|
} else if (length < 0x100000000) { // str 32
|
|
32
|
-
this.
|
|
26
|
+
this.reserve(length + 5)
|
|
27
|
+
this.length += 5
|
|
28
|
+
this.buffer[offset] = 0xdb
|
|
29
|
+
this.buffer[offset + 1] = length >> 24
|
|
30
|
+
this.buffer[offset + 2] = length >> 16
|
|
31
|
+
this.buffer[offset + 3] = length >> 8
|
|
32
|
+
this.buffer[offset + 4] = length
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
this._reserve(length)
|
|
36
|
-
|
|
37
35
|
this.length += this.buffer.utf8Write(value, this.length, length)
|
|
38
36
|
|
|
39
37
|
return this.length - offset
|
|
@@ -44,13 +42,13 @@ class Chunk {
|
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
set (array) {
|
|
47
|
-
this.
|
|
45
|
+
this.reserve(array.length)
|
|
48
46
|
|
|
49
47
|
this.buffer.set(array, this.length)
|
|
50
48
|
this.length += array.length
|
|
51
49
|
}
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
reserve (size) {
|
|
54
52
|
if (this.length + size > this.buffer.length) {
|
|
55
53
|
this._resize(this._minSize * Math.ceil((this.length + size) / this._minSize))
|
|
56
54
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { randomFillSync } = require('crypto')
|
|
4
4
|
|
|
5
5
|
const UINT_MAX = 4294967296
|
|
6
6
|
|
|
7
|
+
const data = new Uint8Array(8 * 8192)
|
|
7
8
|
const zeroId = new Uint8Array(8)
|
|
8
9
|
|
|
9
|
-
// Cryptographically secure local seeds to mitigate Math.random() seed reuse.
|
|
10
|
-
const seed = new Uint32Array(randomBytes(8).buffer)
|
|
11
|
-
|
|
12
10
|
const map = Array.prototype.map
|
|
13
11
|
const pad = byte => `${byte < 16 ? '0' : ''}${byte.toString(16)}`
|
|
14
12
|
|
|
13
|
+
let batch = 0
|
|
14
|
+
|
|
15
15
|
// Internal representation of a trace or span ID.
|
|
16
16
|
class Identifier {
|
|
17
17
|
constructor (value, radix) {
|
|
@@ -36,7 +36,7 @@ class Identifier {
|
|
|
36
36
|
if (this._buffer.length === 8) {
|
|
37
37
|
return this._buffer
|
|
38
38
|
}
|
|
39
|
-
return this._buffer.
|
|
39
|
+
return this._buffer.slice(-8)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
toJSON () {
|
|
@@ -50,7 +50,7 @@ function createBuffer (value) {
|
|
|
50
50
|
if (!value) return pseudoRandom()
|
|
51
51
|
|
|
52
52
|
const size = Math.ceil(value.length / 2)
|
|
53
|
-
const buffer = new
|
|
53
|
+
const buffer = new Array(size)
|
|
54
54
|
|
|
55
55
|
for (let i = 0; i < size; i++) {
|
|
56
56
|
buffer[i] = parseInt(value.substring(i * 2, i * 2 + 2), 16)
|
|
@@ -61,7 +61,7 @@ function createBuffer (value) {
|
|
|
61
61
|
|
|
62
62
|
// Convert a numerical string to a buffer using the specified radix.
|
|
63
63
|
function fromString (str, raddix) {
|
|
64
|
-
const buffer = new
|
|
64
|
+
const buffer = new Array(8)
|
|
65
65
|
const len = str.length
|
|
66
66
|
|
|
67
67
|
let pos = 0
|
|
@@ -126,20 +126,24 @@ function toHexString (buffer) {
|
|
|
126
126
|
|
|
127
127
|
// Simple pseudo-random 64-bit ID generator.
|
|
128
128
|
function pseudoRandom () {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const lo = randomUInt32(seed[1])
|
|
129
|
+
if (batch === 0) {
|
|
130
|
+
randomFillSync(data)
|
|
131
|
+
}
|
|
133
132
|
|
|
134
|
-
|
|
135
|
-
writeUInt32BE(buffer, lo, 4)
|
|
133
|
+
batch = (batch + 1) % 8192
|
|
136
134
|
|
|
137
|
-
|
|
138
|
-
}
|
|
135
|
+
const offset = batch * 8
|
|
139
136
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
return [
|
|
138
|
+
data[offset] & 0x7F, // only positive int64,
|
|
139
|
+
data[offset + 1],
|
|
140
|
+
data[offset + 2],
|
|
141
|
+
data[offset + 3],
|
|
142
|
+
data[offset + 4],
|
|
143
|
+
data[offset + 5],
|
|
144
|
+
data[offset + 6],
|
|
145
|
+
data[offset + 7]
|
|
146
|
+
]
|
|
143
147
|
}
|
|
144
148
|
|
|
145
149
|
// Read a buffer to unsigned integer bytes.
|
|
@@ -7,10 +7,10 @@ const Loader = require('./loader')
|
|
|
7
7
|
const { isTrue } = require('./util')
|
|
8
8
|
const plugins = require('./plugins')
|
|
9
9
|
|
|
10
|
-
const
|
|
10
|
+
const disabledPlugins = process.env.DD_TRACE_DISABLED_PLUGINS
|
|
11
11
|
|
|
12
12
|
const collectDisabledPlugins = () => {
|
|
13
|
-
return new Set(
|
|
13
|
+
return new Set(disabledPlugins && disabledPlugins.split(',').map(plugin => plugin.trim()))
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
function cleanEnv (name) {
|
|
@@ -85,51 +85,26 @@ class Loader {
|
|
|
85
85
|
|
|
86
86
|
const moduleVersion = getVersion(moduleBaseDir)
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
.
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
[].concat(plugin)
|
|
98
|
-
.filter(instrumentation => moduleName === filename(instrumentation))
|
|
99
|
-
.filter(instrumentation => matchVersion(moduleVersion, instrumentation.versions))
|
|
100
|
-
.forEach(instrumentation => {
|
|
101
|
-
const config = this._plugins.get(plugin).config
|
|
102
|
-
|
|
103
|
-
if (config.enabled !== false) {
|
|
104
|
-
moduleExports = this._instrumenter.patch(instrumentation, moduleExports, config) || moduleExports
|
|
105
|
-
}
|
|
106
|
-
})
|
|
107
|
-
} catch (e) {
|
|
108
|
-
log.error(e)
|
|
109
|
-
this._instrumenter.unload(plugin)
|
|
110
|
-
log.debug(`Error while trying to patch ${meta.name}. The plugin has been disabled.`)
|
|
111
|
-
}
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
return moduleExports
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
_validate (plugin, moduleName, moduleBaseDir, moduleVersion) {
|
|
118
|
-
const meta = this._plugins.get(plugin)
|
|
119
|
-
const instrumentations = [].concat(plugin)
|
|
88
|
+
for (const [plugin, meta] of this._plugins) {
|
|
89
|
+
if (meta.config.enabled === false) {
|
|
90
|
+
continue
|
|
91
|
+
}
|
|
92
|
+
try {
|
|
93
|
+
for (const instrumentation of [].concat(plugin)) {
|
|
94
|
+
if (moduleName !== filename(instrumentation) || !matchVersion(moduleVersion, instrumentation.versions)) {
|
|
95
|
+
continue
|
|
96
|
+
}
|
|
120
97
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
98
|
+
moduleExports = this._instrumenter.patch(instrumentation, moduleExports, meta.config) || moduleExports
|
|
99
|
+
}
|
|
100
|
+
} catch (e) {
|
|
101
|
+
log.error(e)
|
|
125
102
|
this._instrumenter.unload(plugin)
|
|
126
|
-
log.debug(
|
|
127
|
-
`Plugin "${meta.name}" requires "${instrumentations[i].file}" which was not found.`,
|
|
128
|
-
`The plugin was disabled.`
|
|
129
|
-
].join(' '))
|
|
130
|
-
break
|
|
103
|
+
log.debug(`Error while trying to patch ${meta.name}. The plugin has been disabled.`)
|
|
131
104
|
}
|
|
132
105
|
}
|
|
106
|
+
|
|
107
|
+
return moduleExports
|
|
133
108
|
}
|
|
134
109
|
}
|
|
135
110
|
|
|
@@ -151,13 +126,4 @@ function filename (plugin) {
|
|
|
151
126
|
return [plugin.name, plugin.file].filter(val => val).join('/')
|
|
152
127
|
}
|
|
153
128
|
|
|
154
|
-
function exists (basedir, file) {
|
|
155
|
-
try {
|
|
156
|
-
require.resolve(`${basedir}/${file}`)
|
|
157
|
-
return true
|
|
158
|
-
} catch (e) {
|
|
159
|
-
return false
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
129
|
module.exports = Loader
|
|
@@ -7,8 +7,10 @@ const SpanContext = require('./span_context')
|
|
|
7
7
|
const constants = require('../constants')
|
|
8
8
|
const id = require('../id')
|
|
9
9
|
const tagger = require('../tagger')
|
|
10
|
+
const log = require('../log')
|
|
10
11
|
|
|
11
12
|
const SAMPLE_RATE_METRIC_KEY = constants.SAMPLE_RATE_METRIC_KEY
|
|
13
|
+
const { DD_TRACE_EXPERIMENTAL_STATE_TRACKING } = process.env
|
|
12
14
|
|
|
13
15
|
class DatadogSpan extends Span {
|
|
14
16
|
constructor (tracer, processor, sampler, prioritySampler, fields, debug) {
|
|
@@ -117,6 +119,12 @@ class DatadogSpan extends Span {
|
|
|
117
119
|
return
|
|
118
120
|
}
|
|
119
121
|
|
|
122
|
+
if (DD_TRACE_EXPERIMENTAL_STATE_TRACKING === 'true') {
|
|
123
|
+
if (!this._spanContext._tags['service.name']) {
|
|
124
|
+
log.error(`Finishing invalid span: ${this}`)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
120
128
|
finishTime = parseFloat(finishTime) || this._getTime()
|
|
121
129
|
|
|
122
130
|
this._duration = finishTime - this._startTime
|
|
@@ -42,7 +42,7 @@ const redis = {
|
|
|
42
42
|
function formatCommand (command, args) {
|
|
43
43
|
command = command.toUpperCase()
|
|
44
44
|
|
|
45
|
-
if (!args) return command
|
|
45
|
+
if (!args || command === 'AUTH') return command
|
|
46
46
|
|
|
47
47
|
for (let i = 0, l = args.length; i < l; i++) {
|
|
48
48
|
if (typeof args[i] === 'function') continue
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
|
|
1
3
|
const { getGitMetadata } = require('./git')
|
|
2
4
|
const { getCIMetadata } = require('./ci')
|
|
3
5
|
const { getRuntimeAndOSMetadata } = require('./env')
|
|
@@ -42,7 +44,8 @@ module.exports = {
|
|
|
42
44
|
getTestEnvironmentMetadata,
|
|
43
45
|
getTestParametersString,
|
|
44
46
|
finishAllTraceSpans,
|
|
45
|
-
getTestParentSpan
|
|
47
|
+
getTestParentSpan,
|
|
48
|
+
getTestSuitePath
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
function getTestEnvironmentMetadata (testFramework) {
|
|
@@ -110,3 +113,16 @@ function getTestParentSpan (tracer) {
|
|
|
110
113
|
'x-datadog-sampled': 1
|
|
111
114
|
})
|
|
112
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* We want to make sure that test suites are reported the same way for
|
|
118
|
+
* every OS, so we replace `path.sep` by `/`
|
|
119
|
+
*/
|
|
120
|
+
function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
|
|
121
|
+
if (!testSuiteAbsolutePath) {
|
|
122
|
+
return sourceRoot
|
|
123
|
+
}
|
|
124
|
+
const testSuitePath = testSuiteAbsolutePath === sourceRoot
|
|
125
|
+
? testSuiteAbsolutePath : path.relative(sourceRoot, testSuiteAbsolutePath)
|
|
126
|
+
|
|
127
|
+
return testSuitePath.replace(path.sep, '/')
|
|
128
|
+
}
|
|
@@ -181,7 +181,7 @@ const web = {
|
|
|
181
181
|
|
|
182
182
|
// Extract the parent span from the headers and start a new span as its child
|
|
183
183
|
startChildSpan (tracer, name, headers) {
|
|
184
|
-
const childOf = tracer.extract(FORMAT_HTTP_HEADERS, headers)
|
|
184
|
+
const childOf = tracer.scope().active() || tracer.extract(FORMAT_HTTP_HEADERS, headers)
|
|
185
185
|
const span = tracer.startSpan(name, { childOf })
|
|
186
186
|
|
|
187
187
|
return span
|
|
@@ -4,9 +4,13 @@ const retry = require('retry')
|
|
|
4
4
|
const { request } = require('http')
|
|
5
5
|
const FormData = require('form-data')
|
|
6
6
|
|
|
7
|
+
// TODO: avoid using dd-trace internals. Make this a separate module?
|
|
8
|
+
const docker = require('../../exporters/agent/docker')
|
|
7
9
|
const version = require('../../../lib/version')
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
const containerId = docker.id()
|
|
12
|
+
|
|
13
|
+
function sendRequest (options, form, callback) {
|
|
10
14
|
const req = request(options, res => {
|
|
11
15
|
if (res.statusCode >= 400) {
|
|
12
16
|
const error = new Error(`HTTP Error ${res.statusCode}`)
|
|
@@ -17,7 +21,7 @@ function sendRequest (options, body, callback) {
|
|
|
17
21
|
}
|
|
18
22
|
})
|
|
19
23
|
req.on('error', callback)
|
|
20
|
-
if (
|
|
24
|
+
if (form) form.pipe(req)
|
|
21
25
|
req.end()
|
|
22
26
|
}
|
|
23
27
|
|
|
@@ -97,13 +101,16 @@ class AgentExporter {
|
|
|
97
101
|
})
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
const body = form.getBuffer()
|
|
101
104
|
const options = {
|
|
102
105
|
method: 'POST',
|
|
103
106
|
path: '/profiling/v1/input',
|
|
104
107
|
headers: form.getHeaders()
|
|
105
108
|
}
|
|
106
109
|
|
|
110
|
+
if (containerId) {
|
|
111
|
+
options.headers['Datadog-Container-ID'] = containerId
|
|
112
|
+
}
|
|
113
|
+
|
|
107
114
|
if (this._url.protocol === 'unix:') {
|
|
108
115
|
options.socketPath = this._url.pathname
|
|
109
116
|
} else {
|
|
@@ -125,7 +132,7 @@ class AgentExporter {
|
|
|
125
132
|
|
|
126
133
|
operation.attempt((attempt) => {
|
|
127
134
|
const timeout = Math.pow(this._backoffTime, attempt)
|
|
128
|
-
sendRequest({ ...options, timeout },
|
|
135
|
+
sendRequest({ ...options, timeout }, form, (err, response) => {
|
|
129
136
|
if (operation.retry(err)) {
|
|
130
137
|
this._logger.error(`Error from the agent: ${err.message}`)
|
|
131
138
|
return
|
|
@@ -46,7 +46,7 @@ class Tracer extends BaseTracer {
|
|
|
46
46
|
metrics.start(config)
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
// dirty require for now so zero appsec code is executed unless
|
|
49
|
+
// dirty require for now so zero appsec code is executed unless explicitly enabled
|
|
50
50
|
if (config.appsec.enabled) {
|
|
51
51
|
require('./appsec').enable(config)
|
|
52
52
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const log = require('./log')
|
|
2
2
|
const format = require('./format')
|
|
3
3
|
|
|
4
|
+
const startedSpans = new WeakSet()
|
|
5
|
+
const finishedSpans = new WeakSet()
|
|
6
|
+
|
|
4
7
|
class SpanProcessor {
|
|
5
8
|
constructor (exporter, prioritySampler) {
|
|
6
9
|
this._exporter = exporter
|
|
@@ -27,9 +30,80 @@ class SpanProcessor {
|
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
_erase (trace) {
|
|
30
|
-
|
|
33
|
+
if (process.env.DD_TRACE_EXPERIMENTAL_STATE_TRACKING === 'true') {
|
|
34
|
+
const started = new Set()
|
|
35
|
+
const startedIds = new Set()
|
|
36
|
+
const finished = new Set()
|
|
37
|
+
const finishedIds = new Set()
|
|
38
|
+
|
|
39
|
+
for (const span of trace.finished) {
|
|
40
|
+
const context = span.context()
|
|
41
|
+
const id = context.toSpanId()
|
|
42
|
+
|
|
43
|
+
if (finished.has(span)) {
|
|
44
|
+
log.error(`Span was already finished in the same trace: ${span}`)
|
|
45
|
+
} else {
|
|
46
|
+
finished.add(span)
|
|
47
|
+
|
|
48
|
+
if (finishedIds.has(id)) {
|
|
49
|
+
log.error(`Another span with the same ID was already finished in the same trace: ${span}`)
|
|
50
|
+
} else {
|
|
51
|
+
finishedIds.add(id)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (context._trace !== trace) {
|
|
55
|
+
log.error(`A span was finished in the wrong trace: ${span}.`)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (finishedSpans.has(span)) {
|
|
59
|
+
log.error(`Span was already finished in a different trace: ${span}`)
|
|
60
|
+
} else {
|
|
61
|
+
finishedSpans.add(span)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
for (const span of trace.started) {
|
|
67
|
+
const context = span.context()
|
|
68
|
+
const id = context.toSpanId()
|
|
69
|
+
|
|
70
|
+
if (started.has(span)) {
|
|
71
|
+
log.error(`Span was already started in the same trace: ${span}`)
|
|
72
|
+
} else {
|
|
73
|
+
started.add(span)
|
|
74
|
+
|
|
75
|
+
if (startedIds.has(id)) {
|
|
76
|
+
log.error(`Another span with the same ID was already started in the same trace: ${span}`)
|
|
77
|
+
} else {
|
|
78
|
+
startedIds.add(id)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (context._trace !== trace) {
|
|
82
|
+
log.error(`A span was started in the wrong trace: ${span}.`)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (startedSpans.has(span)) {
|
|
86
|
+
log.error(`Span was already started in a different trace: ${span}`)
|
|
87
|
+
} else {
|
|
88
|
+
startedSpans.add(span)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!finished.has(span)) {
|
|
93
|
+
log.error(`Span started in one trace but was finished in another trace: ${span}`)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
for (const span of trace.finished) {
|
|
98
|
+
if (!started.has(span)) {
|
|
99
|
+
log.error(`Span finished in one trace but was started in another trace: ${span}`)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const span of trace.finished) {
|
|
31
105
|
span.context()._tags = {}
|
|
32
|
-
}
|
|
106
|
+
}
|
|
33
107
|
|
|
34
108
|
trace.started = []
|
|
35
109
|
trace.finished = []
|
package/NOTICE
DELETED