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
|
@@ -53,6 +53,8 @@ class TextMapPropagator {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
inject (spanContext, carrier) {
|
|
56
|
+
if (!spanContext || !carrier) return
|
|
57
|
+
|
|
56
58
|
this._injectBaggageItems(spanContext, carrier)
|
|
57
59
|
this._injectDatadog(spanContext, carrier)
|
|
58
60
|
this._injectB3MultipleHeaders(spanContext, carrier)
|
|
@@ -107,10 +109,35 @@ class TextMapPropagator {
|
|
|
107
109
|
}
|
|
108
110
|
}
|
|
109
111
|
|
|
112
|
+
_encodeOtelBaggageKey (key) {
|
|
113
|
+
let encoded = encodeURIComponent(key)
|
|
114
|
+
encoded = encoded.replaceAll('(', '%28')
|
|
115
|
+
encoded = encoded.replaceAll(')', '%29')
|
|
116
|
+
return encoded
|
|
117
|
+
}
|
|
118
|
+
|
|
110
119
|
_injectBaggageItems (spanContext, carrier) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
120
|
+
if (this._config.legacyBaggageEnabled) {
|
|
121
|
+
spanContext._baggageItems && Object.keys(spanContext._baggageItems).forEach(key => {
|
|
122
|
+
carrier[baggagePrefix + key] = String(spanContext._baggageItems[key])
|
|
123
|
+
})
|
|
124
|
+
}
|
|
125
|
+
if (this._hasPropagationStyle('inject', 'baggage')) {
|
|
126
|
+
let baggage = ''
|
|
127
|
+
let itemCounter = 0
|
|
128
|
+
let byteCounter = 0
|
|
129
|
+
|
|
130
|
+
for (const [key, value] of Object.entries(spanContext._baggageItems)) {
|
|
131
|
+
const item = `${this._encodeOtelBaggageKey(String(key).trim())}=${encodeURIComponent(String(value).trim())},`
|
|
132
|
+
itemCounter += 1
|
|
133
|
+
byteCounter += item.length
|
|
134
|
+
if (itemCounter > this._config.baggageMaxItems || byteCounter > this._config.baggageMaxBytes) break
|
|
135
|
+
baggage += item
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
baggage = baggage.slice(0, baggage.length - 1)
|
|
139
|
+
if (baggage) carrier.baggage = baggage
|
|
140
|
+
}
|
|
114
141
|
}
|
|
115
142
|
|
|
116
143
|
_injectTags (spanContext, carrier) {
|
|
@@ -263,45 +290,63 @@ class TextMapPropagator {
|
|
|
263
290
|
}
|
|
264
291
|
|
|
265
292
|
_extractSpanContext (carrier) {
|
|
266
|
-
let
|
|
293
|
+
let context = null
|
|
267
294
|
for (const extractor of this._config.tracePropagationStyle.extract) {
|
|
268
|
-
|
|
269
|
-
if (spanContext !== null) {
|
|
270
|
-
if (this._config.tracePropagationExtractFirst) {
|
|
271
|
-
return spanContext
|
|
272
|
-
}
|
|
273
|
-
if (extractor !== 'tracecontext') {
|
|
274
|
-
continue
|
|
275
|
-
}
|
|
276
|
-
spanContext = this._resolveTraceContextConflicts(
|
|
277
|
-
this._extractTraceparentContext(carrier), spanContext, carrier)
|
|
278
|
-
break
|
|
279
|
-
}
|
|
280
|
-
|
|
295
|
+
let extractedContext = null
|
|
281
296
|
switch (extractor) {
|
|
282
297
|
case 'datadog':
|
|
283
|
-
|
|
298
|
+
extractedContext = this._extractDatadogContext(carrier)
|
|
284
299
|
break
|
|
285
300
|
case 'tracecontext':
|
|
286
|
-
|
|
301
|
+
extractedContext = this._extractTraceparentContext(carrier)
|
|
287
302
|
break
|
|
288
303
|
case 'b3' && this
|
|
289
304
|
._config
|
|
290
305
|
.tracePropagationStyle
|
|
291
306
|
.otelPropagators: // TODO: should match "b3 single header" in next major
|
|
292
307
|
case 'b3 single header': // TODO: delete in major after singular "b3"
|
|
293
|
-
|
|
308
|
+
extractedContext = this._extractB3SingleContext(carrier)
|
|
294
309
|
break
|
|
295
310
|
case 'b3':
|
|
296
311
|
case 'b3multi':
|
|
297
|
-
|
|
312
|
+
extractedContext = this._extractB3MultiContext(carrier)
|
|
298
313
|
break
|
|
299
314
|
default:
|
|
300
|
-
log.warn(`Unknown propagation style: ${extractor}`)
|
|
315
|
+
if (extractor !== 'baggage') log.warn(`Unknown propagation style: ${extractor}`)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (extractedContext === null) { // If the current extractor was invalid, continue to the next extractor
|
|
319
|
+
continue
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (context === null) {
|
|
323
|
+
context = extractedContext
|
|
324
|
+
if (this._config.tracePropagationExtractFirst) {
|
|
325
|
+
return context
|
|
326
|
+
}
|
|
327
|
+
} else {
|
|
328
|
+
// If extractor is tracecontext, add tracecontext specific information to the context
|
|
329
|
+
if (extractor === 'tracecontext') {
|
|
330
|
+
context = this._resolveTraceContextConflicts(
|
|
331
|
+
this._extractTraceparentContext(carrier), context, carrier)
|
|
332
|
+
}
|
|
333
|
+
if (extractedContext._traceId && extractedContext._spanId &&
|
|
334
|
+
extractedContext.toTraceId(true) !== context.toTraceId(true)) {
|
|
335
|
+
const link = {
|
|
336
|
+
context: extractedContext,
|
|
337
|
+
attributes: { reason: 'terminated_context', context_headers: extractor }
|
|
338
|
+
}
|
|
339
|
+
context._links.push(link)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
if (this._config.tracePropagationStyle.extract.includes('baggage') && carrier.baggage) {
|
|
344
|
+
context = context || new DatadogSpanContext()
|
|
345
|
+
this._extractBaggageItems(carrier, context)
|
|
301
346
|
}
|
|
302
347
|
}
|
|
303
348
|
|
|
304
|
-
return
|
|
349
|
+
return context || this._extractSqsdContext(carrier)
|
|
305
350
|
}
|
|
306
351
|
|
|
307
352
|
_extractDatadogContext (carrier) {
|
|
@@ -310,7 +355,7 @@ class TextMapPropagator {
|
|
|
310
355
|
if (!spanContext) return spanContext
|
|
311
356
|
|
|
312
357
|
this._extractOrigin(carrier, spanContext)
|
|
313
|
-
this.
|
|
358
|
+
this._extractLegacyBaggageItems(carrier, spanContext)
|
|
314
359
|
this._extractSamplingPriority(carrier, spanContext)
|
|
315
360
|
this._extractTags(carrier, spanContext)
|
|
316
361
|
|
|
@@ -383,7 +428,7 @@ class TextMapPropagator {
|
|
|
383
428
|
return null
|
|
384
429
|
}
|
|
385
430
|
const matches = headerValue.trim().match(traceparentExpr)
|
|
386
|
-
if (matches
|
|
431
|
+
if (matches?.length) {
|
|
387
432
|
const [version, traceId, spanId, flags, tail] = matches.slice(1)
|
|
388
433
|
const traceparent = { version }
|
|
389
434
|
const tracestate = TraceState.fromString(carrier.tracestate)
|
|
@@ -444,7 +489,7 @@ class TextMapPropagator {
|
|
|
444
489
|
}
|
|
445
490
|
})
|
|
446
491
|
|
|
447
|
-
this.
|
|
492
|
+
this._extractLegacyBaggageItems(carrier, spanContext)
|
|
448
493
|
return spanContext
|
|
449
494
|
}
|
|
450
495
|
return null
|
|
@@ -528,14 +573,43 @@ class TextMapPropagator {
|
|
|
528
573
|
}
|
|
529
574
|
}
|
|
530
575
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
576
|
+
_decodeOtelBaggageKey (key) {
|
|
577
|
+
let decoded = decodeURIComponent(key)
|
|
578
|
+
decoded = decoded.replaceAll('%28', '(')
|
|
579
|
+
decoded = decoded.replaceAll('%29', ')')
|
|
580
|
+
return decoded
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
_extractLegacyBaggageItems (carrier, spanContext) {
|
|
584
|
+
if (this._config.legacyBaggageEnabled) {
|
|
585
|
+
Object.keys(carrier).forEach(key => {
|
|
586
|
+
const match = key.match(baggageExpr)
|
|
587
|
+
|
|
588
|
+
if (match) {
|
|
589
|
+
spanContext._baggageItems[match[1]] = carrier[key]
|
|
590
|
+
}
|
|
591
|
+
})
|
|
592
|
+
}
|
|
593
|
+
}
|
|
534
594
|
|
|
535
|
-
|
|
536
|
-
|
|
595
|
+
_extractBaggageItems (carrier, spanContext) {
|
|
596
|
+
const baggages = carrier.baggage.split(',')
|
|
597
|
+
for (const keyValue of baggages) {
|
|
598
|
+
if (!keyValue.includes('=')) {
|
|
599
|
+
spanContext._baggageItems = {}
|
|
600
|
+
return
|
|
537
601
|
}
|
|
538
|
-
|
|
602
|
+
let [key, value] = keyValue.split('=')
|
|
603
|
+
key = this._decodeOtelBaggageKey(key.trim())
|
|
604
|
+
value = decodeURIComponent(value.trim())
|
|
605
|
+
if (!key || !value) {
|
|
606
|
+
spanContext._baggageItems = {}
|
|
607
|
+
return
|
|
608
|
+
}
|
|
609
|
+
// the current code assumes precedence of ot-baggage- (legacy opentracing baggage) over baggage
|
|
610
|
+
if (key in spanContext._baggageItems) return
|
|
611
|
+
spanContext._baggageItems[key] = value
|
|
612
|
+
}
|
|
539
613
|
}
|
|
540
614
|
|
|
541
615
|
_extractSamplingPriority (carrier, spanContext) {
|
|
@@ -145,6 +145,18 @@ class DatadogSpan {
|
|
|
145
145
|
return this._spanContext._baggageItems[key]
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
+
getAllBaggageItems () {
|
|
149
|
+
return JSON.stringify(this._spanContext._baggageItems)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
removeBaggageItem (key) {
|
|
153
|
+
delete this._spanContext._baggageItems[key]
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
removeAllBaggageItems () {
|
|
157
|
+
this._spanContext._baggageItems = {}
|
|
158
|
+
}
|
|
159
|
+
|
|
148
160
|
setTag (key, value) {
|
|
149
161
|
this._addTags({ [key]: value })
|
|
150
162
|
return this
|
|
@@ -168,6 +180,20 @@ class DatadogSpan {
|
|
|
168
180
|
})
|
|
169
181
|
}
|
|
170
182
|
|
|
183
|
+
addSpanPointer (ptrKind, ptrDir, ptrHash) {
|
|
184
|
+
const zeroContext = new SpanContext({
|
|
185
|
+
traceId: id('0'),
|
|
186
|
+
spanId: id('0')
|
|
187
|
+
})
|
|
188
|
+
const attributes = {
|
|
189
|
+
'ptr.kind': ptrKind,
|
|
190
|
+
'ptr.dir': ptrDir,
|
|
191
|
+
'ptr.hash': ptrHash,
|
|
192
|
+
'link.kind': 'span-pointer'
|
|
193
|
+
}
|
|
194
|
+
this.addLink(zeroContext, attributes)
|
|
195
|
+
}
|
|
196
|
+
|
|
171
197
|
addEvent (name, attributesOrStartTime, startTime) {
|
|
172
198
|
const event = { name }
|
|
173
199
|
if (attributesOrStartTime) {
|
|
@@ -18,6 +18,7 @@ class DatadogSpanContext {
|
|
|
18
18
|
this._tags = props.tags || {}
|
|
19
19
|
this._sampling = props.sampling || {}
|
|
20
20
|
this._spanSampling = undefined
|
|
21
|
+
this._links = props.links || []
|
|
21
22
|
this._baggageItems = props.baggageItems || {}
|
|
22
23
|
this._traceparent = props.traceparent
|
|
23
24
|
this._tracestate = props.tracestate
|
|
@@ -52,8 +52,15 @@ class DatadogTracer {
|
|
|
52
52
|
? getContext(options.childOf)
|
|
53
53
|
: getParent(options.references)
|
|
54
54
|
|
|
55
|
+
// as per spec, allow the setting of service name through options
|
|
55
56
|
const tags = {
|
|
56
|
-
'service.name': this._service
|
|
57
|
+
'service.name': options?.tags?.service ? String(options.tags.service) : this._service
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// As per unified service tagging spec if a span is created with a service name different from the global
|
|
61
|
+
// service name it will not inherit the global version value
|
|
62
|
+
if (options?.tags?.service && options.tags.service !== this._service) {
|
|
63
|
+
options.tags.version = undefined
|
|
57
64
|
}
|
|
58
65
|
|
|
59
66
|
const span = new Span(this, this._processor, this._prioritySampler, {
|
|
@@ -17,14 +17,82 @@
|
|
|
17
17
|
"$.Attributes.Token",
|
|
18
18
|
"$.Endpoints.*.Token",
|
|
19
19
|
"$.PhoneNumber",
|
|
20
|
-
"$.PhoneNumbers",
|
|
21
|
-
"$.phoneNumbers",
|
|
22
20
|
"$.PlatformApplication.*.PlatformCredential",
|
|
23
21
|
"$.PlatformApplication.*.PlatformPrincipal",
|
|
24
|
-
"$.Subscriptions.*.Endpoint"
|
|
22
|
+
"$.Subscriptions.*.Endpoint",
|
|
23
|
+
"$.PhoneNumbers[*].PhoneNumber",
|
|
24
|
+
"$.phoneNumbers[*]"
|
|
25
25
|
],
|
|
26
26
|
"expand": [
|
|
27
27
|
"$.MessageAttributes.*.StringValue"
|
|
28
28
|
]
|
|
29
|
+
},
|
|
30
|
+
"eventbridge": {
|
|
31
|
+
"request": [
|
|
32
|
+
"$.AuthParameters.OAuthParameters.OAuthHttpParameters.HeaderParameters[*].Value",
|
|
33
|
+
"$.AuthParameters.OAuthParameters.OAuthHttpParameters.QueryStringParameters[*].Value",
|
|
34
|
+
"$.AuthParameters.OAuthParameters.OAuthHttpParameters.BodyParameters[*].Value",
|
|
35
|
+
"$.AuthParameters.InvocationHttpParameters.HeaderParameters[*].Value",
|
|
36
|
+
"$.AuthParameters.InvocationHttpParameters.QueryStringParameters[*].Value",
|
|
37
|
+
"$.AuthParameters.InvocationHttpParameters.BodyParameters[*].Value",
|
|
38
|
+
"$.Targets[*].RedshiftDataParameters.Sql",
|
|
39
|
+
"$.Targets[*].RedshiftDataParameters.Sqls",
|
|
40
|
+
"$.Targets[*].AppSyncParameters.GraphQLOperation",
|
|
41
|
+
"$.AuthParameters.BasicAuthParameters.Password",
|
|
42
|
+
"$.AuthParameters.OAuthParameters.ClientParameters.ClientSecret",
|
|
43
|
+
"$.AuthParameters.ApiKeyAuthParameters.ApiKeyValue"
|
|
44
|
+
],
|
|
45
|
+
"response": [
|
|
46
|
+
"$.AuthParameters.OAuthParameters.OAuthHttpParameters.HeaderParameters[*].Value",
|
|
47
|
+
"$.AuthParameters.OAuthParameters.OAuthHttpParameters.QueryStringParameters[*].Value",
|
|
48
|
+
"$.AuthParameters.OAuthParameters.OAuthHttpParameters.BodyParameters[*].Value",
|
|
49
|
+
"$.AuthParameters.InvocationHttpParameters.HeaderParameters[*].Value",
|
|
50
|
+
"$.AuthParameters.InvocationHttpParameters.QueryStringParameters[*].Value",
|
|
51
|
+
"$.AuthParameters.InvocationHttpParameters.BodyParameters[*].Value",
|
|
52
|
+
"$.Targets[*].RedshiftDataParameters.Sql",
|
|
53
|
+
"$.Targets[*].RedshiftDataParameters.Sqls",
|
|
54
|
+
"$.Targets[*].AppSyncParameters.GraphQLOperation"
|
|
55
|
+
],
|
|
56
|
+
"expand": [
|
|
57
|
+
]
|
|
58
|
+
},
|
|
59
|
+
"s3": {
|
|
60
|
+
"request": [
|
|
61
|
+
"$.SSEKMSKeyId",
|
|
62
|
+
"$.SSEKMSEncryptionContext",
|
|
63
|
+
"$.ServerSideEncryptionConfiguration.Rules[*].ApplyServerSideEncryptionByDefault.KMSMasterKeyID",
|
|
64
|
+
"$.InventoryConfiguration.Destination.S3BucketDestination.Encryption.SSEKMS.KeyId",
|
|
65
|
+
"$.SSECustomerKey",
|
|
66
|
+
"$.CopySourceSSECustomerKey",
|
|
67
|
+
"$.RestoreRequest.OutputLocation.S3.Encryption.KMSKeyId"
|
|
68
|
+
|
|
69
|
+
],
|
|
70
|
+
"response": [
|
|
71
|
+
"$.SSEKMSKeyId",
|
|
72
|
+
"$.SSEKMSEncryptionContext",
|
|
73
|
+
"$.ServerSideEncryptionConfiguration.Rules[*].ApplyServerSideEncryptionByDefault.KMSMasterKeyID",
|
|
74
|
+
"$.InventoryConfiguration.Destination.S3BucketDestination.Encryption.SSEKMS.KeyId",
|
|
75
|
+
"$.Credentials.SecretAccessKey",
|
|
76
|
+
"$.Credentials.SessionToken",
|
|
77
|
+
"$.InventoryConfigurationList[*].Destination.S3BucketDestination.Encryption.SSEKMS.KeyId"
|
|
78
|
+
],
|
|
79
|
+
"expand": [
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
"sqs": {
|
|
83
|
+
"request": [
|
|
84
|
+
],
|
|
85
|
+
"response": [
|
|
86
|
+
],
|
|
87
|
+
"expand": [
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
"kinesis": {
|
|
91
|
+
"request": [
|
|
92
|
+
],
|
|
93
|
+
"response": [
|
|
94
|
+
],
|
|
95
|
+
"expand": [
|
|
96
|
+
]
|
|
29
97
|
}
|
|
30
98
|
}
|
|
@@ -7,6 +7,7 @@ const {
|
|
|
7
7
|
PEER_SERVICE_REMAP_KEY
|
|
8
8
|
} = require('../constants')
|
|
9
9
|
const TracingPlugin = require('./tracing')
|
|
10
|
+
const { exitTags } = require('../../../datadog-code-origin')
|
|
10
11
|
|
|
11
12
|
const COMMON_PEER_SVC_SOURCE_TAGS = [
|
|
12
13
|
'net.peer.name',
|
|
@@ -25,6 +26,14 @@ class OutboundPlugin extends TracingPlugin {
|
|
|
25
26
|
})
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
startSpan (...args) {
|
|
30
|
+
const span = super.startSpan(...args)
|
|
31
|
+
if (this._tracerConfig.codeOriginForSpans.enabled) {
|
|
32
|
+
span.addTags(exitTags(this.startSpan))
|
|
33
|
+
}
|
|
34
|
+
return span
|
|
35
|
+
}
|
|
36
|
+
|
|
28
37
|
getPeerService (tags) {
|
|
29
38
|
/**
|
|
30
39
|
* Compute `peer.service` and associated metadata from available tags, based
|
|
@@ -101,9 +101,8 @@ class TracingPlugin extends Plugin {
|
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
startSpan (name, { childOf, kind, meta, metrics, service, resource, type } = {}, enter = true) {
|
|
104
|
+
startSpan (name, { childOf, kind, meta, metrics, service, resource, type, extractedLinks } = {}, enter = true) {
|
|
105
105
|
const store = storage.getStore()
|
|
106
|
-
|
|
107
106
|
if (store && childOf === undefined) {
|
|
108
107
|
childOf = store.span
|
|
109
108
|
}
|
|
@@ -119,7 +118,8 @@ class TracingPlugin extends Plugin {
|
|
|
119
118
|
...meta,
|
|
120
119
|
...metrics
|
|
121
120
|
},
|
|
122
|
-
integrationName: type
|
|
121
|
+
integrationName: type,
|
|
122
|
+
links: extractedLinks
|
|
123
123
|
})
|
|
124
124
|
|
|
125
125
|
analyticsSampler.sample(span, this.config.measured)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
const log = require('../../log')
|
|
2
|
+
const tags = require('../../../../../ext/tags')
|
|
3
|
+
|
|
4
|
+
const RESOURCE_NAME = tags.RESOURCE_NAME
|
|
5
|
+
const HTTP_ROUTE = tags.HTTP_ROUTE
|
|
6
|
+
const SPAN_KIND = tags.SPAN_KIND
|
|
7
|
+
const SPAN_TYPE = tags.SPAN_TYPE
|
|
8
|
+
const HTTP_URL = tags.HTTP_URL
|
|
9
|
+
const HTTP_METHOD = tags.HTTP_METHOD
|
|
10
|
+
|
|
11
|
+
const PROXY_HEADER_SYSTEM = 'x-dd-proxy'
|
|
12
|
+
const PROXY_HEADER_START_TIME_MS = 'x-dd-proxy-request-time-ms'
|
|
13
|
+
const PROXY_HEADER_PATH = 'x-dd-proxy-path'
|
|
14
|
+
const PROXY_HEADER_HTTPMETHOD = 'x-dd-proxy-httpmethod'
|
|
15
|
+
const PROXY_HEADER_DOMAIN = 'x-dd-proxy-domain-name'
|
|
16
|
+
const PROXY_HEADER_STAGE = 'x-dd-proxy-stage'
|
|
17
|
+
|
|
18
|
+
const supportedProxies = {
|
|
19
|
+
'aws-apigateway': {
|
|
20
|
+
spanName: 'aws.apigateway',
|
|
21
|
+
component: 'aws-apigateway'
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function createInferredProxySpan (headers, childOf, tracer, context) {
|
|
26
|
+
if (!headers) {
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!tracer._config?.inferredProxyServicesEnabled) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const proxyContext = extractInferredProxyContext(headers)
|
|
35
|
+
|
|
36
|
+
if (!proxyContext) {
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const proxySpanInfo = supportedProxies[proxyContext.proxySystemName]
|
|
41
|
+
|
|
42
|
+
log.debug(`Successfully extracted inferred span info ${proxyContext} for proxy: ${proxyContext.proxySystemName}`)
|
|
43
|
+
|
|
44
|
+
const span = tracer.startSpan(
|
|
45
|
+
proxySpanInfo.spanName,
|
|
46
|
+
{
|
|
47
|
+
childOf,
|
|
48
|
+
type: 'web',
|
|
49
|
+
startTime: proxyContext.requestTime,
|
|
50
|
+
tags: {
|
|
51
|
+
service: proxyContext.domainName || tracer._config.service,
|
|
52
|
+
component: proxySpanInfo.component,
|
|
53
|
+
[SPAN_KIND]: 'internal',
|
|
54
|
+
[SPAN_TYPE]: 'web',
|
|
55
|
+
[HTTP_METHOD]: proxyContext.method,
|
|
56
|
+
[HTTP_URL]: proxyContext.domainName + proxyContext.path,
|
|
57
|
+
[HTTP_ROUTE]: proxyContext.path,
|
|
58
|
+
stage: proxyContext.stage
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
tracer.scope().activate(span)
|
|
64
|
+
context.inferredProxySpan = span
|
|
65
|
+
childOf = span
|
|
66
|
+
|
|
67
|
+
log.debug('Successfully created inferred proxy span.')
|
|
68
|
+
|
|
69
|
+
setInferredProxySpanTags(span, proxyContext)
|
|
70
|
+
|
|
71
|
+
return childOf
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function setInferredProxySpanTags (span, proxyContext) {
|
|
75
|
+
span.setTag(RESOURCE_NAME, `${proxyContext.method} ${proxyContext.path}`)
|
|
76
|
+
span.setTag('_dd.inferred_span', '1')
|
|
77
|
+
return span
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function extractInferredProxyContext (headers) {
|
|
81
|
+
if (!(PROXY_HEADER_START_TIME_MS in headers)) {
|
|
82
|
+
return null
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!(PROXY_HEADER_SYSTEM in headers && headers[PROXY_HEADER_SYSTEM] in supportedProxies)) {
|
|
86
|
+
log.debug(`Received headers to create inferred proxy span but headers include an unsupported proxy type ${headers}`)
|
|
87
|
+
return null
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
requestTime: headers[PROXY_HEADER_START_TIME_MS]
|
|
92
|
+
? parseInt(headers[PROXY_HEADER_START_TIME_MS], 10)
|
|
93
|
+
: null,
|
|
94
|
+
method: headers[PROXY_HEADER_HTTPMETHOD],
|
|
95
|
+
path: headers[PROXY_HEADER_PATH],
|
|
96
|
+
stage: headers[PROXY_HEADER_STAGE],
|
|
97
|
+
domainName: headers[PROXY_HEADER_DOMAIN],
|
|
98
|
+
proxySystemName: headers[PROXY_HEADER_SYSTEM]
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function finishInferredProxySpan (context) {
|
|
103
|
+
const { req } = context
|
|
104
|
+
|
|
105
|
+
if (!context.inferredProxySpan) return
|
|
106
|
+
|
|
107
|
+
if (context.inferredProxySpanFinished && !req.stream) return
|
|
108
|
+
|
|
109
|
+
// context.config.hooks.request(context.inferredProxySpan, req, res) # TODO: Do we need this??
|
|
110
|
+
|
|
111
|
+
// Only close the inferred span if one was created
|
|
112
|
+
if (context.inferredProxySpan) {
|
|
113
|
+
context.inferredProxySpan.finish()
|
|
114
|
+
context.inferredProxySpanFinished = true
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
module.exports = {
|
|
119
|
+
createInferredProxySpan,
|
|
120
|
+
finishInferredProxySpan
|
|
121
|
+
}
|
|
@@ -10,6 +10,7 @@ const kinds = require('../../../../../ext/kinds')
|
|
|
10
10
|
const urlFilter = require('./urlfilter')
|
|
11
11
|
const { extractIp } = require('./ip_extractor')
|
|
12
12
|
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../constants')
|
|
13
|
+
const { createInferredProxySpan, finishInferredProxySpan } = require('./inferred_proxy')
|
|
13
14
|
|
|
14
15
|
const WEB = types.WEB
|
|
15
16
|
const SERVER = kinds.SERVER
|
|
@@ -97,7 +98,7 @@ const web = {
|
|
|
97
98
|
context.span.context()._name = name
|
|
98
99
|
span = context.span
|
|
99
100
|
} else {
|
|
100
|
-
span = web.startChildSpan(tracer, name, req
|
|
101
|
+
span = web.startChildSpan(tracer, name, req)
|
|
101
102
|
}
|
|
102
103
|
|
|
103
104
|
context.tracer = tracer
|
|
@@ -253,9 +254,20 @@ const web = {
|
|
|
253
254
|
},
|
|
254
255
|
|
|
255
256
|
// Extract the parent span from the headers and start a new span as its child
|
|
256
|
-
startChildSpan (tracer, name,
|
|
257
|
-
const
|
|
258
|
-
const
|
|
257
|
+
startChildSpan (tracer, name, req) {
|
|
258
|
+
const headers = req.headers
|
|
259
|
+
const context = contexts.get(req)
|
|
260
|
+
let childOf = tracer.extract(FORMAT_HTTP_HEADERS, headers)
|
|
261
|
+
|
|
262
|
+
// we may have headers signaling a router proxy span should be created (such as for AWS API Gateway)
|
|
263
|
+
if (tracer._config?.inferredProxyServicesEnabled) {
|
|
264
|
+
const proxySpan = createInferredProxySpan(headers, childOf, tracer, context)
|
|
265
|
+
if (proxySpan) {
|
|
266
|
+
childOf = proxySpan
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const span = tracer.startSpan(name, { childOf, extractedLinks: childOf?.links })
|
|
259
271
|
|
|
260
272
|
return span
|
|
261
273
|
},
|
|
@@ -263,13 +275,21 @@ const web = {
|
|
|
263
275
|
// Validate a request's status code and then add error tags if necessary
|
|
264
276
|
addStatusError (req, statusCode) {
|
|
265
277
|
const context = contexts.get(req)
|
|
266
|
-
const span = context
|
|
267
|
-
const error = context.error
|
|
268
|
-
const hasExistingError = span.context()._tags.error || span.context()._tags[ERROR_MESSAGE]
|
|
278
|
+
const { span, inferredProxySpan, error } = context
|
|
269
279
|
|
|
270
|
-
|
|
280
|
+
const spanHasExistingError = span.context()._tags.error || span.context()._tags[ERROR_MESSAGE]
|
|
281
|
+
const inferredSpanContext = inferredProxySpan?.context()
|
|
282
|
+
const inferredSpanHasExistingError = inferredSpanContext?._tags.error || inferredSpanContext?._tags[ERROR_MESSAGE]
|
|
283
|
+
|
|
284
|
+
const isValidStatusCode = context.config.validateStatus(statusCode)
|
|
285
|
+
|
|
286
|
+
if (!spanHasExistingError && !isValidStatusCode) {
|
|
271
287
|
span.setTag(ERROR, error || true)
|
|
272
288
|
}
|
|
289
|
+
|
|
290
|
+
if (inferredProxySpan && !inferredSpanHasExistingError && !isValidStatusCode) {
|
|
291
|
+
inferredProxySpan.setTag(ERROR, error || true)
|
|
292
|
+
}
|
|
273
293
|
},
|
|
274
294
|
|
|
275
295
|
// Add an error to the request
|
|
@@ -316,6 +336,8 @@ const web = {
|
|
|
316
336
|
web.finishMiddleware(context)
|
|
317
337
|
|
|
318
338
|
web.finishSpan(context)
|
|
339
|
+
|
|
340
|
+
finishInferredProxySpan(context)
|
|
319
341
|
},
|
|
320
342
|
|
|
321
343
|
obfuscateQs (config, url) {
|
|
@@ -426,7 +448,7 @@ function reactivate (req, fn) {
|
|
|
426
448
|
}
|
|
427
449
|
|
|
428
450
|
function addRequestTags (context, spanType) {
|
|
429
|
-
const { req, span, config } = context
|
|
451
|
+
const { req, span, inferredProxySpan, config } = context
|
|
430
452
|
const url = extractURL(req)
|
|
431
453
|
|
|
432
454
|
span.addTags({
|
|
@@ -443,6 +465,7 @@ function addRequestTags (context, spanType) {
|
|
|
443
465
|
|
|
444
466
|
if (clientIp) {
|
|
445
467
|
span.setTag(HTTP_CLIENT_IP, clientIp)
|
|
468
|
+
inferredProxySpan?.setTag(HTTP_CLIENT_IP, clientIp)
|
|
446
469
|
}
|
|
447
470
|
}
|
|
448
471
|
|
|
@@ -450,7 +473,7 @@ function addRequestTags (context, spanType) {
|
|
|
450
473
|
}
|
|
451
474
|
|
|
452
475
|
function addResponseTags (context) {
|
|
453
|
-
const { req, res, paths, span } = context
|
|
476
|
+
const { req, res, paths, span, inferredProxySpan } = context
|
|
454
477
|
|
|
455
478
|
if (paths.length > 0) {
|
|
456
479
|
span.setTag(HTTP_ROUTE, paths.join(''))
|
|
@@ -459,6 +482,9 @@ function addResponseTags (context) {
|
|
|
459
482
|
span.addTags({
|
|
460
483
|
[HTTP_STATUS_CODE]: res.statusCode
|
|
461
484
|
})
|
|
485
|
+
inferredProxySpan?.addTags({
|
|
486
|
+
[HTTP_STATUS_CODE]: res.statusCode
|
|
487
|
+
})
|
|
462
488
|
|
|
463
489
|
web.addStatusError(req, res.statusCode)
|
|
464
490
|
}
|
|
@@ -477,7 +503,7 @@ function addResourceTag (context) {
|
|
|
477
503
|
}
|
|
478
504
|
|
|
479
505
|
function addHeaders (context) {
|
|
480
|
-
const { req, res, config, span } = context
|
|
506
|
+
const { req, res, config, span, inferredProxySpan } = context
|
|
481
507
|
|
|
482
508
|
config.headers.forEach(([key, tag]) => {
|
|
483
509
|
const reqHeader = req.headers[key]
|
|
@@ -485,10 +511,12 @@ function addHeaders (context) {
|
|
|
485
511
|
|
|
486
512
|
if (reqHeader) {
|
|
487
513
|
span.setTag(tag || `${HTTP_REQUEST_HEADERS}.${key}`, reqHeader)
|
|
514
|
+
inferredProxySpan?.setTag(tag || `${HTTP_REQUEST_HEADERS}.${key}`, reqHeader)
|
|
488
515
|
}
|
|
489
516
|
|
|
490
517
|
if (resHeader) {
|
|
491
518
|
span.setTag(tag || `${HTTP_RESPONSE_HEADERS}.${key}`, resHeader)
|
|
519
|
+
inferredProxySpan?.setTag(tag || `${HTTP_RESPONSE_HEADERS}.${key}`, resHeader)
|
|
492
520
|
}
|
|
493
521
|
})
|
|
494
522
|
}
|