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
|
@@ -7,6 +7,8 @@ const { Readable } = require('stream')
|
|
|
7
7
|
const http = require('http')
|
|
8
8
|
const https = require('https')
|
|
9
9
|
const { parse: urlParse } = require('url')
|
|
10
|
+
const zlib = require('zlib')
|
|
11
|
+
|
|
10
12
|
const docker = require('./docker')
|
|
11
13
|
const { httpAgent, httpsAgent } = require('./agents')
|
|
12
14
|
const { storage } = require('../../../../datadog-core')
|
|
@@ -93,16 +95,31 @@ function request (data, options, callback) {
|
|
|
93
95
|
options.agent = isSecure ? httpsAgent : httpAgent
|
|
94
96
|
|
|
95
97
|
const onResponse = res => {
|
|
96
|
-
|
|
98
|
+
const chunks = []
|
|
97
99
|
|
|
98
100
|
res.setTimeout(timeout)
|
|
99
101
|
|
|
100
|
-
res.on('data', chunk => {
|
|
102
|
+
res.on('data', chunk => {
|
|
103
|
+
chunks.push(chunk)
|
|
104
|
+
})
|
|
101
105
|
res.on('end', () => {
|
|
102
106
|
activeRequests--
|
|
107
|
+
const buffer = Buffer.concat(chunks)
|
|
103
108
|
|
|
104
109
|
if (res.statusCode >= 200 && res.statusCode <= 299) {
|
|
105
|
-
|
|
110
|
+
const isGzip = res.headers['content-encoding'] === 'gzip'
|
|
111
|
+
if (isGzip) {
|
|
112
|
+
zlib.gunzip(buffer, (err, result) => {
|
|
113
|
+
if (err) {
|
|
114
|
+
log.error(`Could not gunzip response: ${err.message}`)
|
|
115
|
+
callback(null, '', res.statusCode)
|
|
116
|
+
} else {
|
|
117
|
+
callback(null, result.toString(), res.statusCode)
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
} else {
|
|
121
|
+
callback(null, buffer.toString(), res.statusCode)
|
|
122
|
+
}
|
|
106
123
|
} else {
|
|
107
124
|
let errorMessage = ''
|
|
108
125
|
try {
|
|
@@ -114,6 +131,7 @@ function request (data, options, callback) {
|
|
|
114
131
|
} catch (e) {
|
|
115
132
|
// ignore error
|
|
116
133
|
}
|
|
134
|
+
const responseData = buffer.toString()
|
|
117
135
|
if (responseData) {
|
|
118
136
|
errorMessage += ` Response from the endpoint: "${responseData}"`
|
|
119
137
|
}
|
|
@@ -14,7 +14,7 @@ const SPAN_SAMPLING_MECHANISM = constants.SPAN_SAMPLING_MECHANISM
|
|
|
14
14
|
const SPAN_SAMPLING_RULE_RATE = constants.SPAN_SAMPLING_RULE_RATE
|
|
15
15
|
const SPAN_SAMPLING_MAX_PER_SECOND = constants.SPAN_SAMPLING_MAX_PER_SECOND
|
|
16
16
|
const SAMPLING_MECHANISM_SPAN = constants.SAMPLING_MECHANISM_SPAN
|
|
17
|
-
const { MEASURED, BASE_SERVICE } = tags
|
|
17
|
+
const { MEASURED, BASE_SERVICE, ANALYTICS } = tags
|
|
18
18
|
const ORIGIN_KEY = constants.ORIGIN_KEY
|
|
19
19
|
const HOSTNAME_KEY = constants.HOSTNAME_KEY
|
|
20
20
|
const TOP_LEVEL_KEY = constants.TOP_LEVEL_KEY
|
|
@@ -24,6 +24,7 @@ const ERROR_STACK = constants.ERROR_STACK
|
|
|
24
24
|
const ERROR_TYPE = constants.ERROR_TYPE
|
|
25
25
|
|
|
26
26
|
const map = {
|
|
27
|
+
'operation.name': 'name',
|
|
27
28
|
'service.name': 'service',
|
|
28
29
|
'span.type': 'type',
|
|
29
30
|
'resource.name': 'resource'
|
|
@@ -32,6 +33,7 @@ const map = {
|
|
|
32
33
|
function format (span) {
|
|
33
34
|
const formatted = formatSpan(span)
|
|
34
35
|
|
|
36
|
+
extractSpanLinks(formatted, span)
|
|
35
37
|
extractRootTags(formatted, span)
|
|
36
38
|
extractChunkTags(formatted, span)
|
|
37
39
|
extractTags(formatted, span)
|
|
@@ -52,7 +54,8 @@ function formatSpan (span) {
|
|
|
52
54
|
meta: {},
|
|
53
55
|
metrics: {},
|
|
54
56
|
start: Math.round(span._startTime * 1e6),
|
|
55
|
-
duration: Math.round(span._duration * 1e6)
|
|
57
|
+
duration: Math.round(span._duration * 1e6),
|
|
58
|
+
links: []
|
|
56
59
|
}
|
|
57
60
|
}
|
|
58
61
|
|
|
@@ -63,6 +66,28 @@ function setSingleSpanIngestionTags (span, options) {
|
|
|
63
66
|
addTag({}, span.metrics, SPAN_SAMPLING_MAX_PER_SECOND, options.maxPerSecond)
|
|
64
67
|
}
|
|
65
68
|
|
|
69
|
+
function extractSpanLinks (trace, span) {
|
|
70
|
+
const links = []
|
|
71
|
+
if (span._links) {
|
|
72
|
+
for (const link of span._links) {
|
|
73
|
+
const { context, attributes } = link
|
|
74
|
+
const formattedLink = {}
|
|
75
|
+
|
|
76
|
+
formattedLink.trace_id = context.toTraceId(true)
|
|
77
|
+
formattedLink.span_id = context.toSpanId(true)
|
|
78
|
+
|
|
79
|
+
if (attributes && Object.keys(attributes).length > 0) {
|
|
80
|
+
formattedLink.attributes = attributes
|
|
81
|
+
}
|
|
82
|
+
if (context?._sampling?.priority >= 0) formattedLink.flags = context._sampling.priority > 0 ? 1 : 0
|
|
83
|
+
if (context?._tracestate) formattedLink.tracestate = context._tracestate.toString()
|
|
84
|
+
|
|
85
|
+
links.push(formattedLink)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (links.length > 0) { trace.meta['_dd.span_links'] = JSON.stringify(links) }
|
|
89
|
+
}
|
|
90
|
+
|
|
66
91
|
function extractTags (trace, span) {
|
|
67
92
|
const context = span.context()
|
|
68
93
|
const origin = context._trace.origin
|
|
@@ -92,6 +117,9 @@ function extractTags (trace, span) {
|
|
|
92
117
|
case 'http.status_code':
|
|
93
118
|
addTag(trace.meta, {}, tag, tags[tag] && String(tags[tag]))
|
|
94
119
|
break
|
|
120
|
+
case 'analytics.event':
|
|
121
|
+
addTag({}, trace.metrics, ANALYTICS, tags[tag] === undefined || tags[tag] ? 1 : 0)
|
|
122
|
+
break
|
|
95
123
|
case HOSTNAME_KEY:
|
|
96
124
|
case MEASURED:
|
|
97
125
|
addTag({}, trace.metrics, tag, tags[tag] === undefined || tags[tag] ? 1 : 0)
|
|
@@ -42,6 +42,18 @@ class Identifier {
|
|
|
42
42
|
toJSON () {
|
|
43
43
|
return this.toString()
|
|
44
44
|
}
|
|
45
|
+
|
|
46
|
+
equals (other) {
|
|
47
|
+
const length = this._buffer.length
|
|
48
|
+
const otherLength = other._buffer.length
|
|
49
|
+
|
|
50
|
+
// Only compare the bytes available in both IDs.
|
|
51
|
+
for (let i = length, j = otherLength; i >= 0 && j >= 0; i--, j--) {
|
|
52
|
+
if (this._buffer[i] !== other._buffer[j]) return false
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
// Create a buffer, using an optional hexadecimal value if provided.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
const semver = require('semver')
|
|
4
4
|
const logger = require('./log')
|
|
5
5
|
const { addHook } = require('import-in-the-middle')
|
|
6
|
-
const dc = require('
|
|
6
|
+
const dc = require('dc-polyfill')
|
|
7
7
|
|
|
8
8
|
if (semver.satisfies(process.versions.node, '>=14.13.1')) {
|
|
9
9
|
const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
|
|
@@ -11,6 +11,7 @@ const tracer = require('../../')
|
|
|
11
11
|
const DatadogSpan = require('../opentracing/span')
|
|
12
12
|
const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../constants')
|
|
13
13
|
const { SERVICE_NAME, RESOURCE_NAME } = require('../../../../ext/tags')
|
|
14
|
+
const kinds = require('../../../../ext/kinds')
|
|
14
15
|
|
|
15
16
|
const SpanContext = require('./span_context')
|
|
16
17
|
|
|
@@ -19,6 +20,93 @@ function hrTimeToMilliseconds (time) {
|
|
|
19
20
|
return time[0] * 1e3 + time[1] / 1e6
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
const spanKindNames = {
|
|
24
|
+
[api.SpanKind.INTERNAL]: kinds.INTERNAL,
|
|
25
|
+
[api.SpanKind.SERVER]: kinds.SERVER,
|
|
26
|
+
[api.SpanKind.CLIENT]: kinds.CLIENT,
|
|
27
|
+
[api.SpanKind.PRODUCER]: kinds.PRODUCER,
|
|
28
|
+
[api.SpanKind.CONSUMER]: kinds.CONSUMER
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Several of these attributes are not yet supported by the Node.js OTel API.
|
|
33
|
+
* We check for old equivalents where we can, but not all had equivalents.
|
|
34
|
+
*/
|
|
35
|
+
function spanNameMapper (spanName, kind, attributes) {
|
|
36
|
+
if (spanName) return spanName
|
|
37
|
+
|
|
38
|
+
const opName = attributes['operation.name']
|
|
39
|
+
if (opName) return opName
|
|
40
|
+
|
|
41
|
+
const { INTERNAL, SERVER, CLIENT } = api.SpanKind
|
|
42
|
+
|
|
43
|
+
// HTTP server and client requests
|
|
44
|
+
// TODO: Drop http.method when http.request.method is supported.
|
|
45
|
+
for (const key of ['http.method', 'http.request.method']) {
|
|
46
|
+
if (key in attributes) {
|
|
47
|
+
if (kind === SERVER) {
|
|
48
|
+
return 'http.server.request'
|
|
49
|
+
}
|
|
50
|
+
if (kind === CLIENT) {
|
|
51
|
+
return 'http.client.request'
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Databases
|
|
57
|
+
const dbSystem = attributes['db.system']
|
|
58
|
+
if (dbSystem && kind === CLIENT) {
|
|
59
|
+
return `${dbSystem}.query`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Messaging
|
|
63
|
+
const msgSys = attributes['messaging.system']
|
|
64
|
+
const msgOp = attributes['messaging.operation']
|
|
65
|
+
if (msgSys && msgOp && kind !== INTERNAL) {
|
|
66
|
+
return `${msgSys}.${msgOp}`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// RPC (and AWS)
|
|
70
|
+
const rpcSystem = attributes['rpc.system']
|
|
71
|
+
if (rpcSystem) {
|
|
72
|
+
if (kind === CLIENT) {
|
|
73
|
+
return rpcSystem === 'aws-api'
|
|
74
|
+
? `aws.${attributes['rpc.service'] || 'client'}.request`
|
|
75
|
+
: `${rpcSystem}.client.request`
|
|
76
|
+
}
|
|
77
|
+
if (kind === SERVER) {
|
|
78
|
+
return `${rpcSystem}.server.request`
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// FaaS
|
|
83
|
+
const faasProvider = attributes['faas.invoked_provider']
|
|
84
|
+
const faasName = attributes['faas.invoked_name']
|
|
85
|
+
const faasTrigger = attributes['faas.trigger']
|
|
86
|
+
if (kind === CLIENT && faasProvider && faasName) {
|
|
87
|
+
return `${faasProvider}.${faasName}.invoke`
|
|
88
|
+
}
|
|
89
|
+
if (kind === SERVER && faasTrigger) {
|
|
90
|
+
return `${faasTrigger}.invoke`
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// GraphQL
|
|
94
|
+
// NOTE: Not part of Semantic Convention spec yet, but is used in the GraphQL
|
|
95
|
+
// integration.
|
|
96
|
+
const isGraphQL = 'graphql.operation.type' in attributes
|
|
97
|
+
if (isGraphQL) return 'graphql.server.request'
|
|
98
|
+
|
|
99
|
+
// Network
|
|
100
|
+
// TODO: Doesn't exist yet. No equivalent.
|
|
101
|
+
const protocol = attributes['network.protocol.name']
|
|
102
|
+
const protocolPrefix = protocol ? `${protocol}.` : ''
|
|
103
|
+
if (kind === SERVER) return `${protocolPrefix}server.request`
|
|
104
|
+
if (kind === CLIENT) return `${protocolPrefix}client.request`
|
|
105
|
+
|
|
106
|
+
// If all else fails, default to stringified span.kind.
|
|
107
|
+
return spanKindNames[kind]
|
|
108
|
+
}
|
|
109
|
+
|
|
22
110
|
class Span {
|
|
23
111
|
constructor (
|
|
24
112
|
parentTracer,
|
|
@@ -27,7 +115,8 @@ class Span {
|
|
|
27
115
|
spanContext,
|
|
28
116
|
kind,
|
|
29
117
|
links = [],
|
|
30
|
-
timeInput
|
|
118
|
+
timeInput,
|
|
119
|
+
attributes
|
|
31
120
|
) {
|
|
32
121
|
const { _tracer } = tracer
|
|
33
122
|
|
|
@@ -35,7 +124,7 @@ class Span {
|
|
|
35
124
|
const startTime = hrTimeToMilliseconds(hrStartTime)
|
|
36
125
|
|
|
37
126
|
this._ddSpan = new DatadogSpan(_tracer, _tracer._processor, _tracer._prioritySampler, {
|
|
38
|
-
operationName: spanName,
|
|
127
|
+
operationName: spanNameMapper(spanName, kind, attributes),
|
|
39
128
|
context: spanContext._ddContext,
|
|
40
129
|
startTime,
|
|
41
130
|
hostname: _tracer._hostname,
|
|
@@ -43,9 +132,14 @@ class Span {
|
|
|
43
132
|
tags: {
|
|
44
133
|
[SERVICE_NAME]: _tracer._service,
|
|
45
134
|
[RESOURCE_NAME]: spanName
|
|
46
|
-
}
|
|
135
|
+
},
|
|
136
|
+
links
|
|
47
137
|
}, _tracer._debug)
|
|
48
138
|
|
|
139
|
+
if (attributes) {
|
|
140
|
+
this.setAttributes(attributes)
|
|
141
|
+
}
|
|
142
|
+
|
|
49
143
|
this._parentTracer = parentTracer
|
|
50
144
|
this._context = context
|
|
51
145
|
|
|
@@ -55,7 +149,6 @@ class Span {
|
|
|
55
149
|
// math for computing opentracing timestamps is apparently lossy...
|
|
56
150
|
this.startTime = hrStartTime
|
|
57
151
|
this.kind = kind
|
|
58
|
-
this.links = links
|
|
59
152
|
this._spanProcessor.onStart(this, context)
|
|
60
153
|
}
|
|
61
154
|
|
|
@@ -98,6 +191,13 @@ class Span {
|
|
|
98
191
|
return this
|
|
99
192
|
}
|
|
100
193
|
|
|
194
|
+
addLink (context, attributes) {
|
|
195
|
+
// extract dd context
|
|
196
|
+
const ddSpanContext = context._ddContext
|
|
197
|
+
this._ddSpan.addLink(ddSpanContext, attributes)
|
|
198
|
+
return this
|
|
199
|
+
}
|
|
200
|
+
|
|
101
201
|
setStatus ({ code, message }) {
|
|
102
202
|
if (!this.ended && !this._hasStatus && code) {
|
|
103
203
|
this._hasStatus = true
|
|
@@ -78,23 +78,22 @@ class Tracer {
|
|
|
78
78
|
// return api.trace.wrapSpanContext(spanContext)
|
|
79
79
|
// }
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
return new Span(
|
|
82
82
|
this,
|
|
83
83
|
context,
|
|
84
84
|
name,
|
|
85
85
|
spanContext,
|
|
86
86
|
spanKind,
|
|
87
87
|
links,
|
|
88
|
-
options.startTime
|
|
88
|
+
options.startTime,
|
|
89
|
+
|
|
90
|
+
// Set initial span attributes. The attributes object may have been mutated
|
|
91
|
+
// by the sampler, so we sanitize the merged attributes before setting them.
|
|
92
|
+
sanitizeAttributes(
|
|
93
|
+
// Object.assign(attributes, samplingResult.attributes)
|
|
94
|
+
attributes
|
|
95
|
+
)
|
|
89
96
|
)
|
|
90
|
-
// Set initial span attributes. The attributes object may have been mutated
|
|
91
|
-
// by the sampler, so we sanitize the merged attributes before setting them.
|
|
92
|
-
const initAttributes = sanitizeAttributes(
|
|
93
|
-
// Object.assign(attributes, samplingResult.attributes)
|
|
94
|
-
attributes
|
|
95
|
-
)
|
|
96
|
-
span.setAttributes(initAttributes)
|
|
97
|
-
return span
|
|
98
97
|
}
|
|
99
98
|
|
|
100
99
|
startActiveSpan (name, options, context, fn) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const pick = require('
|
|
3
|
+
const pick = require('../../../../datadog-core/src/utils/src/pick')
|
|
4
4
|
const id = require('../../id')
|
|
5
5
|
const DatadogSpanContext = require('../span_context')
|
|
6
6
|
const log = require('../../log')
|
|
@@ -173,7 +173,7 @@ class TextMapPropagator {
|
|
|
173
173
|
ts.forVendor('dd', state => {
|
|
174
174
|
state.set('s', priority)
|
|
175
175
|
if (mechanism) {
|
|
176
|
-
state.set('t.dm', mechanism)
|
|
176
|
+
state.set('t.dm', `-${mechanism}`)
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
if (typeof origin === 'string') {
|
|
@@ -236,11 +236,20 @@ class TextMapPropagator {
|
|
|
236
236
|
_extractDatadogContext (carrier) {
|
|
237
237
|
const spanContext = this._extractGenericContext(carrier, traceKey, spanKey, 10)
|
|
238
238
|
|
|
239
|
-
if (spanContext)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
239
|
+
if (!spanContext) return spanContext
|
|
240
|
+
|
|
241
|
+
this._extractOrigin(carrier, spanContext)
|
|
242
|
+
this._extractBaggageItems(carrier, spanContext)
|
|
243
|
+
this._extractSamplingPriority(carrier, spanContext)
|
|
244
|
+
this._extractTags(carrier, spanContext)
|
|
245
|
+
|
|
246
|
+
if (this._config.tracePropagationExtractFirst) return spanContext
|
|
247
|
+
|
|
248
|
+
const tc = this._extractTraceparentContext(carrier)
|
|
249
|
+
|
|
250
|
+
if (tc && spanContext._traceId.equals(tc._traceId)) {
|
|
251
|
+
spanContext._traceparent = tc._traceparent
|
|
252
|
+
spanContext._tracestate = tc._tracestate
|
|
244
253
|
}
|
|
245
254
|
|
|
246
255
|
return spanContext
|
|
@@ -12,6 +12,8 @@ const runtimeMetrics = require('../runtime_metrics')
|
|
|
12
12
|
const log = require('../log')
|
|
13
13
|
const { storage } = require('../../../datadog-core')
|
|
14
14
|
const telemetryMetrics = require('../telemetry/metrics')
|
|
15
|
+
const { channel } = require('dc-polyfill')
|
|
16
|
+
const spanleak = require('../spanleak')
|
|
15
17
|
|
|
16
18
|
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
17
19
|
|
|
@@ -24,12 +26,15 @@ const unfinishedRegistry = createRegistry('unfinished')
|
|
|
24
26
|
const finishedRegistry = createRegistry('finished')
|
|
25
27
|
|
|
26
28
|
const OTEL_ENABLED = !!process.env.DD_TRACE_OTEL_ENABLED
|
|
29
|
+
const ALLOWED = ['string', 'number', 'boolean']
|
|
27
30
|
|
|
28
31
|
const integrationCounters = {
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
spans_created: {},
|
|
33
|
+
spans_finished: {}
|
|
31
34
|
}
|
|
32
35
|
|
|
36
|
+
const finishCh = channel('dd-trace:span:finish')
|
|
37
|
+
|
|
33
38
|
function getIntegrationCounter (event, integration) {
|
|
34
39
|
const counters = integrationCounters[event]
|
|
35
40
|
|
|
@@ -67,7 +72,7 @@ class DatadogSpan {
|
|
|
67
72
|
this._name = operationName
|
|
68
73
|
this._integrationName = fields.integrationName || 'opentracing'
|
|
69
74
|
|
|
70
|
-
getIntegrationCounter('
|
|
75
|
+
getIntegrationCounter('spans_created', this._integrationName).inc()
|
|
71
76
|
|
|
72
77
|
this._spanContext = this._createContext(parent, fields)
|
|
73
78
|
this._spanContext._name = operationName
|
|
@@ -78,6 +83,9 @@ class DatadogSpan {
|
|
|
78
83
|
|
|
79
84
|
this._startTime = fields.startTime || this._getTime()
|
|
80
85
|
|
|
86
|
+
this._links = []
|
|
87
|
+
fields.links && fields.links.forEach(link => this.addLink(link.context, link.attributes))
|
|
88
|
+
|
|
81
89
|
if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
|
|
82
90
|
runtimeMetrics.increment('runtime.node.spans.unfinished')
|
|
83
91
|
runtimeMetrics.increment('runtime.node.spans.unfinished.by.name', `span_name:${operationName}`)
|
|
@@ -87,6 +95,7 @@ class DatadogSpan {
|
|
|
87
95
|
|
|
88
96
|
unfinishedRegistry.register(this, operationName, this)
|
|
89
97
|
}
|
|
98
|
+
spanleak.addSpan(this, operationName)
|
|
90
99
|
}
|
|
91
100
|
|
|
92
101
|
toString () {
|
|
@@ -145,6 +154,13 @@ class DatadogSpan {
|
|
|
145
154
|
|
|
146
155
|
logEvent () {}
|
|
147
156
|
|
|
157
|
+
addLink (context, attributes) {
|
|
158
|
+
this._links.push({
|
|
159
|
+
context: context._ddContext ? context._ddContext : context,
|
|
160
|
+
attributes: this._sanitizeAttributes(attributes)
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
148
164
|
finish (finishTime) {
|
|
149
165
|
if (this._duration !== undefined) {
|
|
150
166
|
return
|
|
@@ -156,7 +172,7 @@ class DatadogSpan {
|
|
|
156
172
|
}
|
|
157
173
|
}
|
|
158
174
|
|
|
159
|
-
getIntegrationCounter('
|
|
175
|
+
getIntegrationCounter('spans_finished', this._integrationName).inc()
|
|
160
176
|
|
|
161
177
|
if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
|
|
162
178
|
runtimeMetrics.decrement('runtime.node.spans.unfinished')
|
|
@@ -176,9 +192,37 @@ class DatadogSpan {
|
|
|
176
192
|
this._duration = finishTime - this._startTime
|
|
177
193
|
this._spanContext._trace.finished.push(this)
|
|
178
194
|
this._spanContext._isFinished = true
|
|
195
|
+
finishCh.publish(this)
|
|
179
196
|
this._processor.process(this)
|
|
180
197
|
}
|
|
181
198
|
|
|
199
|
+
_sanitizeAttributes (attributes = {}) {
|
|
200
|
+
const sanitizedAttributes = {}
|
|
201
|
+
|
|
202
|
+
const addArrayOrScalarAttributes = (key, maybeArray) => {
|
|
203
|
+
if (Array.isArray(maybeArray)) {
|
|
204
|
+
for (const subkey in maybeArray) {
|
|
205
|
+
addArrayOrScalarAttributes(`${key}.${subkey}`, maybeArray[subkey])
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
const maybeScalar = maybeArray
|
|
209
|
+
if (ALLOWED.includes(typeof maybeScalar)) {
|
|
210
|
+
// Wrap the value as a string if it's not already a string
|
|
211
|
+
sanitizedAttributes[key] = typeof maybeScalar === 'string' ? maybeScalar : String(maybeScalar)
|
|
212
|
+
} else {
|
|
213
|
+
log.warn(`Dropping span link attribute. It is not of an allowed type`)
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
Object.entries(attributes).forEach(entry => {
|
|
219
|
+
const [key, value] = entry
|
|
220
|
+
addArrayOrScalarAttributes(key, value)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
return sanitizedAttributes
|
|
224
|
+
}
|
|
225
|
+
|
|
182
226
|
_createContext (parent, fields) {
|
|
183
227
|
let spanContext
|
|
184
228
|
let startTime
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const { AUTO_KEEP } = require('../../../../ext/priority')
|
|
4
4
|
|
|
5
|
+
// the lowercase, hex encoded upper 64 bits of a 128-bit trace id, if present
|
|
6
|
+
const TRACE_ID_128 = '_dd.p.tid'
|
|
7
|
+
|
|
5
8
|
class DatadogSpanContext {
|
|
6
9
|
constructor (props) {
|
|
7
10
|
props = props || {}
|
|
@@ -25,20 +28,26 @@ class DatadogSpanContext {
|
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
toTraceId () {
|
|
31
|
+
toTraceId (get128bitId = false) {
|
|
32
|
+
if (get128bitId) {
|
|
33
|
+
return this._traceId.toBuffer().length <= 8 && this._trace.tags[TRACE_ID_128]
|
|
34
|
+
? this._trace.tags[TRACE_ID_128] + this._traceId.toString(16).padStart(16, '0')
|
|
35
|
+
: this._traceId.toString(16).padStart(32, '0')
|
|
36
|
+
}
|
|
29
37
|
return this._traceId.toString(10)
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
toSpanId () {
|
|
40
|
+
toSpanId (get128bitId = false) {
|
|
41
|
+
if (get128bitId) {
|
|
42
|
+
return this._spanId.toString(16).padStart(16, '0')
|
|
43
|
+
}
|
|
33
44
|
return this._spanId.toString(10)
|
|
34
45
|
}
|
|
35
46
|
|
|
36
47
|
toTraceparent () {
|
|
37
48
|
const flags = this._sampling.priority >= AUTO_KEEP ? '01' : '00'
|
|
38
|
-
const traceId = this.
|
|
39
|
-
|
|
40
|
-
: this._traceId.toString(16).padStart(32, '0')
|
|
41
|
-
const spanId = this._spanId.toString(16).padStart(16, '0')
|
|
49
|
+
const traceId = this.toTraceId(true)
|
|
50
|
+
const spanId = this.toSpanId(true)
|
|
42
51
|
const version = (this._traceparent && this._traceparent.version) || '00'
|
|
43
52
|
return `${version}-${traceId}-${spanId}-${flags}`
|
|
44
53
|
}
|
|
@@ -22,10 +22,10 @@ class DatadogTracer {
|
|
|
22
22
|
constructor (config) {
|
|
23
23
|
const Exporter = getExporter(config.experimental.exporter)
|
|
24
24
|
|
|
25
|
+
this._config = config
|
|
25
26
|
this._service = config.service
|
|
26
27
|
this._version = config.version
|
|
27
28
|
this._env = config.env
|
|
28
|
-
this._tags = config.tags
|
|
29
29
|
this._logInjection = config.logInjection
|
|
30
30
|
this._debug = config.debug
|
|
31
31
|
this._prioritySampler = new PrioritySampler(config.env, config.sampler)
|
|
@@ -61,10 +61,11 @@ class DatadogTracer {
|
|
|
61
61
|
startTime: options.startTime,
|
|
62
62
|
hostname: this._hostname,
|
|
63
63
|
traceId128BitGenerationEnabled: this._traceId128BitGenerationEnabled,
|
|
64
|
-
integrationName: options.integrationName
|
|
64
|
+
integrationName: options.integrationName,
|
|
65
|
+
links: options.links
|
|
65
66
|
}, this._debug)
|
|
66
67
|
|
|
67
|
-
span.addTags(this.
|
|
68
|
+
span.addTags(this._config.tags)
|
|
68
69
|
span.addTags(options.tags)
|
|
69
70
|
|
|
70
71
|
return span
|