dd-trace 4.29.0 → 4.31.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.
Files changed (80) hide show
  1. package/README.md +7 -0
  2. package/ci/cypress/after-spec.js +1 -0
  3. package/index.d.ts +1502 -1485
  4. package/package.json +4 -4
  5. package/packages/datadog-core/src/utils/src/get.js +11 -0
  6. package/packages/datadog-core/src/utils/src/has.js +14 -0
  7. package/packages/datadog-core/src/utils/src/set.js +16 -0
  8. package/packages/datadog-instrumentations/src/amqplib.js +1 -1
  9. package/packages/datadog-instrumentations/src/cucumber.js +2 -1
  10. package/packages/datadog-instrumentations/src/grpc/server.js +3 -1
  11. package/packages/datadog-instrumentations/src/jest.js +11 -5
  12. package/packages/datadog-instrumentations/src/mocha.js +4 -1
  13. package/packages/datadog-instrumentations/src/mongodb-core.js +34 -3
  14. package/packages/datadog-instrumentations/src/playwright.js +78 -16
  15. package/packages/datadog-plugin-amqplib/src/consumer.js +5 -4
  16. package/packages/datadog-plugin-amqplib/src/producer.js +3 -4
  17. package/packages/datadog-plugin-aws-sdk/src/base.js +3 -2
  18. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -11
  19. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +3 -6
  20. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +5 -7
  21. package/packages/datadog-plugin-cucumber/src/index.js +2 -2
  22. package/packages/datadog-plugin-cypress/src/after-spec.js +3 -0
  23. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +123 -58
  24. package/packages/datadog-plugin-cypress/src/support.js +50 -3
  25. package/packages/datadog-plugin-graphql/src/index.js +1 -1
  26. package/packages/datadog-plugin-graphql/src/resolve.js +10 -8
  27. package/packages/datadog-plugin-grpc/src/util.js +1 -1
  28. package/packages/datadog-plugin-jest/src/index.js +13 -4
  29. package/packages/datadog-plugin-kafkajs/src/consumer.js +4 -3
  30. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -5
  31. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  32. package/packages/datadog-plugin-playwright/src/index.js +34 -3
  33. package/packages/datadog-plugin-rhea/src/consumer.js +5 -3
  34. package/packages/datadog-plugin-rhea/src/producer.js +3 -4
  35. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +23 -12
  36. package/packages/dd-trace/src/appsec/iast/index.js +10 -0
  37. package/packages/dd-trace/src/appsec/iast/path-line.js +9 -6
  38. package/packages/dd-trace/src/appsec/iast/taint-tracking/operations.js +1 -1
  39. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +6 -2
  40. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +1 -1
  41. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +14 -2
  42. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +1 -1
  43. package/packages/dd-trace/src/appsec/iast/telemetry/iast-metric.js +34 -27
  44. package/packages/dd-trace/src/appsec/iast/telemetry/namespaces.js +39 -11
  45. package/packages/dd-trace/src/appsec/iast/telemetry/span-tags.js +7 -6
  46. package/packages/dd-trace/src/appsec/recommended.json +67 -27
  47. package/packages/dd-trace/src/appsec/remote_config/index.js +1 -1
  48. package/packages/dd-trace/src/appsec/reporter.js +24 -11
  49. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -3
  50. package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +6 -1
  51. package/packages/dd-trace/src/config.js +451 -460
  52. package/packages/dd-trace/src/data_streams_context.js +1 -1
  53. package/packages/dd-trace/src/datastreams/pathway.js +58 -1
  54. package/packages/dd-trace/src/datastreams/processor.js +3 -5
  55. package/packages/dd-trace/src/format.js +0 -1
  56. package/packages/dd-trace/src/lambda/runtime/ritm.js +1 -1
  57. package/packages/dd-trace/src/opentracing/propagation/text_map.js +22 -3
  58. package/packages/dd-trace/src/opentracing/span.js +2 -0
  59. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  60. package/packages/dd-trace/src/plugins/util/test.js +4 -2
  61. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  62. package/packages/dd-trace/src/priority_sampler.js +11 -6
  63. package/packages/dd-trace/src/profiling/exporters/agent.js +38 -2
  64. package/packages/dd-trace/src/telemetry/index.js +32 -33
  65. package/packages/dd-trace/src/tracer.js +3 -3
  66. package/register.js +4 -0
  67. package/CONTRIBUTING.md +0 -171
  68. package/MIGRATING.md +0 -224
  69. package/packages/dd-trace/src/external-logger/test/index.spec.js +0 -147
  70. package/scripts/check-proposal-labels.js +0 -71
  71. package/scripts/check_licenses.js +0 -69
  72. package/scripts/helpers/color.js +0 -8
  73. package/scripts/helpers/exec.js +0 -22
  74. package/scripts/helpers/title.js +0 -15
  75. package/scripts/install_plugin_modules.js +0 -248
  76. package/scripts/publish_docs.js +0 -21
  77. package/scripts/st.js +0 -105
  78. /package/packages/{utils → datadog-core/src/utils}/src/kebabcase.js +0 -0
  79. /package/packages/{utils → datadog-core/src/utils}/src/pick.js +0 -0
  80. /package/packages/{utils → datadog-core/src/utils}/src/uniq.js +0 -0
@@ -6,7 +6,7 @@ function getDataStreamsContext () {
6
6
  }
7
7
 
8
8
  function setDataStreamsContext (dataStreamsContext) {
9
- storage.enterWith({ ...(storage.getStore()), dataStreamsContext })
9
+ if (dataStreamsContext) storage.enterWith({ ...(storage.getStore()), dataStreamsContext })
10
10
  }
11
11
 
12
12
  module.exports = {
@@ -8,6 +8,9 @@ const LRUCache = require('lru-cache')
8
8
  const options = { max: 500 }
9
9
  const cache = new LRUCache(options)
10
10
 
11
+ const CONTEXT_PROPAGATION_KEY = 'dd-pathway-ctx'
12
+ const CONTEXT_PROPAGATION_KEY_BASE64 = 'dd-pathway-ctx-base64'
13
+
11
14
  function shaHash (checkpointString) {
12
15
  const hash = crypto.createHash('md5').update(checkpointString).digest('hex').slice(0, 16)
13
16
  return Buffer.from(hash, 'hex')
@@ -33,6 +36,11 @@ function encodePathwayContext (dataStreamsContext) {
33
36
  ], 20)
34
37
  }
35
38
 
39
+ function encodePathwayContextBase64 (dataStreamsContext) {
40
+ const encodedPathway = encodePathwayContext(dataStreamsContext)
41
+ return encodedPathway.toString('base64')
42
+ }
43
+
36
44
  function decodePathwayContext (pathwayContext) {
37
45
  if (pathwayContext == null || pathwayContext.length < 8) {
38
46
  return null
@@ -51,8 +59,57 @@ function decodePathwayContext (pathwayContext) {
51
59
  return { hash: pathwayHash, pathwayStartNs: pathwayStartMs * 1e6, edgeStartNs: edgeStartMs * 1e6 }
52
60
  }
53
61
 
62
+ function decodePathwayContextBase64 (pathwayContext) {
63
+ if (pathwayContext == null || pathwayContext.length < 8) {
64
+ return
65
+ }
66
+ if (Buffer.isBuffer(pathwayContext)) {
67
+ pathwayContext = pathwayContext.toString()
68
+ }
69
+ const encodedPathway = Buffer.from(pathwayContext, 'base64')
70
+ return decodePathwayContext(encodedPathway)
71
+ }
72
+
73
+ class DsmPathwayCodec {
74
+ // we use a class for encoding / decoding in case we update our encoding/decoding. A class will make updates easier
75
+ // instead of using individual functions.
76
+ static encode (dataStreamsContext, carrier) {
77
+ if (!dataStreamsContext || !dataStreamsContext.hash) {
78
+ return
79
+ }
80
+ carrier[CONTEXT_PROPAGATION_KEY_BASE64] = encodePathwayContextBase64(dataStreamsContext)
81
+ }
82
+
83
+ static decode (carrier) {
84
+ if (carrier == null) return
85
+
86
+ let ctx
87
+ if (CONTEXT_PROPAGATION_KEY_BASE64 in carrier) {
88
+ // decode v2 encoding of base64
89
+ ctx = decodePathwayContextBase64(carrier[CONTEXT_PROPAGATION_KEY_BASE64])
90
+ } else if (CONTEXT_PROPAGATION_KEY in carrier) {
91
+ try {
92
+ // decode v1 encoding
93
+ ctx = decodePathwayContext(carrier[CONTEXT_PROPAGATION_KEY])
94
+ } catch {
95
+ // pass
96
+ }
97
+ // cover case where base64 context was received under wrong key
98
+ if (!ctx) ctx = decodePathwayContextBase64(carrier[CONTEXT_PROPAGATION_KEY])
99
+ }
100
+ return ctx
101
+ }
102
+
103
+ static contextExists (carrier) {
104
+ return CONTEXT_PROPAGATION_KEY_BASE64 in carrier || CONTEXT_PROPAGATION_KEY in carrier
105
+ }
106
+ }
107
+
54
108
  module.exports = {
55
109
  computePathwayHash: computeHash,
56
110
  encodePathwayContext,
57
- decodePathwayContext
111
+ decodePathwayContext,
112
+ encodePathwayContextBase64,
113
+ decodePathwayContextBase64,
114
+ DsmPathwayCodec
58
115
  }
@@ -4,7 +4,7 @@ const pkg = require('../../../../package.json')
4
4
  const Uint64 = require('int64-buffer').Uint64BE
5
5
 
6
6
  const { LogCollapsingLowestDenseDDSketch } = require('@datadog/sketches-js')
7
- const { encodePathwayContext } = require('./pathway')
7
+ const { DsmPathwayCodec } = require('./pathway')
8
8
  const { DataStreamsWriter } = require('./writer')
9
9
  const { computePathwayHash } = require('./pathway')
10
10
  const { types } = require('util')
@@ -13,7 +13,6 @@ const { PATHWAY_HASH } = require('../../../../ext/tags')
13
13
  const ENTRY_PARENT_HASH = Buffer.from('0000000000000000', 'hex')
14
14
 
15
15
  const HIGH_ACCURACY_DISTRIBUTION = 0.0075
16
- const CONTEXT_PROPAGATION_KEY = 'dd-pathway-ctx'
17
16
 
18
17
  class StatsPoint {
19
18
  constructor (hash, parentHash, edgeTags) {
@@ -285,7 +284,7 @@ class DataStreamsProcessor {
285
284
  // Add the header for this now, as the callee doesn't have access to context when producing
286
285
  // - 1 to account for extra byte for {
287
286
  const ddInfoContinued = {}
288
- ddInfoContinued[CONTEXT_PROPAGATION_KEY] = encodePathwayContext(dataStreamsContext).toJSON()
287
+ DsmPathwayCodec.encode(dataStreamsContext, ddInfoContinued)
289
288
  payloadSize += getSizeOrZero(JSON.stringify(ddInfoContinued)) - 1
290
289
  }
291
290
  const checkpoint = {
@@ -364,6 +363,5 @@ module.exports = {
364
363
  getHeadersSize,
365
364
  getSizeOrZero,
366
365
  getAmqpMessageSize,
367
- ENTRY_PARENT_HASH,
368
- CONTEXT_PROPAGATION_KEY
366
+ ENTRY_PARENT_HASH
369
367
  }
@@ -108,7 +108,6 @@ function extractTags (trace, span) {
108
108
 
109
109
  for (const tag in tags) {
110
110
  switch (tag) {
111
- case 'operation.name':
112
111
  case 'service.name':
113
112
  case 'span.type':
114
113
  case 'resource.name':
@@ -87,7 +87,7 @@ const registerLambdaHook = () => {
87
87
  const lambdaTaskRoot = process.env.LAMBDA_TASK_ROOT
88
88
  const originalLambdaHandler = process.env.DD_LAMBDA_HANDLER
89
89
 
90
- if (originalLambdaHandler !== undefined) {
90
+ if (originalLambdaHandler !== undefined && lambdaTaskRoot !== undefined) {
91
91
  const [moduleRoot, moduleAndHandler] = _extractModuleRootAndHandler(originalLambdaHandler)
92
92
  const [_module] = _extractModuleNameAndHandlerPath(moduleAndHandler)
93
93
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const pick = require('../../../../utils/src/pick')
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')
@@ -171,6 +171,14 @@ class TextMapPropagator {
171
171
  carrier[traceparentKey] = spanContext.toTraceparent()
172
172
 
173
173
  ts.forVendor('dd', state => {
174
+ if (!spanContext._isRemote) {
175
+ // SpanContext was created by a ddtrace span.
176
+ // Last datadog span id should be set to the current span.
177
+ state.set('p', spanContext._spanId)
178
+ } else if (spanContext._trace.tags['_dd.parent_id']) {
179
+ // Propagate the last Datadog span id set on the remote span.
180
+ state.set('p', spanContext._trace.tags['_dd.parent_id'])
181
+ }
174
182
  state.set('s', priority)
175
183
  if (mechanism) {
176
184
  state.set('t.dm', `-${mechanism}`)
@@ -279,7 +287,8 @@ class TextMapPropagator {
279
287
  return new DatadogSpanContext({
280
288
  traceId: id(),
281
289
  spanId: null,
282
- sampling: { priority }
290
+ sampling: { priority },
291
+ isRemote: true
283
292
  })
284
293
  }
285
294
 
@@ -327,6 +336,7 @@ class TextMapPropagator {
327
336
  const spanContext = new DatadogSpanContext({
328
337
  traceId: id(traceId, 16),
329
338
  spanId: id(spanId, 16),
339
+ isRemote: true,
330
340
  sampling: { priority: parseInt(flags, 10) & 1 ? 1 : 0 },
331
341
  traceparent,
332
342
  tracestate
@@ -337,6 +347,10 @@ class TextMapPropagator {
337
347
  tracestate.forVendor('dd', state => {
338
348
  for (const [key, value] of state.entries()) {
339
349
  switch (key) {
350
+ case 'p': {
351
+ spanContext._trace.tags['_dd.parent_id'] = value
352
+ break
353
+ }
340
354
  case 's': {
341
355
  const priority = parseInt(value, 10)
342
356
  if (!Number.isInteger(priority)) continue
@@ -367,6 +381,10 @@ class TextMapPropagator {
367
381
  }
368
382
  })
369
383
 
384
+ if (!spanContext._trace.tags['_dd.parent_id']) {
385
+ spanContext._trace.tags['_dd.parent_id'] = '0000000000000000'
386
+ }
387
+
370
388
  this._extractBaggageItems(carrier, spanContext)
371
389
  return spanContext
372
390
  }
@@ -379,7 +397,8 @@ class TextMapPropagator {
379
397
 
380
398
  return new DatadogSpanContext({
381
399
  traceId: id(carrier[traceKey], radix),
382
- spanId: id(carrier[spanKey], radix)
400
+ spanId: id(carrier[spanKey], radix),
401
+ isRemote: true
383
402
  })
384
403
  }
385
404
 
@@ -266,6 +266,8 @@ class DatadogSpan {
266
266
  if (startTime) {
267
267
  spanContext._trace.startTime = startTime
268
268
  }
269
+ // SpanContext was NOT propagated from a remote parent
270
+ spanContext._isRemote = false
269
271
 
270
272
  return spanContext
271
273
  }
@@ -11,6 +11,7 @@ class DatadogSpanContext {
11
11
 
12
12
  this._traceId = props.traceId
13
13
  this._spanId = props.spanId
14
+ this._isRemote = props.isRemote ?? true
14
15
  this._parentId = props.parentId || null
15
16
  this._name = props.name
16
17
  this._isFinished = props.isFinished || false
@@ -52,12 +52,13 @@ const TEST_SKIPPED_BY_ITR = 'test.skipped_by_itr'
52
52
  const TEST_CONFIGURATION_BROWSER_NAME = 'test.configuration.browser_name'
53
53
  // Early flake detection
54
54
  const TEST_IS_NEW = 'test.is_new'
55
- const TEST_EARLY_FLAKE_IS_RETRY = 'test.early_flake.is_retry'
55
+ const TEST_IS_RETRY = 'test.is_retry'
56
56
  const TEST_EARLY_FLAKE_IS_ENABLED = 'test.early_flake.is_enabled'
57
57
 
58
58
  const CI_APP_ORIGIN = 'ciapp-test'
59
59
 
60
60
  const JEST_TEST_RUNNER = 'test.jest.test_runner'
61
+ const JEST_DISPLAY_NAME = 'test.jest.display_name'
61
62
 
62
63
  const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
63
64
  const TEST_ITR_SKIPPING_ENABLED = 'test.itr.tests_skipping.enabled'
@@ -83,6 +84,7 @@ module.exports = {
83
84
  TEST_FRAMEWORK,
84
85
  TEST_FRAMEWORK_VERSION,
85
86
  JEST_TEST_RUNNER,
87
+ JEST_DISPLAY_NAME,
86
88
  TEST_TYPE,
87
89
  TEST_NAME,
88
90
  TEST_SUITE,
@@ -99,7 +101,7 @@ module.exports = {
99
101
  TEST_SKIPPED_BY_ITR,
100
102
  TEST_CONFIGURATION_BROWSER_NAME,
101
103
  TEST_IS_NEW,
102
- TEST_EARLY_FLAKE_IS_RETRY,
104
+ TEST_IS_RETRY,
103
105
  TEST_EARLY_FLAKE_IS_ENABLED,
104
106
  getTestEnvironmentMetadata,
105
107
  getTestParametersString,
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const uniq = require('../../../../utils/src/uniq')
3
+ const uniq = require('../../../../datadog-core/src/utils/src/uniq')
4
4
  const analyticsSampler = require('../../analytics_sampler')
5
5
  const FORMAT_HTTP_HEADERS = 'http_headers'
6
6
  const log = require('../../log')
@@ -1,5 +1,6 @@
1
1
  'use strict'
2
2
 
3
+ const RateLimiter = require('./rate_limiter')
3
4
  const Sampler = require('./sampler')
4
5
  const { setSamplingRules } = require('./startup-log')
5
6
  const SamplingRule = require('./sampling_rule')
@@ -43,6 +44,7 @@ class PrioritySampler {
43
44
  configure (env, { sampleRate, rateLimit = 100, rules = [] } = {}) {
44
45
  this._env = env
45
46
  this._rules = this._normalizeRules(rules, sampleRate, rateLimit)
47
+ this._limiter = new RateLimiter(rateLimit)
46
48
 
47
49
  setSamplingRules(this._rules)
48
50
  }
@@ -136,14 +138,17 @@ class PrioritySampler {
136
138
  context._trace[SAMPLING_RULE_DECISION] = rule.sampleRate
137
139
  context._sampling.mechanism = SAMPLING_MECHANISM_RULE
138
140
 
139
- const sampled = rule.sample()
140
- const priority = sampled ? USER_KEEP : USER_REJECT
141
+ return rule.sample() && this._isSampledByRateLimit(context)
142
+ ? USER_KEEP
143
+ : USER_REJECT
144
+ }
141
145
 
142
- if (sampled) {
143
- context._trace[SAMPLING_LIMIT_DECISION] = rule.effectiveRate
144
- }
146
+ _isSampledByRateLimit (context) {
147
+ const allowed = this._limiter.isAllowed()
148
+
149
+ context._trace[SAMPLING_LIMIT_DECISION] = this._limiter.effectiveRate()
145
150
 
146
- return priority
151
+ return allowed
147
152
  }
148
153
 
149
154
  _getPriorityByAgent (context) {
@@ -9,6 +9,8 @@ const docker = require('../../exporters/common/docker')
9
9
  const FormData = require('../../exporters/common/form-data')
10
10
  const { storage } = require('../../../../datadog-core')
11
11
  const version = require('../../../../../package.json').version
12
+ const os = require('os')
13
+ const perf = require('perf_hooks').performance
12
14
 
13
15
  const containerId = docker.id()
14
16
 
@@ -50,7 +52,7 @@ function computeRetries (uploadTimeout) {
50
52
  }
51
53
 
52
54
  class AgentExporter {
53
- constructor ({ url, logger, uploadTimeout } = {}) {
55
+ constructor ({ url, logger, uploadTimeout, env, host, service, version } = {}) {
54
56
  this._url = url
55
57
  this._logger = logger
56
58
 
@@ -58,6 +60,10 @@ class AgentExporter {
58
60
 
59
61
  this._backoffTime = backoffTime
60
62
  this._backoffTries = backoffTries
63
+ this._env = env
64
+ this._host = host
65
+ this._service = service
66
+ this._appVersion = version
61
67
  }
62
68
 
63
69
  export ({ profiles, start, end, tags }) {
@@ -83,7 +89,37 @@ class AgentExporter {
83
89
  `profiler_version:${version}`,
84
90
  'format:pprof',
85
91
  ...Object.entries(tags).map(([key, value]) => `${key}:${value}`)
86
- ].join(',')
92
+ ].join(','),
93
+ info: {
94
+ application: {
95
+ env: this._env,
96
+ service: this._service,
97
+ start_time: new Date(perf.nodeTiming.nodeStart + perf.timeOrigin).toISOString(),
98
+ version: this._appVersion
99
+ },
100
+ platform: {
101
+ hostname: this._host,
102
+ kernel_name: os.type(),
103
+ kernel_release: os.release(),
104
+ kernel_version: os.version()
105
+ },
106
+ profiler: {
107
+ version
108
+ },
109
+ runtime: {
110
+ // Using `nodejs` for consistency with the existing `runtime` tag.
111
+ // Note that the event `family` property uses `node`, as that's what's
112
+ // proscribed by the Intake API, but that's an internal enum and is
113
+ // not customer visible.
114
+ engine: 'nodejs',
115
+ // strip off leading 'v'. This makes the format consistent with other
116
+ // runtimes (e.g. Ruby) but not with the existing `runtime_version` tag.
117
+ // We'll keep it like this as we want cross-engine consistency. We
118
+ // also aren't changing the format of the existing tag as we don't want
119
+ // to break it.
120
+ version: process.version.substring(1)
121
+ }
122
+ }
87
123
  })
88
124
 
89
125
  fields.push(['event', event, {
@@ -20,6 +20,7 @@ let heartbeatTimeout
20
20
  let heartbeatInterval
21
21
  let extendedInterval
22
22
  let integrations
23
+ let configWithOrigin = []
23
24
  let retryData = null
24
25
  const extendedHeartbeatPayload = {}
25
26
 
@@ -96,23 +97,6 @@ function getProducts (config) {
96
97
  return products
97
98
  }
98
99
 
99
- function flatten (input, result = [], prefix = [], traversedObjects = null) {
100
- traversedObjects = traversedObjects || new WeakSet()
101
- if (traversedObjects.has(input)) {
102
- return
103
- }
104
- traversedObjects.add(input)
105
- for (const [key, value] of Object.entries(input)) {
106
- if (typeof value === 'object' && value !== null) {
107
- flatten(value, result, [...prefix, key], traversedObjects)
108
- } else {
109
- // TODO: add correct origin value
110
- result.push({ name: [...prefix, key].join('.'), value, origin: 'unknown' })
111
- }
112
- }
113
- return result
114
- }
115
-
116
100
  function getInstallSignature (config) {
117
101
  const { installSignature: sig } = config
118
102
  if (sig && (sig.id || sig.time || sig.type)) {
@@ -127,7 +111,7 @@ function getInstallSignature (config) {
127
111
  function appStarted (config) {
128
112
  const app = {
129
113
  products: getProducts(config),
130
- configuration: flatten(config)
114
+ configuration: configWithOrigin
131
115
  }
132
116
  const installSignature = getInstallSignature(config)
133
117
  if (installSignature) {
@@ -305,44 +289,59 @@ function updateIntegrations () {
305
289
  sendData(config, application, host, reqType, payload, updateRetryData)
306
290
  }
307
291
 
292
+ function formatMapForTelemetry (map) {
293
+ // format from an object to a string map in order for
294
+ // telemetry intake to accept the configuration
295
+ return map
296
+ ? Object.entries(map).map(([key, value]) => `${key}:${value}`).join(',')
297
+ : ''
298
+ }
299
+
308
300
  function updateConfig (changes, config) {
309
301
  if (!config.telemetry.enabled) return
310
302
  if (changes.length === 0) return
311
303
 
312
- // Hack to make system tests happy until we ship telemetry v2
313
- if (process.env.DD_INTERNAL_TELEMETRY_V2_ENABLED !== '1') return
314
-
315
304
  const application = createAppObject(config)
316
305
  const host = createHostObject()
317
306
 
318
- const names = {
307
+ const nameMapping = {
319
308
  sampleRate: 'DD_TRACE_SAMPLE_RATE',
320
309
  logInjection: 'DD_LOG_INJECTION',
321
310
  headerTags: 'DD_TRACE_HEADER_TAGS',
322
311
  tags: 'DD_TAGS'
323
312
  }
324
313
 
314
+ const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping'])
315
+
325
316
  const configuration = []
317
+ const names = [] // list of config names whose values have been changed
326
318
 
327
319
  for (const change of changes) {
328
- if (!names.hasOwnProperty(change.name)) continue
329
-
330
- const name = names[change.name]
320
+ const name = nameMapping[change.name] || change.name
321
+ names.push(name)
331
322
  const { origin, value } = change
332
- const entry = { name, origin, value }
323
+ const entry = { name, value, origin }
333
324
 
334
- if (Array.isArray(value)) {
335
- entry.value = value.join(',')
336
- } else if (name === 'DD_TAGS') {
337
- entry.value = Object.entries(value).map(([key, value]) => `${key}:${value}`)
338
- }
325
+ if (Array.isArray(value)) entry.value = value.join(',')
326
+ if (namesNeedFormatting.has(entry.name)) entry.value = formatMapForTelemetry(entry.value)
327
+ if (entry.name === 'url' && entry.value) entry.value = entry.value.toString()
339
328
 
340
329
  configuration.push(entry)
341
330
  }
342
331
 
343
- const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
332
+ function isNotModified (entry) {
333
+ return !names.includes(entry.name)
334
+ }
344
335
 
345
- sendData(config, application, host, reqType, payload, updateRetryData)
336
+ if (!configWithOrigin.length) {
337
+ configWithOrigin = configuration
338
+ } else {
339
+ // update configWithOrigin to contain up-to-date full list of config values for app-extended-heartbeat
340
+ configWithOrigin = configWithOrigin.filter(isNotModified)
341
+ configWithOrigin = configWithOrigin.concat(configuration)
342
+ const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
343
+ sendData(config, application, host, reqType, payload, updateRetryData)
344
+ }
346
345
  }
347
346
 
348
347
  module.exports = {
@@ -8,7 +8,7 @@ const { isError } = require('./util')
8
8
  const { setStartupLogConfig } = require('./startup-log')
9
9
  const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../../dd-trace/src/constants')
10
10
  const { DataStreamsProcessor } = require('./datastreams/processor')
11
- const { decodePathwayContext } = require('./datastreams/pathway')
11
+ const { DsmPathwayCodec } = require('./datastreams/pathway')
12
12
  const { DD_MAJOR } = require('../../../version')
13
13
  const DataStreamsContext = require('./data_streams_context')
14
14
 
@@ -39,8 +39,8 @@ class DatadogTracer extends Tracer {
39
39
  return ctx
40
40
  }
41
41
 
42
- decodeDataStreamsContext (data) {
43
- const ctx = decodePathwayContext(data)
42
+ decodeDataStreamsContext (carrier) {
43
+ const ctx = DsmPathwayCodec.decode(carrier)
44
44
  // we erase the previous context everytime we decode a new one
45
45
  DataStreamsContext.setDataStreamsContext(ctx)
46
46
  return ctx
package/register.js ADDED
@@ -0,0 +1,4 @@
1
+ const { register } = require('node:module')
2
+ const { pathToFileURL } = require('node:url')
3
+
4
+ register('./loader-hook.mjs', pathToFileURL(__filename))