dd-trace 3.2.0 → 3.3.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 +2 -1
- package/README.md +4 -0
- package/package.json +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +14 -12
- package/packages/datadog-instrumentations/src/grpc/server.js +15 -7
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/jest.js +136 -14
- package/packages/datadog-instrumentations/src/mocha.js +77 -31
- package/packages/datadog-instrumentations/src/next.js +7 -3
- package/packages/datadog-plugin-jest/src/index.js +106 -6
- package/packages/datadog-plugin-mocha/src/index.js +15 -7
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-cipher-analyzer.js +27 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +13 -5
- package/packages/dd-trace/src/appsec/recommended.json +1144 -275
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +3 -3
- package/packages/dd-trace/src/config.js +16 -2
- package/packages/dd-trace/src/encode/0.4.js +7 -1
- package/packages/dd-trace/src/encode/0.5.js +7 -1
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +2 -2
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +32 -20
- package/packages/dd-trace/src/exporters/common/request.js +3 -3
- package/packages/dd-trace/src/opentracing/span.js +6 -0
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/util/ip_blocklist.js +30 -4
- package/packages/dd-trace/src/plugins/util/redis.js +0 -74
- package/packages/dd-trace/src/plugins/util/tx.js +0 -75
|
@@ -25,10 +25,10 @@ class AgentlessCiVisibilityExporter {
|
|
|
25
25
|
})
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
exportCoverage ({
|
|
28
|
+
exportCoverage ({ span, coverageFiles }) {
|
|
29
29
|
const formattedCoverage = {
|
|
30
|
-
traceId:
|
|
31
|
-
spanId:
|
|
30
|
+
traceId: span.context()._traceId,
|
|
31
|
+
spanId: span.context()._spanId,
|
|
32
32
|
files: coverageFiles
|
|
33
33
|
}
|
|
34
34
|
this._coverageWriter.append(formattedCoverage)
|
|
@@ -14,7 +14,7 @@ const fromEntries = Object.fromEntries || (entries =>
|
|
|
14
14
|
entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
|
|
15
15
|
|
|
16
16
|
// eslint-disable-next-line max-len
|
|
17
|
-
const qsRegex = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\\s|%20)*(?:=|%3D)[^&]+|(?:"|%22)(?:\\s|%20)*(?::|%3A)(?:\\s|%20)*(?:"|%22)(?:%2[^2]|%[^2]|[^"%])+(?:"|%22))|bearer(?:\\s|%20)+[a-z0-9\\._\\-]
|
|
17
|
+
const qsRegex = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\\s|%20)*(?:=|%3D)[^&]+|(?:"|%22)(?:\\s|%20)*(?::|%3A)(?:\\s|%20)*(?:"|%22)(?:%2[^2]|%[^2]|[^"%])+(?:"|%22))|bearer(?:\\s|%20)+[a-z0-9\\._\\-]+|token(?::|%3A)[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L](?:[\\w=-]|%3D)+\\.ey[I-L](?:[\\w=-]|%3D)+(?:\\.(?:[\\w.+\\/=-]|%3D|%2F|%2B)+)?|[\\-]{5}BEGIN(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY[\\-]{5}[^\\-]+[\\-]{5}END(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY|ssh-rsa(?:\\s|%20)*(?:[a-z0-9\\/\\.+]|%2F|%5C|%2B){100,}'
|
|
18
18
|
|
|
19
19
|
function safeJsonParse (input) {
|
|
20
20
|
try {
|
|
@@ -24,6 +24,16 @@ function safeJsonParse (input) {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
// Shallow clone with property name remapping
|
|
28
|
+
function remapify (input, mappings) {
|
|
29
|
+
if (!input) return
|
|
30
|
+
const output = {}
|
|
31
|
+
for (const [key, value] of Object.entries(input)) {
|
|
32
|
+
output[key in mappings ? mappings[key] : key] = value
|
|
33
|
+
}
|
|
34
|
+
return output
|
|
35
|
+
}
|
|
36
|
+
|
|
27
37
|
class Config {
|
|
28
38
|
constructor (options) {
|
|
29
39
|
options = options || {}
|
|
@@ -257,7 +267,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
257
267
|
ingestion.sampleRate
|
|
258
268
|
),
|
|
259
269
|
rateLimit: coalesce(options.rateLimit, process.env.DD_TRACE_RATE_LIMIT, ingestion.rateLimit),
|
|
260
|
-
rules: coalesce(options.samplingRules, safeJsonParse(process.env.DD_TRACE_SAMPLING_RULES), [])
|
|
270
|
+
rules: coalesce(options.samplingRules, safeJsonParse(process.env.DD_TRACE_SAMPLING_RULES), []).map(rule => {
|
|
271
|
+
return remapify(rule, {
|
|
272
|
+
sample_rate: 'sampleRate'
|
|
273
|
+
})
|
|
274
|
+
})
|
|
261
275
|
}
|
|
262
276
|
|
|
263
277
|
const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { truncateSpan, normalizeSpan } = require('./tags-processors')
|
|
3
4
|
const Chunk = require('./chunk')
|
|
4
5
|
const log = require('../log')
|
|
5
6
|
|
|
@@ -12,6 +13,10 @@ float64Array[0] = -1
|
|
|
12
13
|
|
|
13
14
|
const bigEndian = uInt8Float64Array[7] === 0
|
|
14
15
|
|
|
16
|
+
function formatSpan (span) {
|
|
17
|
+
return normalizeSpan(truncateSpan(span))
|
|
18
|
+
}
|
|
19
|
+
|
|
15
20
|
class AgentEncoder {
|
|
16
21
|
constructor (writer, limit = SOFT_LIMIT) {
|
|
17
22
|
this._limit = limit
|
|
@@ -66,7 +71,8 @@ class AgentEncoder {
|
|
|
66
71
|
_encode (bytes, trace) {
|
|
67
72
|
this._encodeArrayPrefix(bytes, trace)
|
|
68
73
|
|
|
69
|
-
for (
|
|
74
|
+
for (let span of trace) {
|
|
75
|
+
span = formatSpan(span)
|
|
70
76
|
bytes.reserve(1)
|
|
71
77
|
|
|
72
78
|
if (span.type) {
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { truncateSpan, normalizeSpan } = require('./tags-processors')
|
|
3
4
|
const { AgentEncoder: BaseEncoder } = require('./0.4')
|
|
4
5
|
|
|
5
6
|
const ARRAY_OF_TWO = 0x92
|
|
6
7
|
const ARRAY_OF_TWELVE = 0x9c
|
|
7
8
|
|
|
9
|
+
function formatSpan (span) {
|
|
10
|
+
return normalizeSpan(truncateSpan(span))
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
class AgentEncoder extends BaseEncoder {
|
|
9
14
|
makePayload () {
|
|
10
15
|
const prefixSize = 1
|
|
@@ -27,7 +32,8 @@ class AgentEncoder extends BaseEncoder {
|
|
|
27
32
|
_encode (bytes, trace) {
|
|
28
33
|
this._encodeArrayPrefix(bytes, trace)
|
|
29
34
|
|
|
30
|
-
for (
|
|
35
|
+
for (let span of trace) {
|
|
36
|
+
span = formatSpan(span)
|
|
31
37
|
this._encodeByte(bytes, ARRAY_OF_TWELVE)
|
|
32
38
|
this._encodeString(bytes, span.service)
|
|
33
39
|
this._encodeString(bytes, span.name)
|
|
@@ -134,11 +134,11 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
|
|
|
134
134
|
*/
|
|
135
135
|
if (content.meta.test_session_id) {
|
|
136
136
|
this._encodeString(bytes, 'test_session_id')
|
|
137
|
-
this._encodeId(bytes, id(content.meta.test_session_id))
|
|
137
|
+
this._encodeId(bytes, id(content.meta.test_session_id, 10))
|
|
138
138
|
delete content.meta.test_session_id
|
|
139
139
|
|
|
140
140
|
this._encodeString(bytes, 'test_suite_id')
|
|
141
|
-
this._encodeId(bytes, id(content.meta.test_suite_id))
|
|
141
|
+
this._encodeId(bytes, id(content.meta.test_suite_id, 10))
|
|
142
142
|
delete content.meta.test_suite_id
|
|
143
143
|
}
|
|
144
144
|
this._encodeString(bytes, 'meta')
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const { AgentEncoder } = require('./0.4')
|
|
3
3
|
const Chunk = require('./chunk')
|
|
4
|
+
const log = require('../log')
|
|
4
5
|
|
|
5
6
|
const FormData = require('../exporters/common/form-data')
|
|
6
7
|
|
|
@@ -13,17 +14,34 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
|
13
14
|
super(...arguments)
|
|
14
15
|
this.codeCoverageBuffers = []
|
|
15
16
|
this._coverageBytes = new Chunk()
|
|
17
|
+
this.form = new FormData()
|
|
18
|
+
this.fileIndex = 1
|
|
16
19
|
this.reset()
|
|
17
20
|
}
|
|
18
21
|
|
|
19
22
|
count () {
|
|
20
|
-
return this.
|
|
23
|
+
return this.fileIndex - 1
|
|
21
24
|
}
|
|
22
25
|
|
|
23
26
|
encode (coverage) {
|
|
24
27
|
const bytes = this._coverageBytes
|
|
25
28
|
const coverageBuffer = this.encodeCodeCoverage(bytes, coverage)
|
|
26
|
-
this.
|
|
29
|
+
const coverageFilename = `coverage${this.fileIndex++}`
|
|
30
|
+
|
|
31
|
+
this.form.append(
|
|
32
|
+
coverageFilename,
|
|
33
|
+
coverageBuffer,
|
|
34
|
+
{
|
|
35
|
+
filename: `${coverageFilename}.msgpack`,
|
|
36
|
+
contentType: 'application/msgpack'
|
|
37
|
+
}
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
if (this.fileIndex === MAXIMUM_NUM_COVERAGE_FILES) {
|
|
41
|
+
log.debug('Coverage buffer reached the limit, flushing')
|
|
42
|
+
this._writer.flush()
|
|
43
|
+
}
|
|
44
|
+
|
|
27
45
|
this.reset()
|
|
28
46
|
}
|
|
29
47
|
|
|
@@ -58,24 +76,18 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
|
|
|
58
76
|
}
|
|
59
77
|
|
|
60
78
|
makePayload () {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}
|
|
74
|
-
)
|
|
75
|
-
}
|
|
76
|
-
// 'event' is a backend requirement
|
|
77
|
-
form.append('event', JSON.stringify({}), { filename: 'event.json', contentType: 'application/json' })
|
|
78
|
-
this.codeCoverageBuffers = this.codeCoverageBuffers.slice(MAXIMUM_NUM_COVERAGE_FILES)
|
|
79
|
+
this.form.append(
|
|
80
|
+
'event',
|
|
81
|
+
// The intake requires a populated dictionary here. Simply having {} is not valid.
|
|
82
|
+
// We use dummy: true but any other key/value pair would be valid.
|
|
83
|
+
JSON.stringify({ dummy: true }),
|
|
84
|
+
{ filename: 'event.json', contentType: 'application/json' }
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
const form = this.form
|
|
88
|
+
|
|
89
|
+
this.form = new FormData()
|
|
90
|
+
this.fileIndex = 1
|
|
79
91
|
|
|
80
92
|
return form
|
|
81
93
|
}
|
|
@@ -11,10 +11,10 @@ const { storage } = require('../../../../datadog-core')
|
|
|
11
11
|
const log = require('../../log')
|
|
12
12
|
|
|
13
13
|
const keepAlive = true
|
|
14
|
-
const
|
|
14
|
+
const maxSockets = 1
|
|
15
15
|
const maxActiveRequests = 8
|
|
16
|
-
const httpAgent = new http.Agent({ keepAlive,
|
|
17
|
-
const httpsAgent = new https.Agent({ keepAlive,
|
|
16
|
+
const httpAgent = new http.Agent({ keepAlive, maxSockets })
|
|
17
|
+
const httpsAgent = new https.Agent({ keepAlive, maxSockets })
|
|
18
18
|
const containerId = docker.id()
|
|
19
19
|
|
|
20
20
|
let activeRequests = 0
|
|
@@ -44,6 +44,9 @@ class DatadogSpan {
|
|
|
44
44
|
metrics.increment('runtime.node.spans.unfinished')
|
|
45
45
|
metrics.increment('runtime.node.spans.unfinished.by.name', `span_name:${operationName}`)
|
|
46
46
|
|
|
47
|
+
metrics.increment('runtime.node.spans.open') // unfinished for real
|
|
48
|
+
metrics.increment('runtime.node.spans.open.by.name', `span_name:${operationName}`)
|
|
49
|
+
|
|
47
50
|
unfinishedRegistry.register(this, operationName, this)
|
|
48
51
|
}
|
|
49
52
|
}
|
|
@@ -121,6 +124,9 @@ class DatadogSpan {
|
|
|
121
124
|
metrics.increment('runtime.node.spans.finished')
|
|
122
125
|
metrics.increment('runtime.node.spans.finished.by.name', `span_name:${this._name}`)
|
|
123
126
|
|
|
127
|
+
metrics.decrement('runtime.node.spans.open') // unfinished for real
|
|
128
|
+
metrics.decrement('runtime.node.spans.open.by.name', `span_name:${this._name}`)
|
|
129
|
+
|
|
124
130
|
unfinishedRegistry.unregister(this)
|
|
125
131
|
finishedRegistry.register(this, this._name)
|
|
126
132
|
}
|
|
@@ -7,6 +7,7 @@ module.exports = {
|
|
|
7
7
|
get '@google-cloud/pubsub' () { return require('../../../datadog-plugin-google-cloud-pubsub/src') },
|
|
8
8
|
get '@grpc/grpc-js' () { return require('../../../datadog-plugin-grpc/src') },
|
|
9
9
|
get '@hapi/hapi' () { return require('../../../datadog-plugin-hapi/src') },
|
|
10
|
+
get '@jest/core' () { return require('../../../datadog-plugin-jest/src') },
|
|
10
11
|
get '@koa/router' () { return require('../../../datadog-plugin-koa/src') },
|
|
11
12
|
get '@node-redis/client' () { return require('../../../datadog-plugin-redis/src') },
|
|
12
13
|
get 'amqp10' () { return require('../../../datadog-plugin-amqp10/src') },
|
|
@@ -29,6 +30,8 @@ module.exports = {
|
|
|
29
30
|
get 'http2' () { return require('../../../datadog-plugin-http2/src') },
|
|
30
31
|
get 'https' () { return require('../../../datadog-plugin-http/src') },
|
|
31
32
|
get 'ioredis' () { return require('../../../datadog-plugin-ioredis/src') },
|
|
33
|
+
get 'jest-circus' () { return require('../../../datadog-plugin-jest/src') },
|
|
34
|
+
get 'jest-config' () { return require('../../../datadog-plugin-jest/src') },
|
|
32
35
|
get 'jest-environment-node' () { return require('../../../datadog-plugin-jest/src') },
|
|
33
36
|
get 'jest-environment-jsdom' () { return require('../../../datadog-plugin-jest/src') },
|
|
34
37
|
get 'jest-jasmine2' () { return require('../../../datadog-plugin-jest/src') },
|
|
@@ -7,19 +7,45 @@ if (semver.satisfies(process.version, '>=14.18.0')) {
|
|
|
7
7
|
|
|
8
8
|
module.exports = net.BlockList
|
|
9
9
|
} else {
|
|
10
|
-
const
|
|
10
|
+
const ipaddr = require('ipaddr.js')
|
|
11
11
|
|
|
12
12
|
module.exports = class BlockList {
|
|
13
13
|
constructor () {
|
|
14
|
-
this.
|
|
14
|
+
this.v4Ranges = []
|
|
15
|
+
this.v6Ranges = []
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
addSubnet (net, prefix, type) {
|
|
18
|
-
this.
|
|
19
|
+
this[type === 'ipv4' ? 'v4Ranges' : 'v6Ranges'].push(ipaddr.parseCIDR(`${net}/${prefix}`))
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
check (address, type) {
|
|
22
|
-
|
|
23
|
+
try {
|
|
24
|
+
let ip = ipaddr.parse(address)
|
|
25
|
+
|
|
26
|
+
type = ip.kind()
|
|
27
|
+
|
|
28
|
+
if (type === 'ipv6') {
|
|
29
|
+
for (const range of this.v6Ranges) {
|
|
30
|
+
if (ip.match(range)) return true
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (ip.isIPv4MappedAddress()) {
|
|
34
|
+
ip = ip.toIPv4Address()
|
|
35
|
+
type = ip.kind()
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (type === 'ipv4') {
|
|
40
|
+
for (const range of this.v4Ranges) {
|
|
41
|
+
if (ip.match(range)) return true
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return false
|
|
46
|
+
} catch {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
23
49
|
}
|
|
24
50
|
}
|
|
25
51
|
}
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const analyticsSampler = require('../../analytics_sampler')
|
|
4
|
-
const urlFilter = require('../util/urlfilter')
|
|
5
|
-
const tx = require('./tx')
|
|
6
|
-
|
|
7
|
-
const redis = {
|
|
8
|
-
// Ensure the configuration has the correct structure and defaults.
|
|
9
|
-
normalizeConfig (config) {
|
|
10
|
-
const filter = urlFilter.getFilter(config)
|
|
11
|
-
|
|
12
|
-
return Object.assign({}, config, {
|
|
13
|
-
filter
|
|
14
|
-
})
|
|
15
|
-
},
|
|
16
|
-
|
|
17
|
-
// Start a span for a Redis command.
|
|
18
|
-
instrument (tracer, config, db, command, args) {
|
|
19
|
-
const childOf = tracer.scope().active()
|
|
20
|
-
const span = tracer.startSpan('redis.command', {
|
|
21
|
-
childOf,
|
|
22
|
-
tags: {
|
|
23
|
-
'span.kind': 'client',
|
|
24
|
-
'resource.name': command,
|
|
25
|
-
'span.type': 'redis',
|
|
26
|
-
'db.type': 'redis',
|
|
27
|
-
'db.name': db || '0',
|
|
28
|
-
'redis.raw_command': formatCommand(command, args)
|
|
29
|
-
}
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
span.setTag('service.name', config.service || `${span.context()._tags['service.name']}-redis`)
|
|
33
|
-
|
|
34
|
-
analyticsSampler.sample(span, config.measured)
|
|
35
|
-
|
|
36
|
-
return span
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function formatCommand (command, args) {
|
|
41
|
-
command = command.toUpperCase()
|
|
42
|
-
|
|
43
|
-
if (!args || command === 'AUTH') return command
|
|
44
|
-
|
|
45
|
-
for (let i = 0, l = args.length; i < l; i++) {
|
|
46
|
-
if (typeof args[i] === 'function') continue
|
|
47
|
-
|
|
48
|
-
command = `${command} ${formatArg(args[i])}`
|
|
49
|
-
|
|
50
|
-
if (command.length > 1000) return trim(command, 1000)
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return command
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function formatArg (arg) {
|
|
57
|
-
switch (typeof arg) {
|
|
58
|
-
case 'string':
|
|
59
|
-
case 'number':
|
|
60
|
-
return trim(String(arg), 100)
|
|
61
|
-
default:
|
|
62
|
-
return '?'
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function trim (str, maxlen) {
|
|
67
|
-
if (str.length > maxlen) {
|
|
68
|
-
str = str.substr(0, maxlen - 3) + '...'
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return str
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
module.exports = Object.assign({}, tx, redis)
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const tx = {
|
|
4
|
-
// Set the outgoing host.
|
|
5
|
-
setHost (span, hostname, port) {
|
|
6
|
-
hostname && span.setTag('out.host', hostname)
|
|
7
|
-
port && span.setTag('out.port', port)
|
|
8
|
-
},
|
|
9
|
-
|
|
10
|
-
// Wrap a promise or a callback to also finish the span.
|
|
11
|
-
wrap (span, done) {
|
|
12
|
-
if (typeof done === 'function' || !done) {
|
|
13
|
-
return wrapCallback(span, done)
|
|
14
|
-
} else if (isPromise(done)) {
|
|
15
|
-
return wrapPromise(span, done)
|
|
16
|
-
} else if (done && done.length) {
|
|
17
|
-
return wrapArguments(span, done)
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function wrapCallback (span, callback) {
|
|
23
|
-
const scope = span.tracer().scope()
|
|
24
|
-
const previous = scope.active()
|
|
25
|
-
|
|
26
|
-
return function (err) {
|
|
27
|
-
finish(span, err)
|
|
28
|
-
|
|
29
|
-
if (callback) {
|
|
30
|
-
return scope.activate(previous, () => callback.apply(this, arguments))
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function wrapPromise (span, promise) {
|
|
36
|
-
promise.then(
|
|
37
|
-
() => finish(span),
|
|
38
|
-
err => finish(span, err)
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
return promise
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function wrapArguments (span, args) {
|
|
45
|
-
const lastIndex = args.length - 1
|
|
46
|
-
const callback = args[lastIndex]
|
|
47
|
-
|
|
48
|
-
if (typeof callback === 'function') {
|
|
49
|
-
args[lastIndex] = wrapCallback(span, args[lastIndex])
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return args
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function finish (span, error) {
|
|
56
|
-
if (error) {
|
|
57
|
-
span.addTags({
|
|
58
|
-
'error.type': error.name,
|
|
59
|
-
'error.msg': error.message,
|
|
60
|
-
'error.stack': error.stack
|
|
61
|
-
})
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
span.finish()
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function isPromise (obj) {
|
|
68
|
-
return isObject(obj) && typeof obj.then === 'function'
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function isObject (obj) {
|
|
72
|
-
return typeof obj === 'object' && obj !== null
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
module.exports = tx
|