dd-trace 4.18.0 → 4.22.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/LICENSE-3rdparty.csv +3 -2
- package/README.md +3 -3
- package/ext/kinds.d.ts +1 -0
- package/ext/kinds.js +2 -1
- package/ext/tags.d.ts +2 -1
- package/ext/tags.js +6 -1
- package/index.d.ts +29 -0
- package/package.json +11 -10
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
- package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/register.js +1 -1
- package/packages/datadog-instrumentations/src/http/client.js +10 -0
- package/packages/datadog-instrumentations/src/jest.js +11 -5
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/next.js +18 -6
- package/packages/datadog-instrumentations/src/restify.js +14 -1
- package/packages/datadog-instrumentations/src/rhea.js +15 -9
- package/packages/datadog-plugin-aerospike/src/index.js +113 -0
- package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +3 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
- package/packages/dd-trace/src/appsec/blocking.js +95 -43
- package/packages/dd-trace/src/appsec/channels.js +5 -2
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/index.js +33 -32
- package/packages/dd-trace/src/appsec/recommended.json +1737 -120
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +36 -15
- package/packages/dd-trace/src/appsec/reporter.js +50 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +75 -56
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +22 -6
- package/packages/dd-trace/src/config.js +48 -7
- package/packages/dd-trace/src/datastreams/processor.js +166 -26
- package/packages/dd-trace/src/format.js +6 -1
- package/packages/dd-trace/src/id.js +12 -0
- package/packages/dd-trace/src/iitm.js +1 -1
- package/packages/dd-trace/src/log/channels.js +1 -1
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/opentelemetry/span.js +95 -2
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
- package/packages/dd-trace/src/opentracing/span.js +6 -0
- package/packages/dd-trace/src/opentracing/span_context.js +5 -2
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -1
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/util/ci.js +6 -19
- package/packages/dd-trace/src/plugins/util/git.js +4 -3
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +3 -2
- package/packages/dd-trace/src/plugins/util/url.js +26 -0
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +26 -2
- package/packages/dd-trace/src/profiling/profiler.js +17 -10
- package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
- package/packages/dd-trace/src/proxy.js +25 -1
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
- package/packages/dd-trace/src/span_processor.js +4 -0
- package/packages/dd-trace/src/spanleak.js +98 -0
- package/packages/dd-trace/src/startup-log.js +7 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
- package/packages/dd-trace/src/telemetry/index.js +136 -44
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +47 -5
- package/packages/dd-trace/src/tracer.js +8 -2
- package/scripts/install_plugin_modules.js +11 -3
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -65,7 +65,7 @@ function wrapRenderToHTML (renderToHTML) {
|
|
|
65
65
|
|
|
66
66
|
function wrapRenderErrorToHTML (renderErrorToHTML) {
|
|
67
67
|
return function (err, req, res, pathname, query) {
|
|
68
|
-
return instrument(req, res, () => renderErrorToHTML.apply(this, arguments))
|
|
68
|
+
return instrument(req, res, err, () => renderErrorToHTML.apply(this, arguments))
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -76,8 +76,8 @@ function wrapRenderToResponse (renderToResponse) {
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
function wrapRenderErrorToResponse (renderErrorToResponse) {
|
|
79
|
-
return function (ctx) {
|
|
80
|
-
return instrument(ctx.req, ctx.res, () => renderErrorToResponse.apply(this, arguments))
|
|
79
|
+
return function (ctx, err) {
|
|
80
|
+
return instrument(ctx.req, ctx.res, err, () => renderErrorToResponse.apply(this, arguments))
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
@@ -111,13 +111,23 @@ function getPageFromPath (page, dynamicRoutes = []) {
|
|
|
111
111
|
return getPagePath(page)
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
function instrument (req, res, handler) {
|
|
114
|
+
function instrument (req, res, error, handler) {
|
|
115
|
+
if (typeof error === 'function') {
|
|
116
|
+
handler = error
|
|
117
|
+
error = null
|
|
118
|
+
}
|
|
119
|
+
|
|
115
120
|
req = req.originalRequest || req
|
|
116
121
|
res = res.originalResponse || res
|
|
117
122
|
|
|
118
123
|
// TODO support middleware properly in the future?
|
|
119
124
|
const isMiddleware = req.headers[MIDDLEWARE_HEADER]
|
|
120
|
-
if (isMiddleware || requests.has(req))
|
|
125
|
+
if (isMiddleware || requests.has(req)) {
|
|
126
|
+
if (error) {
|
|
127
|
+
errorChannel.publish({ error })
|
|
128
|
+
}
|
|
129
|
+
return handler()
|
|
130
|
+
}
|
|
121
131
|
|
|
122
132
|
requests.add(req)
|
|
123
133
|
|
|
@@ -144,7 +154,9 @@ function instrument (req, res, handler) {
|
|
|
144
154
|
function wrapServeStatic (serveStatic) {
|
|
145
155
|
return function (req, res, path) {
|
|
146
156
|
return instrument(req, res, () => {
|
|
147
|
-
if (pageLoadChannel.hasSubscribers && path)
|
|
157
|
+
if (pageLoadChannel.hasSubscribers && path) {
|
|
158
|
+
pageLoadChannel.publish({ page: path, isStatic: true })
|
|
159
|
+
}
|
|
148
160
|
|
|
149
161
|
return serveStatic.apply(this, arguments)
|
|
150
162
|
})
|
|
@@ -50,7 +50,20 @@ function wrapFn (fn) {
|
|
|
50
50
|
enterChannel.publish({ req, route })
|
|
51
51
|
|
|
52
52
|
try {
|
|
53
|
-
|
|
53
|
+
const result = fn.apply(this, arguments)
|
|
54
|
+
if (result && typeof result === 'object' && typeof result.then === 'function') {
|
|
55
|
+
return result.then(function () {
|
|
56
|
+
nextChannel.publish({ req })
|
|
57
|
+
finishChannel.publish({ req })
|
|
58
|
+
return arguments[0]
|
|
59
|
+
}).catch(function (error) {
|
|
60
|
+
errorChannel.publish({ req, error })
|
|
61
|
+
nextChannel.publish({ req })
|
|
62
|
+
finishChannel.publish({ req })
|
|
63
|
+
throw error
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
return result
|
|
54
67
|
} catch (error) {
|
|
55
68
|
errorChannel.publish({ req, error })
|
|
56
69
|
nextChannel.publish({ req })
|
|
@@ -22,7 +22,7 @@ const dispatchReceiveCh = channel('apm:rhea:receive:dispatch')
|
|
|
22
22
|
const errorReceiveCh = channel('apm:rhea:receive:error')
|
|
23
23
|
const finishReceiveCh = channel('apm:rhea:receive:finish')
|
|
24
24
|
|
|
25
|
-
const contexts = new WeakMap()
|
|
25
|
+
const contexts = new WeakMap() // key: delivery Fn, val: context
|
|
26
26
|
|
|
27
27
|
addHook({ name: 'rhea', versions: ['>=1'] }, rhea => {
|
|
28
28
|
shimmer.wrap(rhea.message, 'encode', encode => function (msg) {
|
|
@@ -52,7 +52,8 @@ addHook({ name: 'rhea', versions: ['>=1'], file: 'lib/link.js' }, obj => {
|
|
|
52
52
|
startSendCh.publish({ targetAddress, host, port, msg })
|
|
53
53
|
const delivery = send.apply(this, arguments)
|
|
54
54
|
const context = {
|
|
55
|
-
asyncResource
|
|
55
|
+
asyncResource,
|
|
56
|
+
connection: this.connection
|
|
56
57
|
}
|
|
57
58
|
contexts.set(delivery, context)
|
|
58
59
|
|
|
@@ -80,7 +81,8 @@ addHook({ name: 'rhea', versions: ['>=1'], file: 'lib/link.js' }, obj => {
|
|
|
80
81
|
|
|
81
82
|
if (msgObj.delivery) {
|
|
82
83
|
const context = {
|
|
83
|
-
asyncResource
|
|
84
|
+
asyncResource,
|
|
85
|
+
connection: this.connection
|
|
84
86
|
}
|
|
85
87
|
contexts.set(msgObj.delivery, context)
|
|
86
88
|
msgObj.delivery.update = wrapDeliveryUpdate(msgObj.delivery, msgObj.delivery.update)
|
|
@@ -114,7 +116,7 @@ addHook({ name: 'rhea', versions: ['>=1'], file: 'lib/connection.js' }, Connecti
|
|
|
114
116
|
|
|
115
117
|
asyncResource.runInAsyncScope(() => {
|
|
116
118
|
errorReceiveCh.publish(error)
|
|
117
|
-
beforeFinish(delivery, null)
|
|
119
|
+
exports.beforeFinish(delivery, null)
|
|
118
120
|
finishReceiveCh.publish()
|
|
119
121
|
})
|
|
120
122
|
})
|
|
@@ -187,7 +189,7 @@ function patchCircularBuffer (proto, Session) {
|
|
|
187
189
|
const state = remoteState && remoteState.constructor
|
|
188
190
|
? entry.remote_state.constructor.composite_type : undefined
|
|
189
191
|
asyncResource.runInAsyncScope(() => {
|
|
190
|
-
beforeFinish(entry, state)
|
|
192
|
+
exports.beforeFinish(entry, state)
|
|
191
193
|
finishSendCh.publish()
|
|
192
194
|
})
|
|
193
195
|
}
|
|
@@ -217,13 +219,13 @@ function addToInFlightDeliveries (connection, delivery) {
|
|
|
217
219
|
}
|
|
218
220
|
|
|
219
221
|
function beforeFinish (delivery, state) {
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
+
const context = contexts.get(delivery)
|
|
223
|
+
if (context) {
|
|
222
224
|
if (state) {
|
|
223
225
|
dispatchReceiveCh.publish({ state })
|
|
224
226
|
}
|
|
225
|
-
if (
|
|
226
|
-
|
|
227
|
+
if (context.connection && context.connection[inFlightDeliveries]) {
|
|
228
|
+
context.connection[inFlightDeliveries].delete(delivery)
|
|
227
229
|
}
|
|
228
230
|
}
|
|
229
231
|
}
|
|
@@ -238,3 +240,7 @@ function getStateFromData (stateData) {
|
|
|
238
240
|
}
|
|
239
241
|
}
|
|
240
242
|
}
|
|
243
|
+
|
|
244
|
+
module.exports.inFlightDeliveries = inFlightDeliveries
|
|
245
|
+
module.exports.beforeFinish = beforeFinish
|
|
246
|
+
module.exports.contexts = contexts
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { storage } = require('../../datadog-core')
|
|
4
|
+
const DatabasePlugin = require('../../dd-trace/src/plugins/database')
|
|
5
|
+
|
|
6
|
+
const AEROSPIKE_PEER_SERVICE = 'aerospike.namespace'
|
|
7
|
+
|
|
8
|
+
class AerospikePlugin extends DatabasePlugin {
|
|
9
|
+
static get id () { return 'aerospike' }
|
|
10
|
+
static get operation () { return 'command' }
|
|
11
|
+
static get system () { return 'aerospike' }
|
|
12
|
+
static get prefix () {
|
|
13
|
+
return 'tracing:apm:aerospike:command'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
static get peerServicePrecursors () {
|
|
17
|
+
return [AEROSPIKE_PEER_SERVICE]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
bindStart (ctx) {
|
|
21
|
+
const { commandName, commandArgs } = ctx
|
|
22
|
+
const resourceName = commandName.slice(0, commandName.indexOf('Command'))
|
|
23
|
+
const store = storage.getStore()
|
|
24
|
+
const childOf = store ? store.span : null
|
|
25
|
+
const meta = getMeta(resourceName, commandArgs)
|
|
26
|
+
|
|
27
|
+
const span = this.startSpan(this.operationName(), {
|
|
28
|
+
childOf,
|
|
29
|
+
service: this.serviceName({ pluginConfig: this.config }),
|
|
30
|
+
type: 'aerospike',
|
|
31
|
+
kind: 'client',
|
|
32
|
+
resource: resourceName,
|
|
33
|
+
meta
|
|
34
|
+
}, false)
|
|
35
|
+
|
|
36
|
+
ctx.parentStore = store
|
|
37
|
+
ctx.currentStore = { ...store, span }
|
|
38
|
+
|
|
39
|
+
return ctx.currentStore
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
bindAsyncStart (ctx) {
|
|
43
|
+
if (ctx.currentStore) {
|
|
44
|
+
// have to manually trigger peer service calculation when using tracing channel
|
|
45
|
+
this.tagPeerService(ctx.currentStore.span)
|
|
46
|
+
ctx.currentStore.span.finish()
|
|
47
|
+
}
|
|
48
|
+
return ctx.parentStore
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
end (ctx) {
|
|
52
|
+
if (ctx.result) {
|
|
53
|
+
// have to manually trigger peer service calculation when using tracing channel
|
|
54
|
+
this.tagPeerService(ctx.currentStore.span)
|
|
55
|
+
ctx.currentStore.span.finish()
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
error (ctx) {
|
|
60
|
+
if (ctx.error) {
|
|
61
|
+
const error = ctx.error
|
|
62
|
+
const span = ctx.currentStore.span
|
|
63
|
+
span.setTag('error', error)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getMeta (resourceName, commandArgs) {
|
|
69
|
+
let meta = {}
|
|
70
|
+
if (resourceName.includes('Index')) {
|
|
71
|
+
const [ns, set, bin, index] = commandArgs
|
|
72
|
+
meta = getMetaForIndex(ns, set, bin, index)
|
|
73
|
+
} else if (resourceName === 'Query') {
|
|
74
|
+
const { ns, set } = commandArgs[2]
|
|
75
|
+
meta = getMetaForQuery({ ns, set })
|
|
76
|
+
} else if (isKeyObject(commandArgs[0])) {
|
|
77
|
+
const { ns, set, key } = commandArgs[0]
|
|
78
|
+
meta = getMetaForKey(ns, set, key)
|
|
79
|
+
}
|
|
80
|
+
return meta
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getMetaForIndex (ns, set, bin, index) {
|
|
84
|
+
return {
|
|
85
|
+
[AEROSPIKE_PEER_SERVICE]: ns,
|
|
86
|
+
'aerospike.setname': set,
|
|
87
|
+
'aerospike.bin': bin,
|
|
88
|
+
'aerospike.index': index
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getMetaForKey (ns, set, key) {
|
|
93
|
+
return {
|
|
94
|
+
'aerospike.key': `${ns}:${set}:${key}`,
|
|
95
|
+
[AEROSPIKE_PEER_SERVICE]: ns,
|
|
96
|
+
'aerospike.setname': set,
|
|
97
|
+
'aerospike.userkey': key
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function getMetaForQuery (queryObj) {
|
|
102
|
+
const { ns, set } = queryObj
|
|
103
|
+
return {
|
|
104
|
+
[AEROSPIKE_PEER_SERVICE]: ns,
|
|
105
|
+
'aerospike.setname': set
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function isKeyObject (obj) {
|
|
110
|
+
return obj && obj.ns !== undefined && obj.set !== undefined && obj.key !== undefined
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = AerospikePlugin
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
+
const dc = require('dc-polyfill')
|
|
4
5
|
|
|
5
6
|
const collapsedPathSym = Symbol('collapsedPaths')
|
|
6
7
|
|
|
@@ -14,8 +15,6 @@ class GraphQLResolvePlugin extends TracingPlugin {
|
|
|
14
15
|
if (!shouldInstrument(this.config, path)) return
|
|
15
16
|
const computedPathString = path.join('.')
|
|
16
17
|
|
|
17
|
-
addResolver(context, info, args)
|
|
18
|
-
|
|
19
18
|
if (this.config.collapse) {
|
|
20
19
|
if (!context[collapsedPathSym]) {
|
|
21
20
|
context[collapsedPathSym] = {}
|
|
@@ -55,6 +54,10 @@ class GraphQLResolvePlugin extends TracingPlugin {
|
|
|
55
54
|
span.setTag(`graphql.variables.${name}`, variables[name])
|
|
56
55
|
})
|
|
57
56
|
}
|
|
57
|
+
|
|
58
|
+
if (this.resolverStartCh.hasSubscribers) {
|
|
59
|
+
this.resolverStartCh.publish({ context, resolverInfo: getResolverInfo(info, args) })
|
|
60
|
+
}
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
constructor (...args) {
|
|
@@ -69,6 +72,8 @@ class GraphQLResolvePlugin extends TracingPlugin {
|
|
|
69
72
|
field.finishTime = span._getTime ? span._getTime() : 0
|
|
70
73
|
field.error = field.error || err
|
|
71
74
|
})
|
|
75
|
+
|
|
76
|
+
this.resolverStartCh = dc.channel('datadog:graphql:resolver:start')
|
|
72
77
|
}
|
|
73
78
|
|
|
74
79
|
configure (config) {
|
|
@@ -109,28 +114,31 @@ function withCollapse (responsePathAsArray) {
|
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
|
|
112
|
-
function
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
117
|
+
function getResolverInfo (info, args) {
|
|
118
|
+
let resolverInfo = null
|
|
119
|
+
const resolverVars = {}
|
|
116
120
|
|
|
117
|
-
if (
|
|
118
|
-
|
|
121
|
+
if (args && Object.keys(args).length) {
|
|
122
|
+
Object.assign(resolverVars, args)
|
|
119
123
|
}
|
|
120
124
|
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
} else {
|
|
127
|
-
resolvers[info.fieldName] = []
|
|
125
|
+
const directives = info.fieldNodes[0].directives
|
|
126
|
+
for (const directive of directives) {
|
|
127
|
+
const argList = {}
|
|
128
|
+
for (const argument of directive['arguments']) {
|
|
129
|
+
argList[argument.name.value] = argument.value.value
|
|
128
130
|
}
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
|
|
131
|
+
|
|
132
|
+
if (Object.keys(argList).length) {
|
|
133
|
+
resolverVars[directive.name.value] = argList
|
|
132
134
|
}
|
|
133
135
|
}
|
|
136
|
+
|
|
137
|
+
if (Object.keys(resolverVars).length) {
|
|
138
|
+
resolverInfo = { [info.fieldName]: resolverVars }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return resolverInfo
|
|
134
142
|
}
|
|
135
143
|
|
|
136
144
|
module.exports = GraphQLResolvePlugin
|
|
@@ -58,7 +58,7 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
58
58
|
span._spanContext._trace.record = false
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
if (
|
|
61
|
+
if (this.shouldInjectTraceHeaders(options, uri)) {
|
|
62
62
|
this.tracer.inject(span, HTTP_HEADERS, options.headers)
|
|
63
63
|
}
|
|
64
64
|
|
|
@@ -71,6 +71,18 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
71
71
|
return message.currentStore
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
shouldInjectTraceHeaders (options, uri) {
|
|
75
|
+
if (hasAmazonSignature(options) && !this.config.enablePropagationWithAmazonHeaders) {
|
|
76
|
+
return false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!this.config.propagationFilter(uri)) {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return true
|
|
84
|
+
}
|
|
85
|
+
|
|
74
86
|
bindAsyncStart ({ parentStore }) {
|
|
75
87
|
return parentStore
|
|
76
88
|
}
|
|
@@ -98,7 +110,7 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
98
110
|
span.finish()
|
|
99
111
|
}
|
|
100
112
|
|
|
101
|
-
error ({ span, error }) {
|
|
113
|
+
error ({ span, error, args, customRequestTimeout }) {
|
|
102
114
|
if (!span) return
|
|
103
115
|
if (error) {
|
|
104
116
|
span.addTags({
|
|
@@ -107,6 +119,11 @@ class HttpClientPlugin extends ClientPlugin {
|
|
|
107
119
|
[ERROR_STACK]: error.stack
|
|
108
120
|
})
|
|
109
121
|
} else {
|
|
122
|
+
// conditions for no error:
|
|
123
|
+
// 1. not using a custom agent instance with custom timeout specified
|
|
124
|
+
// 2. no invocation of `req.setTimeout`
|
|
125
|
+
if (!args.options.agent?.options.timeout && !customRequestTimeout) return
|
|
126
|
+
|
|
110
127
|
span.setTag('error', 1)
|
|
111
128
|
}
|
|
112
129
|
}
|
|
@@ -1,19 +1,66 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { getMessageSize, CONTEXT_PROPAGATION_KEY } = require('../../dd-trace/src/datastreams/processor')
|
|
3
4
|
const ConsumerPlugin = require('../../dd-trace/src/plugins/consumer')
|
|
4
5
|
|
|
5
6
|
class KafkajsConsumerPlugin extends ConsumerPlugin {
|
|
6
7
|
static get id () { return 'kafkajs' }
|
|
7
8
|
static get operation () { return 'consume' }
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
constructor () {
|
|
11
|
+
super(...arguments)
|
|
12
|
+
this.addSub('apm:kafkajs:consume:commit', message => this.commit(message))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Transform individual commit details sent by kafkajs' event reporter
|
|
17
|
+
* into actionable backlog items for DSM
|
|
18
|
+
*
|
|
19
|
+
* @typedef {object} ConsumerBacklog
|
|
20
|
+
* @property {number} type
|
|
21
|
+
* @property {string} consumer_group
|
|
22
|
+
* @property {string} topic
|
|
23
|
+
* @property {number} partition
|
|
24
|
+
* @property {number} offset
|
|
25
|
+
*
|
|
26
|
+
* @typedef {object} CommitEventItem
|
|
27
|
+
* @property {string} groupId
|
|
28
|
+
* @property {string} topic
|
|
29
|
+
* @property {number} partition
|
|
30
|
+
* @property {import('kafkajs/utils/long').Long} offset
|
|
31
|
+
*
|
|
32
|
+
* @param {CommitEventItem} commit
|
|
33
|
+
* @returns {ConsumerBacklog}
|
|
34
|
+
*/
|
|
35
|
+
transformCommit (commit) {
|
|
36
|
+
const { groupId, partition, offset, topic } = commit
|
|
37
|
+
return {
|
|
38
|
+
partition,
|
|
39
|
+
topic,
|
|
40
|
+
type: 'kafka_commit',
|
|
41
|
+
offset: Number(offset),
|
|
42
|
+
consumer_group: groupId
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
commit (commitList) {
|
|
47
|
+
if (!this.config.dsmEnabled) return
|
|
48
|
+
const keys = [
|
|
49
|
+
'consumer_group',
|
|
50
|
+
'type',
|
|
51
|
+
'partition',
|
|
52
|
+
'offset',
|
|
53
|
+
'topic'
|
|
54
|
+
]
|
|
55
|
+
for (const commit of commitList.map(this.transformCommit)) {
|
|
56
|
+
if (keys.some(key => !commit.hasOwnProperty(key))) continue
|
|
57
|
+
this.tracer.setOffset(commit)
|
|
14
58
|
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
start ({ topic, partition, message, groupId }) {
|
|
15
62
|
const childOf = extract(this.tracer, message.headers)
|
|
16
|
-
this.startSpan({
|
|
63
|
+
const span = this.startSpan({
|
|
17
64
|
childOf,
|
|
18
65
|
resource: topic,
|
|
19
66
|
type: 'worker',
|
|
@@ -26,6 +73,12 @@ class KafkajsConsumerPlugin extends ConsumerPlugin {
|
|
|
26
73
|
'kafka.partition': partition
|
|
27
74
|
}
|
|
28
75
|
})
|
|
76
|
+
if (this.config.dsmEnabled) {
|
|
77
|
+
const payloadSize = getMessageSize(message)
|
|
78
|
+
this.tracer.decodeDataStreamsContext(message.headers[CONTEXT_PROPAGATION_KEY])
|
|
79
|
+
this.tracer
|
|
80
|
+
.setCheckpoint(['direction:in', `group:${groupId}`, `topic:${topic}`, 'type:kafka'], span, payloadSize)
|
|
81
|
+
}
|
|
29
82
|
}
|
|
30
83
|
}
|
|
31
84
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const ProducerPlugin = require('../../dd-trace/src/plugins/producer')
|
|
4
4
|
const { encodePathwayContext } = require('../../dd-trace/src/datastreams/pathway')
|
|
5
|
+
const { getMessageSize, CONTEXT_PROPAGATION_KEY } = require('../../dd-trace/src/datastreams/processor')
|
|
6
|
+
|
|
5
7
|
const BOOTSTRAP_SERVERS_KEY = 'messaging.kafka.bootstrap.servers'
|
|
6
8
|
|
|
7
9
|
class KafkajsProducerPlugin extends ProducerPlugin {
|
|
@@ -9,13 +11,63 @@ class KafkajsProducerPlugin extends ProducerPlugin {
|
|
|
9
11
|
static get operation () { return 'produce' }
|
|
10
12
|
static get peerServicePrecursors () { return [BOOTSTRAP_SERVERS_KEY] }
|
|
11
13
|
|
|
14
|
+
constructor () {
|
|
15
|
+
super(...arguments)
|
|
16
|
+
this.addSub('apm:kafkajs:produce:commit', message => this.commit(message))
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Transform individual commit details sent by kafkajs' event reporter
|
|
21
|
+
* into actionable backlog items for DSM
|
|
22
|
+
*
|
|
23
|
+
* @typedef {object} ProducerBacklog
|
|
24
|
+
* @property {number} type
|
|
25
|
+
* @property {string} topic
|
|
26
|
+
* @property {number} partition
|
|
27
|
+
* @property {number} offset
|
|
28
|
+
*
|
|
29
|
+
* @typedef {object} ProducerResponseItem
|
|
30
|
+
* @property {string} topic
|
|
31
|
+
* @property {number} partition
|
|
32
|
+
* @property {import('kafkajs/utils/long').Long} [offset]
|
|
33
|
+
* @property {import('kafkajs/utils/long').Long} [baseOffset]
|
|
34
|
+
*
|
|
35
|
+
* @param {ProducerResponseItem} response
|
|
36
|
+
* @returns {ProducerBacklog}
|
|
37
|
+
*/
|
|
38
|
+
transformProduceResponse (response) {
|
|
39
|
+
// In produce protocol >=v3, the offset key changes from `offset` to `baseOffset`
|
|
40
|
+
const { topicName: topic, partition, offset, baseOffset } = response
|
|
41
|
+
const offsetAsLong = offset || baseOffset
|
|
42
|
+
return {
|
|
43
|
+
type: 'kafka_produce',
|
|
44
|
+
partition,
|
|
45
|
+
offset: offsetAsLong ? Number(offsetAsLong) : undefined,
|
|
46
|
+
topic
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* @param {ProducerResponseItem[]} commitList
|
|
53
|
+
* @returns {void}
|
|
54
|
+
*/
|
|
55
|
+
commit (commitList) {
|
|
56
|
+
if (!this.config.dsmEnabled) return
|
|
57
|
+
const keys = [
|
|
58
|
+
'type',
|
|
59
|
+
'partition',
|
|
60
|
+
'offset',
|
|
61
|
+
'topic'
|
|
62
|
+
]
|
|
63
|
+
for (const commit of commitList.map(this.transformProduceResponse)) {
|
|
64
|
+
if (keys.some(key => !commit.hasOwnProperty(key))) continue
|
|
65
|
+
this.tracer.setOffset(commit)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
12
69
|
start ({ topic, messages, bootstrapServers }) {
|
|
13
70
|
let pathwayCtx
|
|
14
|
-
if (this.config.dsmEnabled) {
|
|
15
|
-
const dataStreamsContext = this.tracer
|
|
16
|
-
.setCheckpoint(['direction:out', `topic:${topic}`, 'type:kafka'])
|
|
17
|
-
pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
18
|
-
}
|
|
19
71
|
const span = this.startSpan({
|
|
20
72
|
resource: topic,
|
|
21
73
|
meta: {
|
|
@@ -31,8 +83,14 @@ class KafkajsProducerPlugin extends ProducerPlugin {
|
|
|
31
83
|
}
|
|
32
84
|
for (const message of messages) {
|
|
33
85
|
if (typeof message === 'object') {
|
|
34
|
-
if (this.config.dsmEnabled) message.headers['dd-pathway-ctx'] = pathwayCtx
|
|
35
86
|
this.tracer.inject(span, 'text_map', message.headers)
|
|
87
|
+
if (this.config.dsmEnabled) {
|
|
88
|
+
const payloadSize = getMessageSize(message)
|
|
89
|
+
const dataStreamsContext = this.tracer
|
|
90
|
+
.setCheckpoint(['direction:out', `topic:${topic}`, 'type:kafka'], span, payloadSize)
|
|
91
|
+
pathwayCtx = encodePathwayContext(dataStreamsContext)
|
|
92
|
+
message.headers[CONTEXT_PROPAGATION_KEY] = pathwayCtx
|
|
93
|
+
}
|
|
36
94
|
}
|
|
37
95
|
}
|
|
38
96
|
}
|
|
@@ -6,6 +6,8 @@ const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
|
|
|
6
6
|
const { COMPONENT } = require('../../dd-trace/src/constants')
|
|
7
7
|
const web = require('../../dd-trace/src/plugins/util/web')
|
|
8
8
|
|
|
9
|
+
const errorPages = ['/404', '/500', '/_error', '/_not-found']
|
|
10
|
+
|
|
9
11
|
class NextPlugin extends ServerPlugin {
|
|
10
12
|
static get id () {
|
|
11
13
|
return 'next'
|
|
@@ -40,6 +42,13 @@ class NextPlugin extends ServerPlugin {
|
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
error ({ span, error }) {
|
|
45
|
+
if (!span) {
|
|
46
|
+
const store = storage.getStore()
|
|
47
|
+
if (!store) return
|
|
48
|
+
|
|
49
|
+
span = store.span
|
|
50
|
+
}
|
|
51
|
+
|
|
43
52
|
this.addError(error, span)
|
|
44
53
|
}
|
|
45
54
|
|
|
@@ -50,10 +59,20 @@ class NextPlugin extends ServerPlugin {
|
|
|
50
59
|
|
|
51
60
|
const span = store.span
|
|
52
61
|
const error = span.context()._tags['error']
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
const requestError = req.error || nextRequest.error
|
|
63
|
+
|
|
64
|
+
if (requestError) {
|
|
65
|
+
// prioritize user-set errors from API routes
|
|
66
|
+
span.setTag('error', requestError)
|
|
67
|
+
web.addError(req, requestError)
|
|
68
|
+
} else if (error) {
|
|
69
|
+
// general error handling
|
|
70
|
+
span.setTag('error', error)
|
|
71
|
+
web.addError(req, requestError || error)
|
|
72
|
+
} else if (!this.config.validateStatus(res.statusCode)) {
|
|
73
|
+
// where there's no error, we still need to validate status
|
|
74
|
+
span.setTag('error', true)
|
|
75
|
+
web.addError(req, true)
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
span.addTags({
|
|
@@ -65,7 +84,7 @@ class NextPlugin extends ServerPlugin {
|
|
|
65
84
|
span.finish()
|
|
66
85
|
}
|
|
67
86
|
|
|
68
|
-
pageLoad ({ page, isAppPath = false }) {
|
|
87
|
+
pageLoad ({ page, isAppPath = false, isStatic = false }) {
|
|
69
88
|
const store = storage.getStore()
|
|
70
89
|
|
|
71
90
|
if (!store) return
|
|
@@ -73,21 +92,28 @@ class NextPlugin extends ServerPlugin {
|
|
|
73
92
|
const span = store.span
|
|
74
93
|
const req = this._requests.get(span)
|
|
75
94
|
|
|
95
|
+
// safeguard against missing req in complicated timeout scenarios
|
|
96
|
+
if (!req) return
|
|
97
|
+
|
|
76
98
|
// Only use error page names if there's not already a name
|
|
77
99
|
const current = span.context()._tags['next.page']
|
|
78
|
-
|
|
100
|
+
const isErrorPage = errorPages.includes(page)
|
|
101
|
+
|
|
102
|
+
if (current && isErrorPage) {
|
|
79
103
|
return
|
|
80
104
|
}
|
|
81
105
|
|
|
82
106
|
// remove ending /route or /page for appDir projects
|
|
83
|
-
if
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
107
|
+
// need to check if not an error page too, as those are marked as app directory
|
|
108
|
+
// in newer versions
|
|
109
|
+
if (isAppPath && !isErrorPage) page = page.substring(0, page.lastIndexOf('/'))
|
|
110
|
+
|
|
111
|
+
// handle static resource
|
|
112
|
+
if (isStatic) {
|
|
113
|
+
page = req.url.includes('_next/static')
|
|
114
|
+
? '/_next/static/*'
|
|
115
|
+
: '/public/*'
|
|
116
|
+
}
|
|
91
117
|
|
|
92
118
|
span.addTags({
|
|
93
119
|
[COMPONENT]: this.constructor.id,
|