dd-trace 3.54.0 → 3.56.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/index.d.ts +15 -0
- package/package.json +3 -2
- package/packages/datadog-instrumentations/src/fetch.js +6 -45
- package/packages/datadog-instrumentations/src/helpers/fetch.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -1
- package/packages/datadog-instrumentations/src/jest.js +161 -14
- package/packages/datadog-instrumentations/src/kafkajs.js +4 -7
- package/packages/datadog-instrumentations/src/mongoose.js +2 -1
- package/packages/datadog-instrumentations/src/oracledb.js +1 -1
- package/packages/datadog-instrumentations/src/otel-sdk-trace.js +6 -1
- package/packages/datadog-instrumentations/src/selenium.js +69 -0
- package/packages/datadog-plugin-cucumber/src/index.js +2 -2
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +2 -2
- package/packages/datadog-plugin-cypress/src/support.js +19 -3
- package/packages/datadog-plugin-fetch/src/index.js +17 -11
- package/packages/datadog-plugin-jest/src/index.js +7 -2
- package/packages/datadog-plugin-mocha/src/index.js +4 -5
- package/packages/datadog-plugin-openai/src/services.js +2 -1
- package/packages/datadog-plugin-playwright/src/index.js +2 -2
- package/packages/datadog-plugin-selenium/src/index.js +71 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-base-analyzer.js +70 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-analyzer.js +14 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-password-rules.js +12 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-rule-type.js +6 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-analyzer.js +5 -50
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secret-rules.js +742 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/hardcoded-secrets-rules.js +539 -66
- package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +6 -2
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/reporter.js +11 -10
- package/packages/dd-trace/src/appsec/telemetry.js +36 -7
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
- package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +9 -2
- package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +4 -1
- package/packages/dd-trace/src/config.js +97 -10
- package/packages/dd-trace/src/dogstatsd.js +13 -11
- package/packages/dd-trace/src/index.js +5 -1
- package/packages/dd-trace/src/noop/dogstatsd.js +11 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +10 -4
- package/packages/dd-trace/src/opentracing/span.js +2 -0
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/git.js +33 -11
- package/packages/dd-trace/src/plugins/util/test.js +34 -3
- package/packages/dd-trace/src/profiling/config.js +8 -4
- package/packages/dd-trace/src/profiling/profiler.js +4 -0
- package/packages/dd-trace/src/profiling/ssi-telemetry-mock-profiler.js +33 -0
- package/packages/dd-trace/src/profiling/ssi-telemetry.js +167 -0
- package/packages/dd-trace/src/proxy.js +7 -1
- package/packages/dd-trace/src/tagger.js +13 -3
- package/packages/dd-trace/src/telemetry/index.js +5 -4
- package/packages/dd-trace/src/telemetry/metrics.js +2 -2
|
@@ -20,11 +20,15 @@ const EXCLUDED_LOCATIONS = getNodeModulesPaths(
|
|
|
20
20
|
'pusher/lib/utils.js',
|
|
21
21
|
'redlock/dist/cjs',
|
|
22
22
|
'sqreen/lib/package-reader/index.js',
|
|
23
|
-
'ws/lib/websocket-server.js'
|
|
23
|
+
'ws/lib/websocket-server.js',
|
|
24
|
+
'google-gax/build/src/grpc.js',
|
|
25
|
+
'cookie-signature/index.js'
|
|
24
26
|
)
|
|
25
27
|
|
|
26
28
|
const EXCLUDED_PATHS_FROM_STACK = [
|
|
27
|
-
path.join('node_modules', 'object-hash', path.sep)
|
|
29
|
+
path.join('node_modules', 'object-hash', path.sep),
|
|
30
|
+
path.join('node_modules', 'aws-sdk', 'lib', 'util.js'),
|
|
31
|
+
path.join('node_modules', 'keygrip', path.sep)
|
|
28
32
|
]
|
|
29
33
|
class WeakHashAnalyzer extends Analyzer {
|
|
30
34
|
constructor () {
|
|
@@ -8,7 +8,8 @@ const {
|
|
|
8
8
|
incrementWafInitMetric,
|
|
9
9
|
updateWafRequestsMetricTags,
|
|
10
10
|
incrementWafUpdatesMetric,
|
|
11
|
-
incrementWafRequestsMetric
|
|
11
|
+
incrementWafRequestsMetric,
|
|
12
|
+
getRequestMetrics
|
|
12
13
|
} = require('./telemetry')
|
|
13
14
|
const zlib = require('zlib')
|
|
14
15
|
|
|
@@ -92,19 +93,10 @@ function reportWafInit (wafVersion, rulesVersion, diagnosticsRules = {}) {
|
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
function reportMetrics (metrics) {
|
|
95
|
-
// TODO: metrics should be incremental, there already is an RFC to report metrics
|
|
96
96
|
const store = storage.getStore()
|
|
97
97
|
const rootSpan = store?.req && web.root(store.req)
|
|
98
98
|
if (!rootSpan) return
|
|
99
99
|
|
|
100
|
-
if (metrics.duration) {
|
|
101
|
-
rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (metrics.durationExt) {
|
|
105
|
-
rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
100
|
if (metrics.rulesVersion) {
|
|
109
101
|
rootSpan.setTag('_dd.appsec.event_rules.version', metrics.rulesVersion)
|
|
110
102
|
}
|
|
@@ -179,6 +171,15 @@ function finishRequest (req, res) {
|
|
|
179
171
|
metricsQueue.clear()
|
|
180
172
|
}
|
|
181
173
|
|
|
174
|
+
const metrics = getRequestMetrics(req)
|
|
175
|
+
if (metrics?.duration) {
|
|
176
|
+
rootSpan.setTag('_dd.appsec.waf.duration', metrics.duration)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (metrics?.durationExt) {
|
|
180
|
+
rootSpan.setTag('_dd.appsec.waf.duration_ext', metrics.durationExt)
|
|
181
|
+
}
|
|
182
|
+
|
|
182
183
|
incrementWafRequestsMetric(req)
|
|
183
184
|
|
|
184
185
|
// collect some headers even when no attack is detected
|
|
@@ -5,6 +5,7 @@ const telemetryMetrics = require('../telemetry/metrics')
|
|
|
5
5
|
const appsecMetrics = telemetryMetrics.manager.namespace('appsec')
|
|
6
6
|
|
|
7
7
|
const DD_TELEMETRY_WAF_RESULT_TAGS = Symbol('_dd.appsec.telemetry.waf.result.tags')
|
|
8
|
+
const DD_TELEMETRY_REQUEST_METRICS = Symbol('_dd.appsec.telemetry.request.metrics')
|
|
8
9
|
|
|
9
10
|
const tags = {
|
|
10
11
|
REQUEST_BLOCKED: 'request_blocked',
|
|
@@ -26,10 +27,19 @@ function disable () {
|
|
|
26
27
|
enabled = false
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
function newStore () {
|
|
31
|
+
return {
|
|
32
|
+
[DD_TELEMETRY_REQUEST_METRICS]: {
|
|
33
|
+
duration: 0,
|
|
34
|
+
durationExt: 0
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
29
39
|
function getStore (req) {
|
|
30
40
|
let store = metricsStoreMap.get(req)
|
|
31
41
|
if (!store) {
|
|
32
|
-
store =
|
|
42
|
+
store = newStore()
|
|
33
43
|
metricsStoreMap.set(req, store)
|
|
34
44
|
}
|
|
35
45
|
return store
|
|
@@ -51,9 +61,7 @@ function trackWafDurations (metrics, versionsTags) {
|
|
|
51
61
|
}
|
|
52
62
|
}
|
|
53
63
|
|
|
54
|
-
function getOrCreateMetricTags (
|
|
55
|
-
const store = getStore(req)
|
|
56
|
-
|
|
64
|
+
function getOrCreateMetricTags (store, versionsTags) {
|
|
57
65
|
let metricTags = store[DD_TELEMETRY_WAF_RESULT_TAGS]
|
|
58
66
|
if (!metricTags) {
|
|
59
67
|
metricTags = {
|
|
@@ -69,13 +77,20 @@ function getOrCreateMetricTags (req, versionsTags) {
|
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
function updateWafRequestsMetricTags (metrics, req) {
|
|
72
|
-
if (!req
|
|
80
|
+
if (!req) return
|
|
81
|
+
|
|
82
|
+
const store = getStore(req)
|
|
83
|
+
|
|
84
|
+
// it does not depend on whether telemetry is enabled or not
|
|
85
|
+
addRequestMetrics(store, metrics)
|
|
86
|
+
|
|
87
|
+
if (!enabled) return
|
|
73
88
|
|
|
74
89
|
const versionsTags = getVersionsTags(metrics.wafVersion, metrics.rulesVersion)
|
|
75
90
|
|
|
76
91
|
trackWafDurations(metrics, versionsTags)
|
|
77
92
|
|
|
78
|
-
const metricTags = getOrCreateMetricTags(
|
|
93
|
+
const metricTags = getOrCreateMetricTags(store, versionsTags)
|
|
79
94
|
|
|
80
95
|
const { blockTriggered, ruleTriggered, wafTimeout } = metrics
|
|
81
96
|
|
|
@@ -121,6 +136,18 @@ function incrementWafRequestsMetric (req) {
|
|
|
121
136
|
metricsStoreMap.delete(req)
|
|
122
137
|
}
|
|
123
138
|
|
|
139
|
+
function addRequestMetrics (store, { duration, durationExt }) {
|
|
140
|
+
store[DD_TELEMETRY_REQUEST_METRICS].duration += duration || 0
|
|
141
|
+
store[DD_TELEMETRY_REQUEST_METRICS].durationExt += durationExt || 0
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function getRequestMetrics (req) {
|
|
145
|
+
if (req) {
|
|
146
|
+
const store = getStore(req)
|
|
147
|
+
return store?.[DD_TELEMETRY_REQUEST_METRICS]
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
124
151
|
module.exports = {
|
|
125
152
|
enable,
|
|
126
153
|
disable,
|
|
@@ -128,5 +155,7 @@ module.exports = {
|
|
|
128
155
|
updateWafRequestsMetricTags,
|
|
129
156
|
incrementWafInitMetric,
|
|
130
157
|
incrementWafUpdatesMetric,
|
|
131
|
-
incrementWafRequestsMetric
|
|
158
|
+
incrementWafRequestsMetric,
|
|
159
|
+
|
|
160
|
+
getRequestMetrics
|
|
132
161
|
}
|
|
@@ -189,7 +189,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
189
189
|
isItrEnabled,
|
|
190
190
|
requireGit,
|
|
191
191
|
isEarlyFlakeDetectionEnabled,
|
|
192
|
-
earlyFlakeDetectionNumRetries
|
|
192
|
+
earlyFlakeDetectionNumRetries,
|
|
193
|
+
earlyFlakeDetectionFaultyThreshold
|
|
193
194
|
} = remoteConfiguration
|
|
194
195
|
return {
|
|
195
196
|
isCodeCoverageEnabled,
|
|
@@ -197,7 +198,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
|
|
|
197
198
|
isItrEnabled,
|
|
198
199
|
requireGit,
|
|
199
200
|
isEarlyFlakeDetectionEnabled: isEarlyFlakeDetectionEnabled && this._config.isEarlyFlakeDetectionEnabled,
|
|
200
|
-
earlyFlakeDetectionNumRetries
|
|
201
|
+
earlyFlakeDetectionNumRetries,
|
|
202
|
+
earlyFlakeDetectionFaultyThreshold
|
|
201
203
|
}
|
|
202
204
|
}
|
|
203
205
|
|
|
@@ -114,6 +114,10 @@ function getCommitsToUpload ({ url, repositoryUrl, latestCommits, isEvpProxy, ev
|
|
|
114
114
|
|
|
115
115
|
const commitsToUpload = getCommitsRevList(alreadySeenCommits, commitsToInclude)
|
|
116
116
|
|
|
117
|
+
if (commitsToUpload === null) {
|
|
118
|
+
return callback(new Error('git rev-list failed'))
|
|
119
|
+
}
|
|
120
|
+
|
|
117
121
|
callback(null, commitsToUpload)
|
|
118
122
|
})
|
|
119
123
|
}
|
|
@@ -252,9 +256,8 @@ function sendGitMetadata (url, { isEvpProxy, evpProxyPrefix }, configRepositoryU
|
|
|
252
256
|
return callback(new Error('Repository URL is empty'))
|
|
253
257
|
}
|
|
254
258
|
|
|
255
|
-
|
|
259
|
+
let latestCommits = getLatestCommits()
|
|
256
260
|
log.debug(`There were ${latestCommits.length} commits since last month.`)
|
|
257
|
-
const [headCommit] = latestCommits
|
|
258
261
|
|
|
259
262
|
const getOnFinishGetCommitsToUpload = (hasCheckedShallow) => (err, commitsToUpload) => {
|
|
260
263
|
if (err) {
|
|
@@ -268,6 +271,7 @@ function sendGitMetadata (url, { isEvpProxy, evpProxyPrefix }, configRepositoryU
|
|
|
268
271
|
|
|
269
272
|
// If it has already unshallowed or the clone is not shallow, we move on
|
|
270
273
|
if (hasCheckedShallow || !isShallowRepository()) {
|
|
274
|
+
const [headCommit] = latestCommits
|
|
271
275
|
return generateAndUploadPackFiles({
|
|
272
276
|
url,
|
|
273
277
|
isEvpProxy,
|
|
@@ -280,6 +284,9 @@ function sendGitMetadata (url, { isEvpProxy, evpProxyPrefix }, configRepositoryU
|
|
|
280
284
|
// Otherwise we unshallow and get commits to upload again
|
|
281
285
|
log.debug('It is shallow clone, unshallowing...')
|
|
282
286
|
unshallowRepository()
|
|
287
|
+
|
|
288
|
+
// The latest commits change after unshallowing
|
|
289
|
+
latestCommits = getLatestCommits()
|
|
283
290
|
getCommitsToUpload({
|
|
284
291
|
url,
|
|
285
292
|
repositoryUrl,
|
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
} = require('../telemetry')
|
|
13
13
|
|
|
14
14
|
const DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES = 2
|
|
15
|
+
const DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD = 30
|
|
15
16
|
|
|
16
17
|
function getLibraryConfiguration ({
|
|
17
18
|
url,
|
|
@@ -104,7 +105,9 @@ function getLibraryConfiguration ({
|
|
|
104
105
|
requireGit,
|
|
105
106
|
isEarlyFlakeDetectionEnabled: earlyFlakeDetectionConfig?.enabled ?? false,
|
|
106
107
|
earlyFlakeDetectionNumRetries:
|
|
107
|
-
earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES
|
|
108
|
+
earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
|
|
109
|
+
earlyFlakeDetectionFaultyThreshold:
|
|
110
|
+
earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)
|
|
@@ -15,9 +15,65 @@ const { isTrue, isFalse } = require('./util')
|
|
|
15
15
|
const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('./plugins/util/tags')
|
|
16
16
|
const { getGitMetadataFromGitProperties, removeUserSensitiveInfo } = require('./git_properties')
|
|
17
17
|
const { updateConfig } = require('./telemetry')
|
|
18
|
+
const telemetryMetrics = require('./telemetry/metrics')
|
|
18
19
|
const { getIsGCPFunction, getIsAzureFunctionConsumptionPlan } = require('./serverless')
|
|
19
20
|
const { ORIGIN_KEY } = require('./constants')
|
|
20
21
|
|
|
22
|
+
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
23
|
+
|
|
24
|
+
const telemetryCounters = {
|
|
25
|
+
'otel.env.hiding': {},
|
|
26
|
+
'otel.env.invalid': {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getCounter (event, ddVar, otelVar, otelTracesSamplerArg) {
|
|
30
|
+
const counters = telemetryCounters[event]
|
|
31
|
+
const tags = []
|
|
32
|
+
|
|
33
|
+
if (ddVar) tags.push(ddVar)
|
|
34
|
+
if (otelVar) tags.push(otelVar)
|
|
35
|
+
if (otelTracesSamplerArg) tags.push(otelTracesSamplerArg)
|
|
36
|
+
|
|
37
|
+
if (!(ddVar in counters)) counters[ddVar] = {}
|
|
38
|
+
|
|
39
|
+
const counter = tracerMetrics.count(event, tags)
|
|
40
|
+
counters[ddVar][otelVar] = counter
|
|
41
|
+
return counter
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const otelDdEnvMapping = {
|
|
45
|
+
DD_TRACE_LOG_LEVEL: 'OTEL_LOG_LEVEL',
|
|
46
|
+
DD_TRACE_PROPAGATION_STYLE: 'OTEL_PROPAGATORS',
|
|
47
|
+
DD_SERVICE: 'OTEL_SERVICE_NAME',
|
|
48
|
+
DD_TRACE_SAMPLE_RATE: 'OTEL_TRACES_SAMPLER',
|
|
49
|
+
DD_TRACE_ENABLED: 'OTEL_TRACES_EXPORTER',
|
|
50
|
+
DD_RUNTIME_METRICS_ENABLED: 'OTEL_METRICS_EXPORTER',
|
|
51
|
+
DD_TAGS: 'OTEL_RESOURCE_ATTRIBUTES',
|
|
52
|
+
DD_TRACE_OTEL_ENABLED: 'OTEL_SDK_DISABLED'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const otelInvalidEnv = ['OTEL_LOGS_EXPORTER']
|
|
56
|
+
|
|
57
|
+
function checkIfBothOtelAndDdEnvVarSet () {
|
|
58
|
+
for (const [ddVar, otelVar] of Object.entries(otelDdEnvMapping)) {
|
|
59
|
+
if (process.env[ddVar] && process.env[otelVar]) {
|
|
60
|
+
log.warn(`both ${ddVar} and ${otelVar} environment variables are set`)
|
|
61
|
+
getCounter('otel.env.hiding', ddVar, otelVar,
|
|
62
|
+
otelVar === 'OTEL_TRACES_SAMPLER' &&
|
|
63
|
+
process.env.OTEL_TRACES_SAMPLER_ARG
|
|
64
|
+
? 'OTEL_TRACES_SAMPLER_ARG'
|
|
65
|
+
: undefined).inc()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
for (const otelVar of otelInvalidEnv) {
|
|
70
|
+
if (process.env[otelVar]) {
|
|
71
|
+
log.warn(`${otelVar} is not supported by the Datadog SDK`)
|
|
72
|
+
getCounter('otel.env.invalid', otelVar).inc()
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
21
77
|
const fromEntries = Object.fromEntries || (entries =>
|
|
22
78
|
entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
|
|
23
79
|
|
|
@@ -27,6 +83,7 @@ const qsRegex = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private
|
|
|
27
83
|
const defaultWafObfuscatorKeyRegex = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?)key)|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization'
|
|
28
84
|
// eslint-disable-next-line max-len
|
|
29
85
|
const defaultWafObfuscatorValueRegex = '(?i)(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:\\s*=[^;]|"\\s*:\\s*"[^"]+")|bearer\\s+[a-z0-9\\._\\-]+|token:[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L][\\w=-]+\\.ey[I-L][\\w=-]+(?:\\.[\\w.+\\/=-]+)?|[\\-]{5}BEGIN[a-z\\s]+PRIVATE\\sKEY[\\-]{5}[^\\-]+[\\-]{5}END[a-z\\s]+PRIVATE\\sKEY|ssh-rsa\\s*[a-z0-9\\/\\.+]{100,}'
|
|
86
|
+
const runtimeId = uuid()
|
|
30
87
|
|
|
31
88
|
function maybeFile (filepath) {
|
|
32
89
|
if (!filepath) return
|
|
@@ -88,7 +145,8 @@ function propagationStyle (key, option, defaultValue) {
|
|
|
88
145
|
|
|
89
146
|
// Otherwise, fallback to env var parsing
|
|
90
147
|
const envKey = `DD_TRACE_PROPAGATION_STYLE_${key.toUpperCase()}`
|
|
91
|
-
|
|
148
|
+
|
|
149
|
+
const envVar = coalesce(process.env[envKey], process.env.DD_TRACE_PROPAGATION_STYLE, process.env.OTEL_PROPAGATORS)
|
|
92
150
|
if (typeof envVar !== 'undefined') {
|
|
93
151
|
return envVar.split(',')
|
|
94
152
|
.filter(v => v !== '')
|
|
@@ -107,15 +165,19 @@ class Config {
|
|
|
107
165
|
iastOptions: options.experimental?.iast
|
|
108
166
|
}
|
|
109
167
|
|
|
168
|
+
checkIfBothOtelAndDdEnvVarSet()
|
|
169
|
+
|
|
110
170
|
// Configure the logger first so it can be used to warn about other configs
|
|
111
171
|
this.debug = isTrue(coalesce(
|
|
112
172
|
process.env.DD_TRACE_DEBUG,
|
|
113
173
|
false
|
|
114
174
|
))
|
|
115
175
|
this.logger = options.logger
|
|
176
|
+
|
|
116
177
|
this.logLevel = coalesce(
|
|
117
178
|
options.logLevel,
|
|
118
179
|
process.env.DD_TRACE_LOG_LEVEL,
|
|
180
|
+
process.env.OTEL_LOG_LEVEL,
|
|
119
181
|
'debug'
|
|
120
182
|
)
|
|
121
183
|
|
|
@@ -162,12 +224,12 @@ class Config {
|
|
|
162
224
|
'environment variables'
|
|
163
225
|
)
|
|
164
226
|
}
|
|
165
|
-
const
|
|
227
|
+
const PROPAGATION_STYLE_INJECT = propagationStyle(
|
|
166
228
|
'inject',
|
|
167
229
|
options.tracePropagationStyle,
|
|
168
230
|
defaultPropagationStyle
|
|
169
231
|
)
|
|
170
|
-
const
|
|
232
|
+
const PROPAGATION_STYLE_EXTRACT = propagationStyle(
|
|
171
233
|
'extract',
|
|
172
234
|
options.tracePropagationStyle,
|
|
173
235
|
defaultPropagationStyle
|
|
@@ -252,8 +314,13 @@ class Config {
|
|
|
252
314
|
this.apiKey = DD_API_KEY
|
|
253
315
|
this.serviceMapping = DD_SERVICE_MAPPING
|
|
254
316
|
this.tracePropagationStyle = {
|
|
255
|
-
inject:
|
|
256
|
-
extract:
|
|
317
|
+
inject: PROPAGATION_STYLE_INJECT,
|
|
318
|
+
extract: PROPAGATION_STYLE_EXTRACT,
|
|
319
|
+
otelPropagators: process.env.DD_TRACE_PROPAGATION_STYLE ||
|
|
320
|
+
process.env.DD_TRACE_PROPAGATION_STYLE_INJECT ||
|
|
321
|
+
process.env.DD_TRACE_PROPAGATION_STYLE_EXTRACT
|
|
322
|
+
? false
|
|
323
|
+
: !!process.env.OTEL_PROPAGATORS
|
|
257
324
|
}
|
|
258
325
|
this.tracePropagationExtractFirst = isTrue(DD_TRACE_PROPAGATION_EXTRACT_FIRST)
|
|
259
326
|
this.sampler = sampler
|
|
@@ -291,7 +358,7 @@ class Config {
|
|
|
291
358
|
service: this.service,
|
|
292
359
|
env: this.env,
|
|
293
360
|
version: this.version,
|
|
294
|
-
'runtime-id':
|
|
361
|
+
'runtime-id': runtimeId
|
|
295
362
|
})
|
|
296
363
|
|
|
297
364
|
if (this.isCiVisibility) {
|
|
@@ -525,12 +592,18 @@ class Config {
|
|
|
525
592
|
DD_TRACE_TELEMETRY_ENABLED,
|
|
526
593
|
DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
|
|
527
594
|
DD_TRACING_ENABLED,
|
|
528
|
-
DD_VERSION
|
|
595
|
+
DD_VERSION,
|
|
596
|
+
OTEL_SERVICE_NAME,
|
|
597
|
+
OTEL_RESOURCE_ATTRIBUTES,
|
|
598
|
+
OTEL_TRACES_SAMPLER,
|
|
599
|
+
OTEL_TRACES_SAMPLER_ARG,
|
|
600
|
+
OTEL_METRICS_EXPORTER
|
|
529
601
|
} = process.env
|
|
530
602
|
|
|
531
603
|
const tags = {}
|
|
532
604
|
const env = this._env = {}
|
|
533
605
|
|
|
606
|
+
tagger.add(tags, OTEL_RESOURCE_ATTRIBUTES, true)
|
|
534
607
|
tagger.add(tags, DD_TAGS)
|
|
535
608
|
tagger.add(tags, DD_TRACE_TAGS)
|
|
536
609
|
tagger.add(tags, DD_TRACE_GLOBAL_TAGS)
|
|
@@ -591,11 +664,24 @@ class Config {
|
|
|
591
664
|
))
|
|
592
665
|
this._setValue(env, 'remoteConfig.pollInterval', maybeFloat(DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS))
|
|
593
666
|
this._setBoolean(env, 'reportHostname', DD_TRACE_REPORT_HOSTNAME)
|
|
594
|
-
|
|
595
|
-
|
|
667
|
+
// only used to explicitly set runtimeMetrics to false
|
|
668
|
+
const otelSetRuntimeMetrics = String(OTEL_METRICS_EXPORTER).toLowerCase() === 'none'
|
|
669
|
+
? false
|
|
670
|
+
: undefined
|
|
671
|
+
this._setBoolean(env, 'runtimeMetrics', DD_RUNTIME_METRICS_ENABLED ||
|
|
672
|
+
otelSetRuntimeMetrics)
|
|
673
|
+
const OTEL_TRACES_SAMPLER_MAPPING = {
|
|
674
|
+
always_on: '1.0',
|
|
675
|
+
always_off: '0.0',
|
|
676
|
+
traceidratio: OTEL_TRACES_SAMPLER_ARG,
|
|
677
|
+
parentbased_always_on: '1.0',
|
|
678
|
+
parentbased_always_off: '0.0',
|
|
679
|
+
parentbased_traceidratio: OTEL_TRACES_SAMPLER_ARG
|
|
680
|
+
}
|
|
681
|
+
this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE || OTEL_TRACES_SAMPLER_MAPPING[OTEL_TRACES_SAMPLER])
|
|
596
682
|
this._setValue(env, 'sampler.rateLimit', DD_TRACE_RATE_LIMIT)
|
|
597
683
|
this._setString(env, 'scope', DD_TRACE_SCOPE)
|
|
598
|
-
this._setString(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service)
|
|
684
|
+
this._setString(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service || OTEL_SERVICE_NAME)
|
|
599
685
|
this._setString(env, 'site', DD_SITE)
|
|
600
686
|
if (DD_TRACE_SPAN_ATTRIBUTE_SCHEMA) {
|
|
601
687
|
this._setString(env, 'spanAttributeSchema', validateNamingVersion(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA))
|
|
@@ -823,6 +909,7 @@ class Config {
|
|
|
823
909
|
: undefined
|
|
824
910
|
|
|
825
911
|
tagger.add(tags, options.tracing_tags)
|
|
912
|
+
if (Object.keys(tags).length) tags['runtime-id'] = runtimeId
|
|
826
913
|
|
|
827
914
|
this._setUnit(opts, 'sampleRate', options.tracing_sampling_rate)
|
|
828
915
|
this._setBoolean(opts, 'logInjection', options.log_injection_enabled)
|
|
@@ -12,6 +12,7 @@ const MAX_BUFFER_SIZE = 1024 // limit from the agent
|
|
|
12
12
|
const TYPE_COUNTER = 'c'
|
|
13
13
|
const TYPE_GAUGE = 'g'
|
|
14
14
|
const TYPE_DISTRIBUTION = 'd'
|
|
15
|
+
const TYPE_HISTOGRAM = 'h'
|
|
15
16
|
|
|
16
17
|
class DogStatsDClient {
|
|
17
18
|
constructor (options = {}) {
|
|
@@ -46,6 +47,10 @@ class DogStatsDClient {
|
|
|
46
47
|
this._add(stat, value, TYPE_DISTRIBUTION, tags)
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
histogram (stat, value, tags) {
|
|
51
|
+
this._add(stat, value, TYPE_HISTOGRAM, tags)
|
|
52
|
+
}
|
|
53
|
+
|
|
49
54
|
flush () {
|
|
50
55
|
const queue = this._enqueue()
|
|
51
56
|
|
|
@@ -180,16 +185,6 @@ class DogStatsDClient {
|
|
|
180
185
|
}
|
|
181
186
|
}
|
|
182
187
|
|
|
183
|
-
class NoopDogStatsDClient {
|
|
184
|
-
gauge () { }
|
|
185
|
-
|
|
186
|
-
increment () { }
|
|
187
|
-
|
|
188
|
-
distribution () { }
|
|
189
|
-
|
|
190
|
-
flush () { }
|
|
191
|
-
}
|
|
192
|
-
|
|
193
188
|
// This is a simplified user-facing proxy to the underlying DogStatsDClient instance
|
|
194
189
|
class CustomMetrics {
|
|
195
190
|
constructor (config) {
|
|
@@ -229,6 +224,14 @@ class CustomMetrics {
|
|
|
229
224
|
)
|
|
230
225
|
}
|
|
231
226
|
|
|
227
|
+
histogram (stat, value, tags) {
|
|
228
|
+
return this.dogstatsd.histogram(
|
|
229
|
+
stat,
|
|
230
|
+
value,
|
|
231
|
+
CustomMetrics.tagTranslator(tags)
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
|
|
232
235
|
flush () {
|
|
233
236
|
return this.dogstatsd.flush()
|
|
234
237
|
}
|
|
@@ -252,6 +255,5 @@ class CustomMetrics {
|
|
|
252
255
|
|
|
253
256
|
module.exports = {
|
|
254
257
|
DogStatsDClient,
|
|
255
|
-
NoopDogStatsDClient,
|
|
256
258
|
CustomMetrics
|
|
257
259
|
}
|
|
@@ -5,6 +5,10 @@ const { isFalse } = require('./util')
|
|
|
5
5
|
// Global `jest` is only present in Jest workers.
|
|
6
6
|
const inJestWorker = typeof jest !== 'undefined'
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
const ddTraceDisabled = process.env.DD_TRACE_ENABLED
|
|
9
|
+
? isFalse(process.env.DD_TRACE_ENABLED)
|
|
10
|
+
: String(process.env.OTEL_TRACES_EXPORTER).toLowerCase() === 'none'
|
|
11
|
+
|
|
12
|
+
module.exports = ddTraceDisabled || inJestWorker
|
|
9
13
|
? require('./noop/proxy')
|
|
10
14
|
: require('./proxy')
|
|
@@ -2,14 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
const NoopTracer = require('./tracer')
|
|
4
4
|
const NoopAppsecSdk = require('../appsec/sdk/noop')
|
|
5
|
+
const NoopDogStatsDClient = require('./dogstatsd')
|
|
5
6
|
|
|
6
7
|
const noop = new NoopTracer()
|
|
7
8
|
const noopAppsec = new NoopAppsecSdk()
|
|
9
|
+
const noopDogStatsDClient = new NoopDogStatsDClient()
|
|
8
10
|
|
|
9
11
|
class Tracer {
|
|
10
12
|
constructor () {
|
|
11
13
|
this._tracer = noop
|
|
12
14
|
this.appsec = noopAppsec
|
|
15
|
+
this.dogstatsd = noopDogStatsDClient
|
|
13
16
|
}
|
|
14
17
|
|
|
15
18
|
init () {
|
|
@@ -224,13 +224,19 @@ class TextMapPropagator {
|
|
|
224
224
|
case 'tracecontext':
|
|
225
225
|
spanContext = this._extractTraceparentContext(carrier)
|
|
226
226
|
break
|
|
227
|
-
case 'b3'
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
227
|
+
case 'b3' && this
|
|
228
|
+
._config
|
|
229
|
+
.tracePropagationStyle
|
|
230
|
+
.otelPropagators: // TODO: should match "b3 single header" in next major
|
|
231
231
|
case 'b3 single header': // TODO: delete in major after singular "b3"
|
|
232
232
|
spanContext = this._extractB3SingleContext(carrier)
|
|
233
233
|
break
|
|
234
|
+
case 'b3':
|
|
235
|
+
case 'b3multi':
|
|
236
|
+
spanContext = this._extractB3MultiContext(carrier)
|
|
237
|
+
break
|
|
238
|
+
default:
|
|
239
|
+
log.warn(`Unknown propagation style: ${extractor}`)
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
if (spanContext !== null) {
|
|
@@ -33,6 +33,7 @@ const integrationCounters = {
|
|
|
33
33
|
spans_finished: {}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
const startCh = channel('dd-trace:span:start')
|
|
36
37
|
const finishCh = channel('dd-trace:span:finish')
|
|
37
38
|
|
|
38
39
|
function getIntegrationCounter (event, integration) {
|
|
@@ -96,6 +97,7 @@ class DatadogSpan {
|
|
|
96
97
|
unfinishedRegistry.register(this, operationName, this)
|
|
97
98
|
}
|
|
98
99
|
spanleak.addSpan(this, operationName)
|
|
100
|
+
startCh.publish(this)
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
toString () {
|
|
@@ -45,6 +45,7 @@ module.exports = {
|
|
|
45
45
|
get 'jest-environment-node' () { return require('../../../datadog-plugin-jest/src') },
|
|
46
46
|
get 'jest-environment-jsdom' () { return require('../../../datadog-plugin-jest/src') },
|
|
47
47
|
get 'jest-jasmine2' () { return require('../../../datadog-plugin-jest/src') },
|
|
48
|
+
get 'jest-runtime' () { return require('../../../datadog-plugin-jest/src') },
|
|
48
49
|
get 'jest-worker' () { return require('../../../datadog-plugin-jest/src') },
|
|
49
50
|
get koa () { return require('../../../datadog-plugin-koa/src') },
|
|
50
51
|
get 'koa-router' () { return require('../../../datadog-plugin-koa/src') },
|
|
@@ -77,6 +78,7 @@ module.exports = {
|
|
|
77
78
|
get restify () { return require('../../../datadog-plugin-restify/src') },
|
|
78
79
|
get rhea () { return require('../../../datadog-plugin-rhea/src') },
|
|
79
80
|
get router () { return require('../../../datadog-plugin-router/src') },
|
|
81
|
+
get 'selenium-webdriver' () { return require('../../../datadog-plugin-selenium/src') },
|
|
80
82
|
get sharedb () { return require('../../../datadog-plugin-sharedb/src') },
|
|
81
83
|
get tedious () { return require('../../../datadog-plugin-tedious/src') },
|
|
82
84
|
get winston () { return require('../../../datadog-plugin-winston/src') }
|