dd-trace 4.18.0 → 5.6.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/CONTRIBUTING.md +98 -0
- package/LICENSE-3rdparty.csv +4 -5
- package/MIGRATING.md +15 -0
- package/README.md +20 -140
- package/ci/cypress/after-run.js +1 -0
- package/ci/cypress/after-spec.js +1 -0
- package/ci/init.js +1 -4
- 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 +1523 -1460
- package/package.json +19 -19
- package/packages/datadog-core/src/storage/async_resource.js +1 -1
- package/packages/datadog-core/src/utils/src/get.js +11 -0
- package/packages/datadog-core/src/utils/src/has.js +14 -0
- package/packages/datadog-core/src/utils/src/kebabcase.js +16 -0
- package/packages/datadog-core/src/utils/src/pick.js +11 -0
- package/packages/datadog-core/src/utils/src/set.js +16 -0
- package/packages/datadog-core/src/utils/src/uniq.js +5 -0
- package/packages/datadog-esbuild/index.js +1 -20
- package/packages/datadog-instrumentations/src/aerospike.js +47 -0
- package/packages/datadog-instrumentations/src/amqplib.js +2 -2
- 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/child_process.js +150 -0
- package/packages/datadog-instrumentations/src/couchbase.js +5 -4
- package/packages/datadog-instrumentations/src/crypto.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +163 -46
- package/packages/datadog-instrumentations/src/dns.js +2 -1
- package/packages/datadog-instrumentations/src/express.js +20 -0
- package/packages/datadog-instrumentations/src/graphql.js +18 -4
- package/packages/datadog-instrumentations/src/grpc/client.js +56 -36
- package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -3
- package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
- package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
- package/packages/datadog-instrumentations/src/http/client.js +12 -2
- package/packages/datadog-instrumentations/src/http/server.js +7 -4
- package/packages/datadog-instrumentations/src/http2/client.js +3 -1
- package/packages/datadog-instrumentations/src/http2/server.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +239 -52
- package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
- package/packages/datadog-instrumentations/src/mocha.js +154 -18
- package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
- package/packages/datadog-instrumentations/src/mongoose.js +23 -10
- package/packages/datadog-instrumentations/src/mquery.js +65 -0
- package/packages/datadog-instrumentations/src/net.js +10 -2
- package/packages/datadog-instrumentations/src/next.js +35 -9
- package/packages/datadog-instrumentations/src/playwright.js +110 -16
- 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-amqplib/src/consumer.js +14 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +13 -1
- package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +163 -27
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +46 -8
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +129 -22
- package/packages/datadog-plugin-child_process/src/index.js +91 -0
- package/packages/datadog-plugin-child_process/src/scrub-cmd-params.js +125 -0
- package/packages/datadog-plugin-cucumber/src/index.js +70 -13
- package/packages/datadog-plugin-cypress/src/after-run.js +3 -0
- package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +625 -0
- package/packages/datadog-plugin-cypress/src/plugin.js +6 -454
- package/packages/datadog-plugin-cypress/src/support.js +50 -3
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -0
- package/packages/datadog-plugin-graphql/src/index.js +1 -6
- package/packages/datadog-plugin-graphql/src/resolve.js +28 -18
- package/packages/datadog-plugin-grpc/src/client.js +16 -2
- package/packages/datadog-plugin-grpc/src/util.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +19 -2
- package/packages/datadog-plugin-jest/src/index.js +118 -12
- package/packages/datadog-plugin-jest/src/util.js +38 -16
- package/packages/datadog-plugin-kafkajs/src/consumer.js +76 -6
- package/packages/datadog-plugin-kafkajs/src/producer.js +64 -8
- package/packages/datadog-plugin-mocha/src/index.js +87 -17
- package/packages/datadog-plugin-next/src/index.js +40 -14
- package/packages/datadog-plugin-playwright/src/index.js +71 -8
- package/packages/datadog-plugin-rhea/src/consumer.js +16 -1
- package/packages/datadog-plugin-rhea/src/producer.js +10 -0
- package/packages/dd-trace/src/appsec/activation.js +29 -0
- package/packages/dd-trace/src/appsec/addresses.js +5 -1
- package/packages/dd-trace/src/appsec/api_security_sampler.js +61 -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 +7 -3
- package/packages/dd-trace/src/appsec/graphql.js +146 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/command-injection-analyzer.js +1 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/nosql-injection-mongodb-analyzer.js +22 -17
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +7 -28
- package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +10 -6
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-randomness-analyzer.js +19 -0
- package/packages/dd-trace/src/appsec/iast/context/context-plugin.js +90 -0
- package/packages/dd-trace/src/appsec/iast/context/kafka-ctx-plugin.js +14 -0
- package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +13 -2
- package/packages/dd-trace/src/appsec/iast/index.js +15 -5
- package/packages/dd-trace/src/appsec/iast/overhead-controller.js +1 -1
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +10 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations-taint-object.js +53 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +10 -46
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +13 -9
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugins/kafka.js +47 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +19 -6
- package/packages/dd-trace/src/appsec/iast/taint-tracking/source-types.js +3 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +41 -3
- 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-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +2 -0
- package/packages/dd-trace/src/appsec/index.js +49 -33
- package/packages/dd-trace/src/appsec/recommended.json +1763 -106
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +7 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +42 -16
- package/packages/dd-trace/src/appsec/remote_config/manager.js +9 -8
- package/packages/dd-trace/src/appsec/reporter.js +51 -34
- package/packages/dd-trace/src/appsec/rule_manager.js +11 -8
- 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/{intelligent-test-runner/get-itr-configuration.js → early-flake-detection/get-known-tests.js} +17 -22
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +25 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +2 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +95 -37
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +134 -61
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +37 -4
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +131 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
- package/packages/dd-trace/src/config.js +561 -470
- package/packages/dd-trace/src/data_streams_context.js +1 -1
- package/packages/dd-trace/src/datastreams/pathway.js +58 -1
- package/packages/dd-trace/src/datastreams/processor.js +196 -27
- package/packages/dd-trace/src/datastreams/writer.js +11 -5
- package/packages/dd-trace/src/dogstatsd.js +3 -5
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +44 -6
- package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
- package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
- package/packages/dd-trace/src/exporters/common/request.js +21 -3
- package/packages/dd-trace/src/format.js +30 -2
- 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/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +104 -4
- package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +16 -7
- package/packages/dd-trace/src/opentracing/span.js +48 -4
- package/packages/dd-trace/src/opentracing/span_context.js +15 -6
- package/packages/dd-trace/src/opentracing/tracer.js +4 -3
- package/packages/dd-trace/src/plugin_manager.js +1 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +78 -19
- package/packages/dd-trace/src/plugins/database.js +1 -1
- package/packages/dd-trace/src/plugins/index.js +7 -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 +104 -22
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
- package/packages/dd-trace/src/plugins/util/test.js +60 -10
- 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/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/priority_sampler.js +30 -38
- package/packages/dd-trace/src/profiler.js +5 -3
- package/packages/dd-trace/src/profiling/config.js +77 -24
- package/packages/dd-trace/src/profiling/exporters/agent.js +77 -31
- package/packages/dd-trace/src/profiling/exporters/file.js +2 -1
- package/packages/dd-trace/src/profiling/profiler.js +33 -22
- package/packages/dd-trace/src/profiling/profilers/events.js +270 -0
- package/packages/dd-trace/src/profiling/profilers/shared.js +45 -0
- package/packages/dd-trace/src/profiling/profilers/space.js +18 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +146 -70
- package/packages/dd-trace/src/proxy.js +56 -24
- package/packages/dd-trace/src/ritm.js +1 -1
- package/packages/dd-trace/src/sampling_rule.js +130 -0
- 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 +9 -1
- package/packages/dd-trace/src/span_sampler.js +6 -64
- 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 +182 -53
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/telemetry/send-data.js +65 -7
- package/packages/dd-trace/src/tracer.js +12 -5
- package/register.js +4 -0
- package/scripts/install_plugin_modules.js +11 -3
- package/scripts/st.js +105 -0
- package/packages/datadog-instrumentations/src/child-process.js +0 -30
- package/packages/dd-trace/src/plugins/util/exec.js +0 -13
- package/packages/diagnostics_channel/index.js +0 -3
- package/packages/diagnostics_channel/src/index.js +0 -121
|
@@ -1,10 +1,68 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
const {
|
|
3
|
+
getSizeOrZero
|
|
4
|
+
} = require('../../../dd-trace/src/datastreams/processor')
|
|
5
|
+
const { DsmPathwayCodec } = require('../../../dd-trace/src/datastreams/pathway')
|
|
2
6
|
const log = require('../../../dd-trace/src/log')
|
|
3
7
|
const BaseAwsSdkPlugin = require('../base')
|
|
8
|
+
const { storage } = require('../../../datadog-core')
|
|
9
|
+
|
|
4
10
|
class Kinesis extends BaseAwsSdkPlugin {
|
|
5
11
|
static get id () { return 'kinesis' }
|
|
6
12
|
static get peerServicePrecursors () { return ['streamname'] }
|
|
7
13
|
|
|
14
|
+
constructor (...args) {
|
|
15
|
+
super(...args)
|
|
16
|
+
|
|
17
|
+
// TODO(bengl) Find a way to create the response span tags without this WeakMap being populated
|
|
18
|
+
// in the base class
|
|
19
|
+
this.requestTags = new WeakMap()
|
|
20
|
+
|
|
21
|
+
this.addSub('apm:aws:response:start:kinesis', obj => {
|
|
22
|
+
const { request, response } = obj
|
|
23
|
+
const store = storage.getStore()
|
|
24
|
+
const plugin = this
|
|
25
|
+
|
|
26
|
+
// if we have either of these operations, we want to store the streamName param
|
|
27
|
+
// since it is not typically available during get/put records requests
|
|
28
|
+
if (request.operation === 'getShardIterator' || request.operation === 'listShards') {
|
|
29
|
+
this.storeStreamName(request.params, request.operation, store)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (request.operation === 'getRecords') {
|
|
34
|
+
let span
|
|
35
|
+
const responseExtraction = this.responseExtract(request.params, request.operation, response)
|
|
36
|
+
if (responseExtraction && responseExtraction.maybeChildOf) {
|
|
37
|
+
obj.needsFinish = true
|
|
38
|
+
const options = {
|
|
39
|
+
childOf: responseExtraction.maybeChildOf,
|
|
40
|
+
tags: Object.assign(
|
|
41
|
+
{},
|
|
42
|
+
this.requestTags.get(request) || {},
|
|
43
|
+
{ 'span.kind': 'server' }
|
|
44
|
+
)
|
|
45
|
+
}
|
|
46
|
+
span = plugin.tracer.startSpan('aws.response', options)
|
|
47
|
+
this.enter(span, store)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// get the stream name that should have been stored previously
|
|
51
|
+
const { streamName } = storage.getStore()
|
|
52
|
+
|
|
53
|
+
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
54
|
+
this.responseExtractDSMContext(
|
|
55
|
+
request.operation, response, span || null, streamName
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
this.addSub('apm:aws:response:finish:kinesis', err => {
|
|
61
|
+
const { span } = storage.getStore()
|
|
62
|
+
this.finish(span, null, err)
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
|
|
8
66
|
generateTags (params, operation, response) {
|
|
9
67
|
if (!params || !params.StreamName) return {}
|
|
10
68
|
|
|
@@ -15,6 +73,55 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
15
73
|
}
|
|
16
74
|
}
|
|
17
75
|
|
|
76
|
+
storeStreamName (params, operation, store) {
|
|
77
|
+
if (!operation || (operation !== 'getShardIterator' && operation !== 'listShards')) return
|
|
78
|
+
if (!params || !params.StreamName) return
|
|
79
|
+
|
|
80
|
+
const streamName = params.StreamName
|
|
81
|
+
storage.enterWith({ ...store, streamName })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
responseExtract (params, operation, response) {
|
|
85
|
+
if (operation !== 'getRecords') return
|
|
86
|
+
if (params.Limit && params.Limit !== 1) return
|
|
87
|
+
if (!response || !response.Records || !response.Records[0]) return
|
|
88
|
+
|
|
89
|
+
const record = response.Records[0]
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
const decodedData = JSON.parse(Buffer.from(record.Data).toString())
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
maybeChildOf: this.tracer.extract('text_map', decodedData._datadog),
|
|
96
|
+
parsedAttributes: decodedData._datadog
|
|
97
|
+
}
|
|
98
|
+
} catch (e) {
|
|
99
|
+
log.error(e)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
responseExtractDSMContext (operation, response, span, streamName) {
|
|
104
|
+
if (!this.config.dsmEnabled) return
|
|
105
|
+
if (operation !== 'getRecords') return
|
|
106
|
+
if (!response || !response.Records || !response.Records[0]) return
|
|
107
|
+
|
|
108
|
+
// we only want to set the payloadSize on the span if we have one message, not repeatedly
|
|
109
|
+
span = response.Records.length > 1 ? null : span
|
|
110
|
+
|
|
111
|
+
response.Records.forEach(record => {
|
|
112
|
+
const parsedAttributes = JSON.parse(Buffer.from(record.Data).toString())
|
|
113
|
+
|
|
114
|
+
if (
|
|
115
|
+
parsedAttributes?._datadog && streamName && DsmPathwayCodec.contextExists(parsedAttributes._datadog)
|
|
116
|
+
) {
|
|
117
|
+
const payloadSize = getSizeOrZero(record.Data)
|
|
118
|
+
this.tracer.decodeDataStreamsContext(parsedAttributes._datadog)
|
|
119
|
+
this.tracer
|
|
120
|
+
.setCheckpoint(['direction:in', `topic:${streamName}`, 'type:kinesis'], span, payloadSize)
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
|
|
18
125
|
// AWS-SDK will b64 kinesis payloads
|
|
19
126
|
// or will accept an already b64 encoded payload
|
|
20
127
|
// This method handles both
|
|
@@ -32,40 +139,69 @@ class Kinesis extends BaseAwsSdkPlugin {
|
|
|
32
139
|
}
|
|
33
140
|
|
|
34
141
|
requestInject (span, request) {
|
|
35
|
-
const operation = request
|
|
36
|
-
if (
|
|
37
|
-
|
|
142
|
+
const { operation, params } = request
|
|
143
|
+
if (!params) return
|
|
144
|
+
|
|
145
|
+
let stream
|
|
146
|
+
switch (operation) {
|
|
147
|
+
case 'putRecord':
|
|
148
|
+
stream = params.StreamArn ? params.StreamArn : (params.StreamName ? params.StreamName : '')
|
|
149
|
+
this.injectToMessage(span, params, stream, true)
|
|
150
|
+
break
|
|
151
|
+
case 'putRecords':
|
|
152
|
+
stream = params.StreamArn ? params.StreamArn : (params.StreamName ? params.StreamName : '')
|
|
153
|
+
for (let i = 0; i < params.Records.length; i++) {
|
|
154
|
+
this.injectToMessage(span, params.Records[i], stream, i === 0)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
injectToMessage (span, params, stream, injectTraceContext) {
|
|
160
|
+
if (!params) {
|
|
161
|
+
return
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let parsedData
|
|
165
|
+
if (injectTraceContext || this.config.dsmEnabled) {
|
|
166
|
+
parsedData = this._tryParse(params.Data)
|
|
167
|
+
if (!parsedData) {
|
|
168
|
+
log.error('Unable to parse payload, unable to pass trace context or set DSM checkpoint (if enabled)')
|
|
38
169
|
return
|
|
39
170
|
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const ddInfo = {}
|
|
174
|
+
// for now, we only want to inject to the first message, this may change for batches in the future
|
|
175
|
+
if (injectTraceContext) { this.tracer.inject(span, 'text_map', ddInfo) }
|
|
40
176
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
177
|
+
// set DSM hash if enabled
|
|
178
|
+
if (this.config.dsmEnabled) {
|
|
179
|
+
parsedData._datadog = ddInfo
|
|
180
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, parsedData, stream)
|
|
181
|
+
DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (Object.keys(ddInfo).length !== 0) {
|
|
185
|
+
parsedData._datadog = ddInfo
|
|
186
|
+
const finalData = Buffer.from(JSON.stringify(parsedData))
|
|
187
|
+
const byteSize = finalData.length
|
|
188
|
+
// Kinesis max payload size is 1MB
|
|
189
|
+
// So we must ensure adding DD context won't go over that (512b is an estimate)
|
|
190
|
+
if (byteSize >= 1048576) {
|
|
191
|
+
log.info('Payload size too large to pass context')
|
|
50
192
|
return
|
|
51
193
|
}
|
|
52
|
-
|
|
53
|
-
if (parsedData) {
|
|
54
|
-
parsedData._datadog = traceData
|
|
55
|
-
const finalData = Buffer.from(JSON.stringify(parsedData))
|
|
56
|
-
const byteSize = finalData.length
|
|
57
|
-
// Kinesis max payload size is 1MB
|
|
58
|
-
// So we must ensure adding DD context won't go over that (512b is an estimate)
|
|
59
|
-
if (byteSize >= 1048576) {
|
|
60
|
-
log.info('Payload size too large to pass context')
|
|
61
|
-
return
|
|
62
|
-
}
|
|
63
|
-
injectPath.Data = finalData
|
|
64
|
-
} else {
|
|
65
|
-
log.error('Unable to parse payload, unable to pass trace context')
|
|
66
|
-
}
|
|
194
|
+
params.Data = finalData
|
|
67
195
|
}
|
|
68
196
|
}
|
|
197
|
+
|
|
198
|
+
setDSMCheckpoint (span, parsedData, stream) {
|
|
199
|
+
// get payload size of request data
|
|
200
|
+
const payloadSize = Buffer.from(JSON.stringify(parsedData)).byteLength
|
|
201
|
+
const dataStreamsContext = this.tracer
|
|
202
|
+
.setCheckpoint(['direction:out', `topic:${stream}`, 'type:kinesis'], span, payloadSize)
|
|
203
|
+
return dataStreamsContext
|
|
204
|
+
}
|
|
69
205
|
}
|
|
70
206
|
|
|
71
207
|
module.exports = Kinesis
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
const { getHeadersSize } = require('../../../dd-trace/src/datastreams/processor')
|
|
3
|
+
const { DsmPathwayCodec } = require('../../../dd-trace/src/datastreams/pathway')
|
|
2
4
|
const log = require('../../../dd-trace/src/log')
|
|
3
5
|
const BaseAwsSdkPlugin = require('../base')
|
|
4
6
|
|
|
@@ -11,6 +13,7 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
11
13
|
|
|
12
14
|
if (!params.TopicArn && !(response.data && response.data.TopicArn)) return {}
|
|
13
15
|
const TopicArn = params.TopicArn || response.data.TopicArn
|
|
16
|
+
|
|
14
17
|
// Split the ARN into its parts
|
|
15
18
|
// ex.'arn:aws:sns:us-east-1:123456789012:my-topic'
|
|
16
19
|
const arnParts = TopicArn.split(':')
|
|
@@ -52,17 +55,17 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
52
55
|
|
|
53
56
|
switch (operation) {
|
|
54
57
|
case 'publish':
|
|
55
|
-
this.
|
|
58
|
+
this.injectToMessage(span, params, params.TopicArn, true)
|
|
56
59
|
break
|
|
57
60
|
case 'publishBatch':
|
|
58
|
-
|
|
59
|
-
this.
|
|
61
|
+
for (let i = 0; i < params.PublishBatchRequestEntries.length; i++) {
|
|
62
|
+
this.injectToMessage(span, params.PublishBatchRequestEntries[i], params.TopicArn, i === 0)
|
|
60
63
|
}
|
|
61
64
|
break
|
|
62
65
|
}
|
|
63
66
|
}
|
|
64
67
|
|
|
65
|
-
|
|
68
|
+
injectToMessage (span, params, topicArn, injectTraceContext) {
|
|
66
69
|
if (!params.MessageAttributes) {
|
|
67
70
|
params.MessageAttributes = {}
|
|
68
71
|
}
|
|
@@ -70,11 +73,46 @@ class Sns extends BaseAwsSdkPlugin {
|
|
|
70
73
|
log.info('Message attributes full, skipping trace context injection')
|
|
71
74
|
return
|
|
72
75
|
}
|
|
76
|
+
|
|
73
77
|
const ddInfo = {}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
+
// for now, we only want to inject to the first message, this may change for batches in the future
|
|
79
|
+
if (injectTraceContext) {
|
|
80
|
+
this.tracer.inject(span, 'text_map', ddInfo)
|
|
81
|
+
// add ddInfo before checking DSM so we can include DD attributes in payload size
|
|
82
|
+
params.MessageAttributes._datadog = {
|
|
83
|
+
DataType: 'Binary',
|
|
84
|
+
BinaryValue: ddInfo
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (this.config.dsmEnabled) {
|
|
89
|
+
if (!params.MessageAttributes._datadog) {
|
|
90
|
+
params.MessageAttributes._datadog = {
|
|
91
|
+
DataType: 'Binary',
|
|
92
|
+
BinaryValue: ddInfo
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, params, topicArn)
|
|
97
|
+
DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (Object.keys(ddInfo).length !== 0) {
|
|
101
|
+
// BINARY types are automatically base64 encoded
|
|
102
|
+
params.MessageAttributes._datadog.BinaryValue = Buffer.from(JSON.stringify(ddInfo))
|
|
103
|
+
} else if (params.MessageAttributes._datadog) {
|
|
104
|
+
// let's avoid adding any additional information to payload if we failed to inject
|
|
105
|
+
delete params.MessageAttributes._datadog
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
setDSMCheckpoint (span, params, topicArn) {
|
|
110
|
+
// only set a checkpoint if publishing to a topic
|
|
111
|
+
if (topicArn) {
|
|
112
|
+
const payloadSize = getHeadersSize(params)
|
|
113
|
+
const dataStreamsContext = this.tracer
|
|
114
|
+
.setCheckpoint(['direction:out', `topic:${topicArn}`, 'type:sns'], span, payloadSize)
|
|
115
|
+
return dataStreamsContext
|
|
78
116
|
}
|
|
79
117
|
}
|
|
80
118
|
}
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
const log = require('../../../dd-trace/src/log')
|
|
4
4
|
const BaseAwsSdkPlugin = require('../base')
|
|
5
5
|
const { storage } = require('../../../datadog-core')
|
|
6
|
+
const { getHeadersSize } = require('../../../dd-trace/src/datastreams/processor')
|
|
7
|
+
const { DsmPathwayCodec } = require('../../../dd-trace/src/datastreams/pathway')
|
|
6
8
|
|
|
7
9
|
class Sqs extends BaseAwsSdkPlugin {
|
|
8
10
|
static get id () { return 'sqs' }
|
|
@@ -19,20 +21,27 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
19
21
|
const { request, response } = obj
|
|
20
22
|
const store = storage.getStore()
|
|
21
23
|
const plugin = this
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
+
const contextExtraction = this.responseExtract(request.params, request.operation, response)
|
|
25
|
+
let span
|
|
26
|
+
let parsedMessageAttributes
|
|
27
|
+
if (contextExtraction && contextExtraction.datadogContext) {
|
|
24
28
|
obj.needsFinish = true
|
|
25
29
|
const options = {
|
|
26
|
-
childOf:
|
|
30
|
+
childOf: contextExtraction.datadogContext,
|
|
27
31
|
tags: Object.assign(
|
|
28
32
|
{},
|
|
29
33
|
this.requestTags.get(request) || {},
|
|
30
34
|
{ 'span.kind': 'server' }
|
|
31
35
|
)
|
|
32
36
|
}
|
|
33
|
-
|
|
37
|
+
parsedMessageAttributes = contextExtraction.parsedAttributes
|
|
38
|
+
span = plugin.tracer.startSpan('aws.response', options)
|
|
34
39
|
this.enter(span, store)
|
|
35
40
|
}
|
|
41
|
+
// extract DSM context after as we might not have a parent-child but may have a DSM context
|
|
42
|
+
this.responseExtractDSMContext(
|
|
43
|
+
request.operation, request.params, response, span || null, parsedMessageAttributes || null
|
|
44
|
+
)
|
|
36
45
|
})
|
|
37
46
|
|
|
38
47
|
this.addSub('apm:aws:response:finish:sqs', err => {
|
|
@@ -133,38 +142,136 @@ class Sqs extends BaseAwsSdkPlugin {
|
|
|
133
142
|
|
|
134
143
|
const datadogAttribute = message.MessageAttributes._datadog
|
|
135
144
|
|
|
145
|
+
const parsedAttributes = this.parseDatadogAttributes(datadogAttribute)
|
|
146
|
+
if (parsedAttributes) {
|
|
147
|
+
return {
|
|
148
|
+
datadogContext: this.tracer.extract('text_map', parsedAttributes),
|
|
149
|
+
parsedAttributes: parsedAttributes
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
parseDatadogAttributes (attributes) {
|
|
136
155
|
try {
|
|
137
|
-
if (
|
|
138
|
-
const textMap =
|
|
139
|
-
return
|
|
140
|
-
} else if (
|
|
141
|
-
const buffer = Buffer.from(
|
|
142
|
-
return
|
|
156
|
+
if (attributes.StringValue) {
|
|
157
|
+
const textMap = attributes.StringValue
|
|
158
|
+
return JSON.parse(textMap)
|
|
159
|
+
} else if (attributes.Type === 'Binary') {
|
|
160
|
+
const buffer = Buffer.from(attributes.Value, 'base64')
|
|
161
|
+
return JSON.parse(buffer)
|
|
143
162
|
}
|
|
144
163
|
} catch (e) {
|
|
145
164
|
log.error(e)
|
|
146
165
|
}
|
|
147
166
|
}
|
|
148
167
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (operation
|
|
152
|
-
|
|
153
|
-
|
|
168
|
+
responseExtractDSMContext (operation, params, response, span, parsedAttributes) {
|
|
169
|
+
if (!this.config.dsmEnabled) return
|
|
170
|
+
if (operation !== 'receiveMessage') return
|
|
171
|
+
if (!response || !response.Messages || !response.Messages[0]) return
|
|
172
|
+
|
|
173
|
+
// we only want to set the payloadSize on the span if we have one message
|
|
174
|
+
span = response.Messages.length > 1 ? null : span
|
|
175
|
+
|
|
176
|
+
response.Messages.forEach(message => {
|
|
177
|
+
// we may have already parsed the message attributes when extracting trace context
|
|
178
|
+
if (!parsedAttributes) {
|
|
179
|
+
if (message.Body) {
|
|
180
|
+
try {
|
|
181
|
+
const body = JSON.parse(message.Body)
|
|
182
|
+
|
|
183
|
+
// SNS to SQS
|
|
184
|
+
if (body.Type === 'Notification') {
|
|
185
|
+
message = body
|
|
186
|
+
}
|
|
187
|
+
} catch (e) {
|
|
188
|
+
// SQS to SQS
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (message.MessageAttributes && message.MessageAttributes._datadog) {
|
|
192
|
+
parsedAttributes = this.parseDatadogAttributes(message.MessageAttributes._datadog)
|
|
193
|
+
}
|
|
154
194
|
}
|
|
155
|
-
if (
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
195
|
+
if (parsedAttributes && DsmPathwayCodec.contextExists(parsedAttributes)) {
|
|
196
|
+
const payloadSize = getHeadersSize({
|
|
197
|
+
Body: message.Body,
|
|
198
|
+
MessageAttributes: message.MessageAttributes
|
|
199
|
+
})
|
|
200
|
+
const queue = params.QueueUrl.split('/').pop()
|
|
201
|
+
this.tracer.decodeDataStreamsContext(parsedAttributes)
|
|
202
|
+
this.tracer
|
|
203
|
+
.setCheckpoint(['direction:in', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
160
204
|
}
|
|
161
|
-
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
requestInject (span, request) {
|
|
209
|
+
const { operation, params } = request
|
|
210
|
+
|
|
211
|
+
if (!params) return
|
|
212
|
+
|
|
213
|
+
switch (operation) {
|
|
214
|
+
case 'sendMessage':
|
|
215
|
+
this.injectToMessage(span, params, params.QueueUrl, true)
|
|
216
|
+
break
|
|
217
|
+
case 'sendMessageBatch':
|
|
218
|
+
for (let i = 0; i < params.Entries.length; i++) {
|
|
219
|
+
this.injectToMessage(span, params.Entries[i], params.QueueUrl, i === 0)
|
|
220
|
+
}
|
|
221
|
+
break
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
injectToMessage (span, params, queueUrl, injectTraceContext) {
|
|
226
|
+
if (!params) {
|
|
227
|
+
params = {}
|
|
228
|
+
}
|
|
229
|
+
if (!params.MessageAttributes) {
|
|
230
|
+
params.MessageAttributes = {}
|
|
231
|
+
} else if (Object.keys(params.MessageAttributes).length >= 10) { // SQS quota
|
|
232
|
+
// TODO: add test when the test suite is fixed
|
|
233
|
+
return
|
|
234
|
+
}
|
|
235
|
+
const ddInfo = {}
|
|
236
|
+
// for now, we only want to inject to the first message, this may change for batches in the future
|
|
237
|
+
if (injectTraceContext) {
|
|
162
238
|
this.tracer.inject(span, 'text_map', ddInfo)
|
|
163
|
-
|
|
239
|
+
params.MessageAttributes._datadog = {
|
|
164
240
|
DataType: 'String',
|
|
165
241
|
StringValue: JSON.stringify(ddInfo)
|
|
166
242
|
}
|
|
167
243
|
}
|
|
244
|
+
|
|
245
|
+
if (this.config.dsmEnabled) {
|
|
246
|
+
if (!params.MessageAttributes._datadog) {
|
|
247
|
+
params.MessageAttributes._datadog = {
|
|
248
|
+
DataType: 'String',
|
|
249
|
+
StringValue: JSON.stringify(ddInfo)
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const dataStreamsContext = this.setDSMCheckpoint(span, params, queueUrl)
|
|
254
|
+
if (dataStreamsContext) {
|
|
255
|
+
DsmPathwayCodec.encode(dataStreamsContext, ddInfo)
|
|
256
|
+
params.MessageAttributes._datadog.StringValue = JSON.stringify(ddInfo)
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (params.MessageAttributes._datadog && Object.keys(ddInfo).length === 0) {
|
|
261
|
+
// let's avoid adding any additional information to payload if we failed to inject
|
|
262
|
+
delete params.MessageAttributes._datadog
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
setDSMCheckpoint (span, params, queueUrl) {
|
|
267
|
+
const payloadSize = getHeadersSize({
|
|
268
|
+
Body: params.MessageBody,
|
|
269
|
+
MessageAttributes: params.MessageAttributes
|
|
270
|
+
})
|
|
271
|
+
const queue = queueUrl.split('/').pop()
|
|
272
|
+
const dataStreamsContext = this.tracer
|
|
273
|
+
.setCheckpoint(['direction:out', `topic:${queue}`, 'type:sqs'], span, payloadSize)
|
|
274
|
+
return dataStreamsContext
|
|
168
275
|
}
|
|
169
276
|
}
|
|
170
277
|
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
+
const scrubChildProcessCmd = require('./scrub-cmd-params')
|
|
5
|
+
|
|
6
|
+
const MAX_ARG_SIZE = 4096 // 4kB
|
|
7
|
+
|
|
8
|
+
function truncateCommand (cmdFields) {
|
|
9
|
+
let size = cmdFields[0].length
|
|
10
|
+
let truncated = false
|
|
11
|
+
for (let i = 1; i < cmdFields.length; i++) {
|
|
12
|
+
if (size >= MAX_ARG_SIZE) {
|
|
13
|
+
truncated = true
|
|
14
|
+
cmdFields[i] = ''
|
|
15
|
+
continue
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const argLen = cmdFields[i].length
|
|
19
|
+
if (size < MAX_ARG_SIZE && size + argLen > MAX_ARG_SIZE) {
|
|
20
|
+
cmdFields[i] = cmdFields[i].substring(0, 2)
|
|
21
|
+
truncated = true
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
size += argLen
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return truncated
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class ChildProcessPlugin extends TracingPlugin {
|
|
31
|
+
static get id () { return 'child_process' }
|
|
32
|
+
static get prefix () { return 'tracing:datadog:child_process:execution' }
|
|
33
|
+
|
|
34
|
+
get tracer () {
|
|
35
|
+
return this._tracer
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
start ({ command, shell }) {
|
|
39
|
+
if (typeof command !== 'string') {
|
|
40
|
+
return
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const cmdFields = scrubChildProcessCmd(command)
|
|
44
|
+
const truncated = truncateCommand(cmdFields)
|
|
45
|
+
const property = (shell === true) ? 'cmd.shell' : 'cmd.exec'
|
|
46
|
+
|
|
47
|
+
const meta = {
|
|
48
|
+
'component': 'subprocess',
|
|
49
|
+
[property]: (shell === true) ? cmdFields.join(' ') : JSON.stringify(cmdFields)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (truncated) {
|
|
53
|
+
meta['cmd.truncated'] = `${truncated}`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.startSpan('command_execution', {
|
|
57
|
+
service: this.config.service,
|
|
58
|
+
resource: (shell === true) ? 'sh' : cmdFields[0],
|
|
59
|
+
type: 'system',
|
|
60
|
+
meta
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
end ({ result, error }) {
|
|
65
|
+
let exitCode
|
|
66
|
+
|
|
67
|
+
if (result !== undefined) {
|
|
68
|
+
exitCode = result?.status || 0
|
|
69
|
+
} else if (error !== undefined) {
|
|
70
|
+
exitCode = error?.status || error?.code || 0
|
|
71
|
+
} else {
|
|
72
|
+
// TracingChannels call start, end synchronously. Later when the promise is resolved then asyncStart asyncEnd.
|
|
73
|
+
// Therefore in the case of calling end with neither result nor error means that they will come in the asyncEnd.
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.activeSpan?.setTag('cmd.exit_code', `${exitCode}`)
|
|
78
|
+
this.activeSpan?.finish()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
error (error) {
|
|
82
|
+
this.addError(error)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
asyncEnd ({ result }) {
|
|
86
|
+
this.activeSpan?.setTag('cmd.exit_code', `${result}`)
|
|
87
|
+
this.activeSpan?.finish()
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = ChildProcessPlugin
|