dd-trace 5.24.0 → 5.26.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 -0
- package/index.d.ts +345 -8
- package/init.js +60 -47
- package/package.json +16 -7
- package/packages/datadog-code-origin/index.js +4 -4
- package/packages/datadog-core/index.js +1 -3
- package/packages/datadog-core/src/storage.js +21 -0
- package/packages/datadog-core/src/utils/src/parse-tags.js +33 -0
- package/packages/datadog-esbuild/index.js +4 -2
- package/packages/datadog-instrumentations/src/amqplib.js +65 -5
- package/packages/datadog-instrumentations/src/child_process.js +135 -27
- package/packages/datadog-instrumentations/src/express.js +1 -1
- package/packages/datadog-instrumentations/src/handlebars.js +40 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +5 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +9 -0
- package/packages/datadog-instrumentations/src/jest.js +6 -2
- package/packages/datadog-instrumentations/src/kafkajs.js +123 -63
- package/packages/datadog-instrumentations/src/mocha/utils.js +2 -2
- package/packages/datadog-instrumentations/src/multer.js +37 -0
- package/packages/datadog-instrumentations/src/openai.js +2 -2
- package/packages/datadog-instrumentations/src/pug.js +23 -0
- package/packages/datadog-instrumentations/src/router.js +2 -3
- package/packages/datadog-instrumentations/src/url.js +84 -0
- package/packages/datadog-instrumentations/src/utils/src/extract-package-and-module-path.js +7 -4
- package/packages/datadog-plugin-amqplib/src/consumer.js +6 -5
- package/packages/datadog-plugin-aws-sdk/src/base.js +5 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +10 -7
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +35 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +11 -9
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +59 -45
- package/packages/datadog-plugin-cypress/src/support.js +1 -0
- package/packages/datadog-plugin-fastify/src/code_origin.js +2 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +10 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +8 -0
- package/packages/datadog-plugin-grpc/src/client.js +3 -0
- package/packages/datadog-plugin-grpc/src/server.js +5 -1
- package/packages/datadog-plugin-http/src/client.js +42 -1
- package/packages/datadog-plugin-http2/src/client.js +26 -1
- package/packages/datadog-plugin-jest/src/index.js +2 -1
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +6 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +10 -5
- package/packages/datadog-plugin-kafkajs/src/producer.js +10 -4
- package/packages/datadog-plugin-mocha/src/index.js +5 -2
- package/packages/datadog-plugin-moleculer/src/server.js +2 -2
- package/packages/datadog-plugin-openai/src/index.js +9 -1015
- package/packages/datadog-plugin-openai/src/tracing.js +1023 -0
- package/packages/datadog-plugin-rhea/src/consumer.js +2 -1
- package/packages/datadog-plugin-vitest/src/index.js +2 -1
- package/packages/dd-trace/src/appsec/addresses.js +2 -0
- package/packages/dd-trace/src/appsec/api_security_sampler.js +50 -27
- package/packages/dd-trace/src/appsec/channels.js +3 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +33 -16
- package/packages/dd-trace/src/appsec/iast/analyzers/template-injection-analyzer.js +18 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +55 -7
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +3 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +4 -2
- package/packages/dd-trace/src/appsec/index.js +9 -6
- package/packages/dd-trace/src/appsec/rasp/command_injection.js +49 -0
- package/packages/dd-trace/src/appsec/rasp/index.js +3 -0
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +4 -3
- package/packages/dd-trace/src/appsec/rasp/utils.js +3 -2
- package/packages/dd-trace/src/appsec/recommended.json +354 -158
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +2 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +2 -7
- package/packages/dd-trace/src/appsec/reporter.js +6 -4
- package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -3
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +4 -0
- package/packages/dd-trace/src/azure_metadata.js +120 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +97 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +90 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +19 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +53 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +8 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +43 -0
- package/packages/dd-trace/src/config.js +88 -10
- package/packages/dd-trace/src/constants.js +8 -1
- package/packages/dd-trace/src/crashtracking/crashtracker.js +98 -0
- package/packages/dd-trace/src/crashtracking/index.js +15 -0
- package/packages/dd-trace/src/crashtracking/noop.js +8 -0
- package/packages/dd-trace/src/datastreams/pathway.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +9 -13
- package/packages/dd-trace/src/debugger/devtools_client/send.js +15 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +57 -23
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +12 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +31 -20
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/symbols.js +6 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +11 -2
- package/packages/dd-trace/src/debugger/index.js +10 -3
- package/packages/dd-trace/src/llmobs/constants/tags.js +34 -0
- package/packages/dd-trace/src/llmobs/constants/text.js +6 -0
- package/packages/dd-trace/src/llmobs/constants/writers.js +13 -0
- package/packages/dd-trace/src/llmobs/index.js +103 -0
- package/packages/dd-trace/src/llmobs/noop.js +82 -0
- package/packages/dd-trace/src/llmobs/plugins/base.js +65 -0
- package/packages/dd-trace/src/llmobs/plugins/openai.js +205 -0
- package/packages/dd-trace/src/llmobs/sdk.js +377 -0
- package/packages/dd-trace/src/llmobs/span_processor.js +195 -0
- package/packages/dd-trace/src/llmobs/storage.js +7 -0
- package/packages/dd-trace/src/llmobs/tagger.js +322 -0
- package/packages/dd-trace/src/llmobs/util.js +176 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +111 -0
- package/packages/dd-trace/src/llmobs/writers/evaluations.js +29 -0
- package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +23 -0
- package/packages/dd-trace/src/llmobs/writers/spans/agentless.js +17 -0
- package/packages/dd-trace/src/llmobs/writers/spans/base.js +52 -0
- package/packages/dd-trace/src/log/index.js +10 -13
- package/packages/dd-trace/src/log/log.js +52 -0
- package/packages/dd-trace/src/log/writer.js +50 -19
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/noop/span.js +4 -0
- package/packages/dd-trace/src/opentelemetry/span.js +16 -1
- package/packages/dd-trace/src/opentelemetry/tracer.js +1 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +106 -32
- package/packages/dd-trace/src/opentracing/span.js +26 -0
- package/packages/dd-trace/src/opentracing/span_context.js +1 -0
- package/packages/dd-trace/src/opentracing/tracer.js +8 -1
- package/packages/dd-trace/src/payload-tagging/config/aws.json +71 -3
- package/packages/dd-trace/src/plugins/outbound.js +9 -0
- package/packages/dd-trace/src/plugins/tracing.js +3 -3
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +121 -0
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +0 -1
- package/packages/dd-trace/src/plugins/util/web.js +39 -11
- package/packages/dd-trace/src/priority_sampler.js +16 -0
- package/packages/dd-trace/src/profiling/config.js +3 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +7 -5
- package/packages/dd-trace/src/profiling/profilers/wall.js +2 -1
- package/packages/dd-trace/src/proxy.js +13 -1
- package/packages/dd-trace/src/span_processor.js +5 -0
- package/packages/dd-trace/src/telemetry/index.js +11 -1
- package/packages/dd-trace/src/telemetry/logs/index.js +16 -11
- package/packages/dd-trace/src/telemetry/logs/log-collector.js +3 -8
- package/packages/dd-trace/src/telemetry/metrics.js +6 -1
- package/packages/dd-trace/src/util.js +16 -1
- package/version.js +4 -2
- /package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/{code-injection-sensitive-analyzer.js → tainted-range-based-sensitive-analyzer.js} +0 -0
|
@@ -52,45 +52,59 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
52
52
|
const send = producer.send
|
|
53
53
|
const bootstrapServers = this._brokers
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
55
|
+
const kafkaClusterIdPromise = getKafkaClusterId(this)
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
57
|
+
producer.send = function () {
|
|
58
|
+
const wrappedSend = (clusterId) => {
|
|
59
|
+
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
62
60
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (message !== null && typeof message === 'object') {
|
|
67
|
-
message.headers = message.headers || {}
|
|
68
|
-
}
|
|
61
|
+
return innerAsyncResource.runInAsyncScope(() => {
|
|
62
|
+
if (!producerStartCh.hasSubscribers) {
|
|
63
|
+
return send.apply(this, arguments)
|
|
69
64
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
producerFinishCh.publish(undefined)
|
|
77
|
-
producerCommitCh.publish(res)
|
|
78
|
-
}),
|
|
79
|
-
innerAsyncResource.bind(err => {
|
|
80
|
-
if (err) {
|
|
81
|
-
producerErrorCh.publish(err)
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const { topic, messages = [] } = arguments[0]
|
|
68
|
+
for (const message of messages) {
|
|
69
|
+
if (message !== null && typeof message === 'object') {
|
|
70
|
+
message.headers = message.headers || {}
|
|
82
71
|
}
|
|
83
|
-
|
|
84
|
-
})
|
|
85
|
-
)
|
|
72
|
+
}
|
|
73
|
+
producerStartCh.publish({ topic, messages, bootstrapServers, clusterId })
|
|
86
74
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
75
|
+
const result = send.apply(this, arguments)
|
|
76
|
+
|
|
77
|
+
result.then(
|
|
78
|
+
innerAsyncResource.bind(res => {
|
|
79
|
+
producerFinishCh.publish(undefined)
|
|
80
|
+
producerCommitCh.publish(res)
|
|
81
|
+
}),
|
|
82
|
+
innerAsyncResource.bind(err => {
|
|
83
|
+
if (err) {
|
|
84
|
+
producerErrorCh.publish(err)
|
|
85
|
+
}
|
|
86
|
+
producerFinishCh.publish(undefined)
|
|
87
|
+
})
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
return result
|
|
91
|
+
} catch (e) {
|
|
92
|
+
producerErrorCh.publish(e)
|
|
93
|
+
producerFinishCh.publish(undefined)
|
|
94
|
+
throw e
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (!isPromise(kafkaClusterIdPromise)) {
|
|
100
|
+
// promise is already resolved
|
|
101
|
+
return wrappedSend(kafkaClusterIdPromise)
|
|
102
|
+
} else {
|
|
103
|
+
// promise is not resolved
|
|
104
|
+
return kafkaClusterIdPromise.then((clusterId) => {
|
|
105
|
+
return wrappedSend(clusterId)
|
|
106
|
+
})
|
|
107
|
+
}
|
|
94
108
|
}
|
|
95
109
|
return producer
|
|
96
110
|
})
|
|
@@ -100,15 +114,17 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
100
114
|
return createConsumer.apply(this, arguments)
|
|
101
115
|
}
|
|
102
116
|
|
|
103
|
-
const
|
|
117
|
+
const kafkaClusterIdPromise = getKafkaClusterId(this)
|
|
118
|
+
|
|
119
|
+
const eachMessageExtractor = (args, clusterId) => {
|
|
104
120
|
const { topic, partition, message } = args[0]
|
|
105
|
-
return { topic, partition, message, groupId }
|
|
121
|
+
return { topic, partition, message, groupId, clusterId }
|
|
106
122
|
}
|
|
107
123
|
|
|
108
|
-
const eachBatchExtractor = (args) => {
|
|
124
|
+
const eachBatchExtractor = (args, clusterId) => {
|
|
109
125
|
const { batch } = args[0]
|
|
110
126
|
const { topic, partition, messages } = batch
|
|
111
|
-
return { topic, partition, messages, groupId }
|
|
127
|
+
return { topic, partition, messages, groupId, clusterId }
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
const consumer = createConsumer.apply(this, arguments)
|
|
@@ -116,43 +132,53 @@ addHook({ name: 'kafkajs', file: 'src/index.js', versions: ['>=1.4'] }, (BaseKaf
|
|
|
116
132
|
consumer.on(consumer.events.COMMIT_OFFSETS, commitsFromEvent)
|
|
117
133
|
|
|
118
134
|
const run = consumer.run
|
|
119
|
-
|
|
120
135
|
const groupId = arguments[0].groupId
|
|
136
|
+
|
|
121
137
|
consumer.run = function ({ eachMessage, eachBatch, ...runArgs }) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
138
|
+
const wrapConsume = (clusterId) => {
|
|
139
|
+
return run({
|
|
140
|
+
eachMessage: wrappedCallback(
|
|
141
|
+
eachMessage,
|
|
142
|
+
consumerStartCh,
|
|
143
|
+
consumerFinishCh,
|
|
144
|
+
consumerErrorCh,
|
|
145
|
+
eachMessageExtractor,
|
|
146
|
+
clusterId
|
|
147
|
+
),
|
|
148
|
+
eachBatch: wrappedCallback(
|
|
149
|
+
eachBatch,
|
|
150
|
+
batchConsumerStartCh,
|
|
151
|
+
batchConsumerFinishCh,
|
|
152
|
+
batchConsumerErrorCh,
|
|
153
|
+
eachBatchExtractor,
|
|
154
|
+
clusterId
|
|
155
|
+
),
|
|
156
|
+
...runArgs
|
|
157
|
+
})
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!isPromise(kafkaClusterIdPromise)) {
|
|
161
|
+
// promise is already resolved
|
|
162
|
+
return wrapConsume(kafkaClusterIdPromise)
|
|
163
|
+
} else {
|
|
164
|
+
// promise is not resolved
|
|
165
|
+
return kafkaClusterIdPromise.then((clusterId) => {
|
|
166
|
+
return wrapConsume(clusterId)
|
|
167
|
+
})
|
|
168
|
+
}
|
|
143
169
|
}
|
|
144
|
-
|
|
145
170
|
return consumer
|
|
146
171
|
})
|
|
147
172
|
return Kafka
|
|
148
173
|
})
|
|
149
174
|
|
|
150
|
-
const
|
|
175
|
+
const wrappedCallback = (fn, startCh, finishCh, errorCh, extractArgs, clusterId) => {
|
|
151
176
|
return typeof fn === 'function'
|
|
152
177
|
? function (...args) {
|
|
153
178
|
const innerAsyncResource = new AsyncResource('bound-anonymous-fn')
|
|
154
179
|
return innerAsyncResource.runInAsyncScope(() => {
|
|
155
|
-
const extractedArgs = extractArgs(args)
|
|
180
|
+
const extractedArgs = extractArgs(args, clusterId)
|
|
181
|
+
|
|
156
182
|
startCh.publish(extractedArgs)
|
|
157
183
|
try {
|
|
158
184
|
const result = fn.apply(this, args)
|
|
@@ -179,3 +205,37 @@ const wrapFunction = (fn, startCh, finishCh, errorCh, extractArgs) => {
|
|
|
179
205
|
}
|
|
180
206
|
: fn
|
|
181
207
|
}
|
|
208
|
+
|
|
209
|
+
const getKafkaClusterId = (kafka) => {
|
|
210
|
+
if (kafka._ddKafkaClusterId) {
|
|
211
|
+
return kafka._ddKafkaClusterId
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (!kafka.admin) {
|
|
215
|
+
return null
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const admin = kafka.admin()
|
|
219
|
+
|
|
220
|
+
if (!admin.describeCluster) {
|
|
221
|
+
return null
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return admin.connect()
|
|
225
|
+
.then(() => {
|
|
226
|
+
return admin.describeCluster()
|
|
227
|
+
})
|
|
228
|
+
.then((clusterInfo) => {
|
|
229
|
+
const clusterId = clusterInfo?.clusterId
|
|
230
|
+
kafka._ddKafkaClusterId = clusterId
|
|
231
|
+
admin.disconnect()
|
|
232
|
+
return clusterId
|
|
233
|
+
})
|
|
234
|
+
.catch((error) => {
|
|
235
|
+
throw error
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function isPromise (obj) {
|
|
240
|
+
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
|
|
241
|
+
}
|
|
@@ -280,12 +280,12 @@ function getOnFailHandler (isMain) {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
function getOnTestRetryHandler () {
|
|
283
|
-
return function (test) {
|
|
283
|
+
return function (test, err) {
|
|
284
284
|
const asyncResource = getTestAsyncResource(test)
|
|
285
285
|
if (asyncResource) {
|
|
286
286
|
const isFirstAttempt = test._currentRetry === 0
|
|
287
287
|
asyncResource.runInAsyncScope(() => {
|
|
288
|
-
testRetryCh.publish(isFirstAttempt)
|
|
288
|
+
testRetryCh.publish({ isFirstAttempt, err })
|
|
289
289
|
})
|
|
290
290
|
}
|
|
291
291
|
const key = getTestToArKey(test)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const shimmer = require('../../datadog-shimmer')
|
|
4
|
+
const { channel, addHook, AsyncResource } = require('./helpers/instrument')
|
|
5
|
+
|
|
6
|
+
const multerReadCh = channel('datadog:multer:read:finish')
|
|
7
|
+
|
|
8
|
+
function publishRequestBodyAndNext (req, res, next) {
|
|
9
|
+
return shimmer.wrapFunction(next, next => function () {
|
|
10
|
+
if (multerReadCh.hasSubscribers && req) {
|
|
11
|
+
const abortController = new AbortController()
|
|
12
|
+
const body = req.body
|
|
13
|
+
|
|
14
|
+
multerReadCh.publish({ req, res, body, abortController })
|
|
15
|
+
|
|
16
|
+
if (abortController.signal.aborted) return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return next.apply(this, arguments)
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
addHook({
|
|
24
|
+
name: 'multer',
|
|
25
|
+
file: 'lib/make-middleware.js',
|
|
26
|
+
versions: ['^1.4.4-lts.1']
|
|
27
|
+
}, makeMiddleware => {
|
|
28
|
+
return shimmer.wrapFunction(makeMiddleware, makeMiddleware => function () {
|
|
29
|
+
const middleware = makeMiddleware.apply(this, arguments)
|
|
30
|
+
|
|
31
|
+
return shimmer.wrapFunction(middleware, middleware => function wrapMulterMiddleware (req, res, next) {
|
|
32
|
+
const nextResource = new AsyncResource('bound-anonymous-fn')
|
|
33
|
+
arguments[2] = nextResource.bind(publishRequestBodyAndNext(req, res, next))
|
|
34
|
+
return middleware.apply(this, arguments)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
})
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
const { addHook } = require('./helpers/instrument')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
5
|
|
|
6
|
-
const
|
|
7
|
-
const ch = tracingChannel('apm:openai:request')
|
|
6
|
+
const dc = require('dc-polyfill')
|
|
7
|
+
const ch = dc.tracingChannel('apm:openai:request')
|
|
8
8
|
|
|
9
9
|
const V4_PACKAGE_SHIMS = [
|
|
10
10
|
{
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const shimmer = require('../../datadog-shimmer')
|
|
4
|
+
const { channel, addHook } = require('./helpers/instrument')
|
|
5
|
+
|
|
6
|
+
const pugCompileCh = channel('datadog:pug:compile:start')
|
|
7
|
+
|
|
8
|
+
function wrapCompile (compile) {
|
|
9
|
+
return function wrappedCompile (source) {
|
|
10
|
+
if (pugCompileCh.hasSubscribers) {
|
|
11
|
+
pugCompileCh.publish({ source })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return compile.apply(this, arguments)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
addHook({ name: 'pug', versions: ['>=2.0.4'] }, compiler => {
|
|
19
|
+
shimmer.wrap(compiler, 'compile', wrapCompile)
|
|
20
|
+
shimmer.wrap(compiler, 'compileClientWithDependenciesTracked', wrapCompile)
|
|
21
|
+
|
|
22
|
+
return compiler
|
|
23
|
+
})
|
|
@@ -112,7 +112,6 @@ function createWrapRouterMethod (name) {
|
|
|
112
112
|
path: pattern instanceof RegExp ? `(${pattern})` : pattern,
|
|
113
113
|
test: layer => {
|
|
114
114
|
const matchers = layerMatchers.get(layer)
|
|
115
|
-
|
|
116
115
|
return !isFastStar(layer, matchers) &&
|
|
117
116
|
!isFastSlash(layer, matchers) &&
|
|
118
117
|
cachedPathToRegExp(pattern).test(layer.path)
|
|
@@ -121,7 +120,7 @@ function createWrapRouterMethod (name) {
|
|
|
121
120
|
}
|
|
122
121
|
|
|
123
122
|
function isFastStar (layer, matchers) {
|
|
124
|
-
if (layer.regexp
|
|
123
|
+
if (layer.regexp?.fast_star !== undefined) {
|
|
125
124
|
return layer.regexp.fast_star
|
|
126
125
|
}
|
|
127
126
|
|
|
@@ -129,7 +128,7 @@ function createWrapRouterMethod (name) {
|
|
|
129
128
|
}
|
|
130
129
|
|
|
131
130
|
function isFastSlash (layer, matchers) {
|
|
132
|
-
if (layer.regexp
|
|
131
|
+
if (layer.regexp?.fast_slash !== undefined) {
|
|
133
132
|
return layer.regexp.fast_slash
|
|
134
133
|
}
|
|
135
134
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
const names = ['url', 'node:url']
|
|
6
|
+
|
|
7
|
+
const parseFinishedChannel = channel('datadog:url:parse:finish')
|
|
8
|
+
const urlGetterChannel = channel('datadog:url:getter:finish')
|
|
9
|
+
const instrumentedGetters = ['host', 'origin', 'hostname']
|
|
10
|
+
|
|
11
|
+
addHook({ name: names }, function (url) {
|
|
12
|
+
shimmer.wrap(url, 'parse', (parse) => {
|
|
13
|
+
return function wrappedParse (input) {
|
|
14
|
+
const parsedValue = parse.apply(this, arguments)
|
|
15
|
+
if (!parseFinishedChannel.hasSubscribers) return parsedValue
|
|
16
|
+
|
|
17
|
+
parseFinishedChannel.publish({
|
|
18
|
+
input,
|
|
19
|
+
parsed: parsedValue,
|
|
20
|
+
isURL: false
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
return parsedValue
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
const URLPrototype = url.URL.prototype.constructor.prototype
|
|
28
|
+
instrumentedGetters.forEach(property => {
|
|
29
|
+
const originalDescriptor = Object.getOwnPropertyDescriptor(URLPrototype, property)
|
|
30
|
+
|
|
31
|
+
if (originalDescriptor?.get) {
|
|
32
|
+
const newDescriptor = shimmer.wrap(originalDescriptor, 'get', function (originalGet) {
|
|
33
|
+
return function get () {
|
|
34
|
+
const result = originalGet.apply(this, arguments)
|
|
35
|
+
if (!urlGetterChannel.hasSubscribers) return result
|
|
36
|
+
|
|
37
|
+
const context = { urlObject: this, result, property }
|
|
38
|
+
urlGetterChannel.publish(context)
|
|
39
|
+
|
|
40
|
+
return context.result
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
Object.defineProperty(URLPrototype, property, newDescriptor)
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
shimmer.wrap(url, 'URL', (URL) => {
|
|
49
|
+
return class extends URL {
|
|
50
|
+
constructor (input, base) {
|
|
51
|
+
super(...arguments)
|
|
52
|
+
|
|
53
|
+
if (!parseFinishedChannel.hasSubscribers) return
|
|
54
|
+
|
|
55
|
+
parseFinishedChannel.publish({
|
|
56
|
+
input,
|
|
57
|
+
base,
|
|
58
|
+
parsed: this,
|
|
59
|
+
isURL: true
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
if (url.URL.parse) {
|
|
66
|
+
shimmer.wrap(url.URL, 'parse', (parse) => {
|
|
67
|
+
return function wrappedParse (input, base) {
|
|
68
|
+
const parsedValue = parse.apply(this, arguments)
|
|
69
|
+
if (!parseFinishedChannel.hasSubscribers) return parsedValue
|
|
70
|
+
|
|
71
|
+
parseFinishedChannel.publish({
|
|
72
|
+
input,
|
|
73
|
+
base,
|
|
74
|
+
parsed: parsedValue,
|
|
75
|
+
isURL: true
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
return parsedValue
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return url
|
|
84
|
+
})
|
|
@@ -6,7 +6,7 @@ const NM = 'node_modules/'
|
|
|
6
6
|
* For a given full path to a module,
|
|
7
7
|
* return the package name it belongs to and the local path to the module
|
|
8
8
|
* input: '/foo/node_modules/@co/stuff/foo/bar/baz.js'
|
|
9
|
-
* output: { pkg: '@co/stuff', path: 'foo/bar/baz.js' }
|
|
9
|
+
* output: { pkg: '@co/stuff', path: 'foo/bar/baz.js', pkgJson: '/foo/node_modules/@co/stuff/package.json' }
|
|
10
10
|
*/
|
|
11
11
|
module.exports = function extractPackageAndModulePath (fullPath) {
|
|
12
12
|
const nm = fullPath.lastIndexOf(NM)
|
|
@@ -17,17 +17,20 @@ module.exports = function extractPackageAndModulePath (fullPath) {
|
|
|
17
17
|
const subPath = fullPath.substring(nm + NM.length)
|
|
18
18
|
const firstSlash = subPath.indexOf('/')
|
|
19
19
|
|
|
20
|
+
const firstPath = fullPath.substring(fullPath[0], nm + NM.length)
|
|
21
|
+
|
|
20
22
|
if (subPath[0] === '@') {
|
|
21
23
|
const secondSlash = subPath.substring(firstSlash + 1).indexOf('/')
|
|
22
|
-
|
|
23
24
|
return {
|
|
24
25
|
pkg: subPath.substring(0, firstSlash + 1 + secondSlash),
|
|
25
|
-
path: subPath.substring(firstSlash + 1 + secondSlash + 1)
|
|
26
|
+
path: subPath.substring(firstSlash + 1 + secondSlash + 1),
|
|
27
|
+
pkgJson: firstPath + subPath.substring(0, firstSlash + 1 + secondSlash) + '/package.json'
|
|
26
28
|
}
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
return {
|
|
30
32
|
pkg: subPath.substring(0, firstSlash),
|
|
31
|
-
path: subPath.substring(firstSlash + 1)
|
|
33
|
+
path: subPath.substring(firstSlash + 1),
|
|
34
|
+
pkgJson: firstPath + subPath.substring(0, firstSlash) + '/package.json'
|
|
32
35
|
}
|
|
33
36
|
}
|
|
@@ -9,33 +9,34 @@ class AmqplibConsumerPlugin extends ConsumerPlugin {
|
|
|
9
9
|
static get id () { return 'amqplib' }
|
|
10
10
|
static get operation () { return 'command' }
|
|
11
11
|
|
|
12
|
-
start ({ method, fields, message }) {
|
|
12
|
+
start ({ method, fields, message, queue }) {
|
|
13
13
|
if (method !== 'basic.deliver' && method !== 'basic.get') return
|
|
14
14
|
|
|
15
15
|
const childOf = extract(this.tracer, message)
|
|
16
16
|
|
|
17
|
+
const queueName = queue || fields.queue || fields.routingKey
|
|
17
18
|
const span = this.startSpan({
|
|
18
19
|
childOf,
|
|
19
20
|
resource: getResourceName(method, fields),
|
|
20
21
|
type: 'worker',
|
|
21
22
|
meta: {
|
|
22
|
-
'amqp.queue':
|
|
23
|
+
'amqp.queue': queueName,
|
|
23
24
|
'amqp.exchange': fields.exchange,
|
|
24
25
|
'amqp.routingKey': fields.routingKey,
|
|
25
26
|
'amqp.consumerTag': fields.consumerTag,
|
|
26
27
|
'amqp.source': fields.source,
|
|
27
28
|
'amqp.destination': fields.destination
|
|
28
|
-
}
|
|
29
|
+
},
|
|
30
|
+
extractedLinks: childOf?._links
|
|
29
31
|
})
|
|
30
32
|
|
|
31
33
|
if (
|
|
32
34
|
this.config.dsmEnabled && message?.properties?.headers
|
|
33
35
|
) {
|
|
34
36
|
const payloadSize = getAmqpMessageSize({ headers: message.properties.headers, content: message.content })
|
|
35
|
-
const queue = fields.queue ? fields.queue : fields.routingKey
|
|
36
37
|
this.tracer.decodeDataStreamsContext(message.properties.headers)
|
|
37
38
|
this.tracer
|
|
38
|
-
.setCheckpoint(['direction:in', `topic:${
|
|
39
|
+
.setCheckpoint(['direction:in', `topic:${queueName}`, 'type:rabbitmq'], span, payloadSize)
|
|
39
40
|
}
|
|
40
41
|
}
|
|
41
42
|
}
|
|
@@ -93,6 +93,7 @@ class BaseAwsSdkPlugin extends ClientPlugin {
|
|
|
93
93
|
this.responseExtractDSMContext(operation, params, response.data ?? response, span)
|
|
94
94
|
}
|
|
95
95
|
this.addResponseTags(span, response)
|
|
96
|
+
this.addSpanPointers(span, response)
|
|
96
97
|
this.finish(span, response, response.error)
|
|
97
98
|
})
|
|
98
99
|
}
|
|
@@ -101,6 +102,10 @@ class BaseAwsSdkPlugin extends ClientPlugin {
|
|
|
101
102
|
// implemented by subclasses, or not
|
|
102
103
|
}
|
|
103
104
|
|
|
105
|
+
addSpanPointers (span, response) {
|
|
106
|
+
// Optionally implemented by subclasses, for services where we're unable to inject trace context
|
|
107
|
+
}
|
|
108
|
+
|
|
104
109
|
operationFromRequest (request) {
|
|
105
110
|
// can be overriden by subclasses
|
|
106
111
|
return this.operationName({
|
|
@@ -4,6 +4,7 @@ const BaseAwsSdkPlugin = require('../base')
|
|
|
4
4
|
|
|
5
5
|
class EventBridge extends BaseAwsSdkPlugin {
|
|
6
6
|
static get id () { return 'eventbridge' }
|
|
7
|
+
static get isPayloadReporter () { return true }
|
|
7
8
|
|
|
8
9
|
generateTags (params, operation, response) {
|
|
9
10
|
if (!params || !params.source) return {}
|
|
@@ -10,6 +10,7 @@ const { storage } = require('../../../datadog-core')
|
|
|
10
10
|
class Kinesis extends BaseAwsSdkPlugin {
|
|
11
11
|
static get id () { return 'kinesis' }
|
|
12
12
|
static get peerServicePrecursors () { return ['streamname'] }
|
|
13
|
+
static get isPayloadReporter () { return true }
|
|
13
14
|
|
|
14
15
|
constructor (...args) {
|
|
15
16
|
super(...args)
|
|
@@ -41,7 +42,8 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
41
42
|
{},
|
|
42
43
|
this.requestTags.get(request) || {},
|
|
43
44
|
{ 'span.kind': 'server' }
|
|
44
|
-
)
|
|
45
|
+
),
|
|
46
|
+
extractedLinks: responseExtraction.maybeChildOf._links
|
|
45
47
|
}
|
|
46
48
|
span = plugin.tracer.startSpan('aws.response', options)
|
|
47
49
|
this.enter(span, store)
|
|
@@ -112,14 +114,15 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
112
114
|
response.Records.forEach(record => {
|
|
113
115
|
const parsedAttributes = JSON.parse(Buffer.from(record.Data).toString())
|
|
114
116
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
) {
|
|
118
|
-
const payloadSize = getSizeOrZero(record.Data)
|
|
117
|
+
const payloadSize = getSizeOrZero(record.Data)
|
|
118
|
+
if (parsedAttributes?._datadog) {
|
|
119
119
|
this.tracer.decodeDataStreamsContext(parsedAttributes._datadog)
|
|
120
|
-
this.tracer
|
|
121
|
-
.setCheckpoint(['direction:in', `topic:${streamName}`, 'type:kinesis'], span, payloadSize)
|
|
122
120
|
}
|
|
121
|
+
const tags = streamName
|
|
122
|
+
? ['direction:in', `topic:${streamName}`, 'type:kinesis']
|
|
123
|
+
: ['direction:in', 'type:kinesis']
|
|
124
|
+
this.tracer
|
|
125
|
+
.setCheckpoint(tags, span, payloadSize)
|
|
123
126
|
})
|
|
124
127
|
}
|
|
125
128
|
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const BaseAwsSdkPlugin = require('../base')
|
|
4
|
+
const log = require('../../../dd-trace/src/log')
|
|
5
|
+
const { generatePointerHash } = require('../../../dd-trace/src/util')
|
|
6
|
+
const { S3_PTR_KIND, SPAN_POINTER_DIRECTION } = require('../../../dd-trace/src/constants')
|
|
4
7
|
|
|
5
8
|
class S3 extends BaseAwsSdkPlugin {
|
|
6
9
|
static get id () { return 's3' }
|
|
7
10
|
static get peerServicePrecursors () { return ['bucketname'] }
|
|
11
|
+
static get isPayloadReporter () { return true }
|
|
8
12
|
|
|
9
13
|
generateTags (params, operation, response) {
|
|
10
14
|
const tags = {}
|
|
@@ -17,6 +21,37 @@ class S3 extends BaseAwsSdkPlugin {
|
|
|
17
21
|
bucketname: params.Bucket
|
|
18
22
|
})
|
|
19
23
|
}
|
|
24
|
+
|
|
25
|
+
addSpanPointers (span, response) {
|
|
26
|
+
const request = response?.request
|
|
27
|
+
const operationName = request?.operation
|
|
28
|
+
if (!['putObject', 'copyObject', 'completeMultipartUpload'].includes(operationName)) {
|
|
29
|
+
// We don't create span links for other S3 operations.
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// AWS v2: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html
|
|
34
|
+
// AWS v3: https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/
|
|
35
|
+
const bucketName = request?.params?.Bucket
|
|
36
|
+
const objectKey = request?.params?.Key
|
|
37
|
+
let eTag =
|
|
38
|
+
response?.ETag || // v3 PutObject & CompleteMultipartUpload
|
|
39
|
+
response?.CopyObjectResult?.ETag || // v3 CopyObject
|
|
40
|
+
response?.data?.ETag || // v2 PutObject & CompleteMultipartUpload
|
|
41
|
+
response?.data?.CopyObjectResult?.ETag // v2 CopyObject
|
|
42
|
+
|
|
43
|
+
if (!bucketName || !objectKey || !eTag) {
|
|
44
|
+
log.debug('Unable to calculate span pointer hash because of missing parameters.')
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// https://github.com/DataDog/dd-span-pointer-rules/blob/main/AWS/S3/Object/README.md
|
|
49
|
+
if (eTag.startsWith('"') && eTag.endsWith('"')) {
|
|
50
|
+
eTag = eTag.slice(1, -1)
|
|
51
|
+
}
|
|
52
|
+
const pointerHash = generatePointerHash([bucketName, objectKey, eTag])
|
|
53
|
+
span.addSpanPointer(S3_PTR_KIND, SPAN_POINTER_DIRECTION.DOWNSTREAM, pointerHash)
|
|
54
|
+
}
|
|
20
55
|
}
|
|
21
56
|
|
|
22
57
|
module.exports = S3
|
|
@@ -9,6 +9,7 @@ const { DsmPathwayCodec } = require('../../../dd-trace/src/datastreams/pathway')
|
|
|
9
9
|
class Sqs extends BaseAwsSdkPlugin {
|
|
10
10
|
static get id () { return 'sqs' }
|
|
11
11
|
static get peerServicePrecursors () { return ['queuename'] }
|
|
12
|
+
static get isPayloadReporter () { return true }
|
|
12
13
|
|
|
13
14
|
constructor (...args) {
|
|
14
15
|
super(...args)
|
|
@@ -32,7 +33,8 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
32
33
|
{},
|
|
33
34
|
this.requestTags.get(request) || {},
|
|
34
35
|
{ 'span.kind': 'server' }
|
|
35
|
-
)
|
|
36
|
+
),
|
|
37
|
+
extractedLinks: contextExtraction.datadogContext._links
|
|
36
38
|
}
|
|
37
39
|
parsedMessageAttributes = contextExtraction.parsedAttributes
|
|
38
40
|
span = plugin.tracer.startSpan('aws.response', options)
|
|
@@ -41,7 +43,7 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
41
43
|
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
42
44
|
|
|
43
45
|
this.responseExtractDSMContext(
|
|
44
|
-
request.operation, request.params, response, span || null, { parsedMessageAttributes }
|
|
46
|
+
request.operation, request.params, response, span || null, { parsedAttributes: parsedMessageAttributes }
|
|
45
47
|
)
|
|
46
48
|
})
|
|
47
49
|
|
|
@@ -194,16 +196,16 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
194
196
|
parsedAttributes = this.parseDatadogAttributes(message.MessageAttributes._datadog)
|
|
195
197
|
}
|
|
196
198
|
}
|
|
199
|
+
const payloadSize = getHeadersSize({
|
|
200
|
+
Body: message.Body,
|
|
201
|
+
MessageAttributes: message.MessageAttributes
|
|
202
|
+
})
|
|
203
|
+
const queue = params.QueueUrl.split('/').pop()
|
|
197
204
|
if (parsedAttributes) {
|
|
198
|
-
const payloadSize = getHeadersSize({
|
|
199
|
-
Body: message.Body,
|
|
200
|
-
MessageAttributes: message.MessageAttributes
|
|
201
|
-
})
|
|
202
|
-
const queue = params.QueueUrl.split('/').pop()
|
|
203
205
|
this.tracer.decodeDataStreamsContext(parsedAttributes)
|
|
204
|
-
this.tracer
|
|
205
|
-
.setCheckpoint(['direction:in', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
206
206
|
}
|
|
207
|
+
this.tracer
|
|
208
|
+
.setCheckpoint(['direction:in', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
207
209
|
})
|
|
208
210
|
}
|
|
209
211
|
|