dd-trace 5.85.0 → 5.86.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 (39) hide show
  1. package/index.d.ts +20 -1
  2. package/package.json +1 -1
  3. package/packages/datadog-core/src/storage.js +30 -12
  4. package/packages/datadog-instrumentations/src/jest.js +34 -9
  5. package/packages/datadog-instrumentations/src/mocha/main.js +9 -0
  6. package/packages/datadog-instrumentations/src/prisma.js +225 -30
  7. package/packages/datadog-instrumentations/src/ws.js +22 -0
  8. package/packages/datadog-plugin-cucumber/src/index.js +4 -10
  9. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +5 -1
  10. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -4
  11. package/packages/datadog-plugin-http/src/server.js +23 -8
  12. package/packages/datadog-plugin-jest/src/index.js +29 -10
  13. package/packages/datadog-plugin-jest/src/util.js +7 -1
  14. package/packages/datadog-plugin-mocha/src/index.js +5 -17
  15. package/packages/datadog-plugin-playwright/src/index.js +3 -0
  16. package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +37 -14
  17. package/packages/datadog-plugin-prisma/src/index.js +8 -5
  18. package/packages/datadog-plugin-router/src/index.js +28 -19
  19. package/packages/datadog-plugin-vitest/src/index.js +6 -10
  20. package/packages/datadog-plugin-ws/src/server.js +8 -0
  21. package/packages/dd-trace/src/appsec/iast/path-line.js +1 -0
  22. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
  23. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +19 -0
  24. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +15 -0
  25. package/packages/dd-trace/src/ci-visibility/telemetry.js +36 -0
  26. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +44 -1
  27. package/packages/dd-trace/src/exporters/common/request.js +35 -35
  28. package/packages/dd-trace/src/id.js +1 -1
  29. package/packages/dd-trace/src/lambda/context.js +27 -0
  30. package/packages/dd-trace/src/lambda/handler.js +5 -18
  31. package/packages/dd-trace/src/log/writer.js +1 -5
  32. package/packages/dd-trace/src/plugins/ci_plugin.js +63 -1
  33. package/packages/dd-trace/src/plugins/util/git.js +27 -30
  34. package/packages/dd-trace/src/plugins/util/test.js +3 -1
  35. package/packages/dd-trace/src/plugins/util/web.js +1 -0
  36. package/packages/dd-trace/src/profiling/config.js +6 -14
  37. package/packages/dd-trace/src/profiling/exporters/agent.js +23 -24
  38. package/packages/dd-trace/src/profiling/profiler.js +2 -0
  39. package/packages/dd-trace/src/startup-log.js +1 -0
@@ -17,6 +17,22 @@ const formattedTags = {
17
17
  isRum: 'is_rum',
18
18
  browserDriver: 'browser_driver',
19
19
  autoInjected: 'auto_injected',
20
+ isQuarantined: 'is_quarantined',
21
+ isDisabled: 'is_disabled',
22
+ isTestManagementEnabled: 'test_management_enabled',
23
+ isItrEnabled: 'itr_enabled',
24
+ isEarlyFlakeDetectionEnabled: 'early_flake_detection_enabled',
25
+ isFlakyTestRetriesEnabled: 'flaky_test_retries_enabled',
26
+ isKnownTestsEnabled: 'known_tests_enabled',
27
+ isImpactedTestsEnabled: 'impacted_tests_enabled',
28
+ hasFailedTestReplay: 'has_failed_test_replay',
29
+ isFailedTestReplayEnabled: 'is_failed_test_replay_enabled',
30
+ // isDiEnabled is specifically for the settings endpoint telemetry
31
+ isDiEnabled: 'failed_test_replay_enabled',
32
+ requireGit: 'require_git',
33
+ isModified: 'is_modified',
34
+ isRetry: 'is_retry',
35
+ retryReason: 'retry_reason',
20
36
  }
21
37
 
22
38
  // Transform tags dictionary to array of strings.
@@ -101,6 +117,17 @@ const TELEMETRY_KNOWN_TESTS_MS = 'early_flake_detection.request_ms'
101
117
  const TELEMETRY_KNOWN_TESTS_ERRORS = 'early_flake_detection.request_errors'
102
118
  const TELEMETRY_KNOWN_TESTS_RESPONSE_TESTS = 'early_flake_detection.response_tests'
103
119
  const TELEMETRY_KNOWN_TESTS_RESPONSE_BYTES = 'early_flake_detection.response_bytes'
120
+ // coverage upload
121
+ const TELEMETRY_COVERAGE_UPLOAD = 'coverage_upload.request'
122
+ const TELEMETRY_COVERAGE_UPLOAD_MS = 'coverage_upload.request_ms'
123
+ const TELEMETRY_COVERAGE_UPLOAD_ERRORS = 'coverage_upload.request_errors'
124
+ const TELEMETRY_COVERAGE_UPLOAD_BYTES = 'coverage_upload.request_bytes'
125
+ // test management
126
+ const TELEMETRY_TEST_MANAGEMENT_TESTS = 'test_management_tests.request'
127
+ const TELEMETRY_TEST_MANAGEMENT_TESTS_MS = 'test_management_tests.request_ms'
128
+ const TELEMETRY_TEST_MANAGEMENT_TESTS_ERRORS = 'test_management_tests.request_errors'
129
+ const TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_TESTS = 'test_management_tests.response_tests'
130
+ const TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_BYTES = 'test_management_tests.response_bytes'
104
131
 
105
132
  function isStatusCode400 (statusCode) {
106
133
  return statusCode >= 400 && statusCode < 500
@@ -165,4 +192,13 @@ module.exports = {
165
192
  TELEMETRY_KNOWN_TESTS_ERRORS,
166
193
  TELEMETRY_KNOWN_TESTS_RESPONSE_TESTS,
167
194
  TELEMETRY_KNOWN_TESTS_RESPONSE_BYTES,
195
+ TELEMETRY_COVERAGE_UPLOAD,
196
+ TELEMETRY_COVERAGE_UPLOAD_MS,
197
+ TELEMETRY_COVERAGE_UPLOAD_ERRORS,
198
+ TELEMETRY_COVERAGE_UPLOAD_BYTES,
199
+ TELEMETRY_TEST_MANAGEMENT_TESTS,
200
+ TELEMETRY_TEST_MANAGEMENT_TESTS_MS,
201
+ TELEMETRY_TEST_MANAGEMENT_TESTS_ERRORS,
202
+ TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_TESTS,
203
+ TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_BYTES,
168
204
  }
@@ -5,6 +5,38 @@ const id = require('../../id')
5
5
  const { getValueFromEnvSources } = require('../../config/helper')
6
6
  const log = require('../../log')
7
7
 
8
+ const {
9
+ incrementCountMetric,
10
+ distributionMetric,
11
+ TELEMETRY_TEST_MANAGEMENT_TESTS,
12
+ TELEMETRY_TEST_MANAGEMENT_TESTS_MS,
13
+ TELEMETRY_TEST_MANAGEMENT_TESTS_ERRORS,
14
+ TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_TESTS,
15
+ TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_BYTES,
16
+ } = require('../telemetry')
17
+
18
+ // Calculate the number of tests from the test management tests response, which has a shape like:
19
+ // { module: { suites: { suite: { tests: { testName: { properties: {...} } } } } } }
20
+ function getNumFromTestManagementTests (testManagementTests) {
21
+ if (!testManagementTests) {
22
+ return 0
23
+ }
24
+
25
+ let totalNumTests = 0
26
+
27
+ for (const testModule of Object.values(testManagementTests)) {
28
+ const { suites } = testModule
29
+ if (!suites) continue
30
+ for (const testSuite of Object.values(suites)) {
31
+ const { tests } = testSuite
32
+ if (!tests) continue
33
+ totalNumTests += Object.keys(tests).length
34
+ }
35
+ }
36
+
37
+ return totalNumTests
38
+ }
39
+
8
40
  function getTestManagementTests ({
9
41
  url,
10
42
  isEvpProxy,
@@ -58,13 +90,24 @@ function getTestManagementTests ({
58
90
 
59
91
  log.debug('Requesting test management tests: %s', data)
60
92
 
61
- request(data, options, (err, res) => {
93
+ incrementCountMetric(TELEMETRY_TEST_MANAGEMENT_TESTS)
94
+
95
+ const startTime = Date.now()
96
+
97
+ request(data, options, (err, res, statusCode) => {
98
+ distributionMetric(TELEMETRY_TEST_MANAGEMENT_TESTS_MS, {}, Date.now() - startTime)
62
99
  if (err) {
100
+ incrementCountMetric(TELEMETRY_TEST_MANAGEMENT_TESTS_ERRORS, { statusCode })
63
101
  done(err)
64
102
  } else {
65
103
  try {
66
104
  const { data: { attributes: { modules: testManagementTests } } } = JSON.parse(res)
67
105
 
106
+ const numTests = getNumFromTestManagementTests(testManagementTests)
107
+
108
+ distributionMetric(TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_TESTS, {}, numTests)
109
+ distributionMetric(TELEMETRY_TEST_MANAGEMENT_TESTS_RESPONSE_BYTES, {}, res.length)
110
+
68
111
  log.debug('Test management tests received: %j', testManagementTests)
69
112
 
70
113
  done(null, testManagementTests)
@@ -128,50 +128,50 @@ function request (data, options, callback) {
128
128
 
129
129
  activeRequests++
130
130
 
131
- const store = storage('legacy').getStore()
132
- storage('legacy').enterWith({ noop: true })
133
-
134
- let finished = false
135
- const finalize = () => {
136
- if (finished) return
137
- finished = true
138
- activeRequests--
139
- }
131
+ storage('legacy').run({ noop: true }, () => {
132
+ let finished = false
133
+ const finalize = () => {
134
+ if (finished) return
135
+ finished = true
136
+ activeRequests--
137
+ }
140
138
 
141
- const req = client.request(options, (res) => onResponse(res, finalize))
139
+ const req = client.request(options, (res) => onResponse(res, finalize))
142
140
 
143
- req.once('close', finalize)
144
- req.once('timeout', finalize)
141
+ req.once('close', finalize)
142
+ req.once('timeout', finalize)
145
143
 
146
- req.once('error', err => {
147
- finalize()
148
- onError(err)
149
- })
144
+ req.once('error', err => {
145
+ finalize()
146
+ onError(err)
147
+ })
150
148
 
151
- req.setTimeout(timeout, () => {
152
- try {
153
- if (typeof req.abort === 'function') {
154
- req.abort()
155
- } else {
156
- req.destroy()
149
+ req.setTimeout(timeout, () => {
150
+ try {
151
+ if (typeof req.abort === 'function') {
152
+ req.abort()
153
+ } else {
154
+ req.destroy()
155
+ }
156
+ } catch {
157
+ // ignore
157
158
  }
158
- } catch {
159
- // ignore
159
+ })
160
+
161
+ if (isReadable) {
162
+ data.pipe(req) // TODO: Validate whether this is actually retriable.
163
+ } else {
164
+ for (const buffer of dataArray) req.write(buffer)
165
+ req.end()
160
166
  }
161
167
  })
162
-
163
- if (isReadable) {
164
- data.pipe(req) // TODO: Validate whether this is actually retriable.
165
- } else {
166
- for (const buffer of dataArray) req.write(buffer)
167
- req.end()
168
- }
169
-
170
- storage('legacy').enterWith(store)
171
168
  }
172
169
 
173
- // TODO: Figure out why setTimeout is needed to avoid losing the async context
174
- // in the retry request before socket.connect() is called.
170
+ // The setTimeout is needed to avoid losing the async context in the retry
171
+ // request before socket.connect() is called. This is a workaround for the
172
+ // issue that the AsyncLocalStorage.run() method does not call the
173
+ // AsyncLocalStorage.enterWith() method when not using AsyncContextFrame.
174
+ //
175
175
  // TODO: Test that this doesn't trace itself on retry when the diagnostics
176
176
  // channel events are available in the agent exporter.
177
177
  makeRequest(() => setTimeout(() => makeRequest(callback)))
@@ -243,5 +243,5 @@ function writeUInt32BE (buffer, value, offset) {
243
243
  * @returns {Identifier}
244
244
  */
245
245
  module.exports = function createIdentifier (value, radix) {
246
- return new Identifier(value, radix)
246
+ return new Identifier(value ?? '', radix)
247
247
  }
@@ -0,0 +1,27 @@
1
+ 'use strict'
2
+
3
+ const log = require('../log')
4
+
5
+ /**
6
+ * Extracts the context from the given Lambda handler arguments.
7
+ *
8
+ * It is possible for users to define a lambda function without specifying a
9
+ * context arg. In these cases, this function returns null instead of throwing
10
+ * an error.
11
+ *
12
+ * @param {unknown[]} args any amount of arguments
13
+ * @returns {object | null}
14
+ */
15
+ exports.extractContext = function extractContext (args) {
16
+ let context = null
17
+ for (let i = 0; i < args.length && i < 3; i++) {
18
+ if (args[i] && typeof args[i].getRemainingTimeInMillis === 'function') {
19
+ context = args[i]
20
+ break
21
+ }
22
+ }
23
+ if (!context) {
24
+ log.debug('Unable to extract context object from Lambda handler arguments')
25
+ }
26
+ return context
27
+ }
@@ -5,6 +5,7 @@ const { channel } = require('../../../datadog-instrumentations/src/helpers/instr
5
5
  const { ERROR_MESSAGE, ERROR_TYPE } = require('../constants')
6
6
  const { getValueFromEnvSources } = require('../config/helper')
7
7
  const { ImpendingTimeout } = require('./runtime/errors')
8
+ const { extractContext } = require('./context')
8
9
 
9
10
  const globalTracer = global._ddtrace
10
11
  const tracer = globalTracer._tracer
@@ -60,23 +61,6 @@ function crashFlush () {
60
61
  }
61
62
  }
62
63
 
63
- /**
64
- * Extracts the context from the given Lambda handler arguments.
65
- *
66
- * @param {unknown[]} args any amount of arguments
67
- * @returns the context, if extraction was succesful.
68
- */
69
- function extractContext (args) {
70
- let context = args.length > 1 ? args[1] : undefined
71
- if (context === undefined || context.getRemainingTimeInMillis === undefined) {
72
- context = args.length > 2 ? args[2] : undefined
73
- if (context === undefined || context.getRemainingTimeInMillis === undefined) {
74
- throw new Error('Could not extract context')
75
- }
76
- }
77
- return context
78
- }
79
-
80
64
  /**
81
65
  * Patches your AWS Lambda handler function to add some tracing support.
82
66
  *
@@ -86,7 +70,10 @@ exports.datadog = function datadog (lambdaHandler) {
86
70
  return (...args) => {
87
71
  const context = extractContext(args)
88
72
 
89
- checkTimeout(context)
73
+ if (context) {
74
+ checkTimeout(context)
75
+ }
76
+
90
77
  const result = lambdaHandler.apply(this, args)
91
78
  if (result && typeof result.then === 'function') {
92
79
  return result.then((res) => {
@@ -14,11 +14,7 @@ let logger = defaultLogger
14
14
  let logChannel = new LogChannel()
15
15
 
16
16
  function withNoop (fn) {
17
- const store = storage('legacy').getStore()
18
-
19
- storage('legacy').enterWith({ noop: true })
20
- fn()
21
- storage('legacy').enterWith(store)
17
+ storage('legacy').run({ noop: true }, fn)
22
18
  }
23
19
 
24
20
  function unsubscribeAll () {
@@ -64,6 +64,14 @@ const {
64
64
  getModifiedFilesFromDiff,
65
65
  getPullRequestBaseBranch,
66
66
  TEST_IS_TEST_FRAMEWORK_WORKER,
67
+ TEST_IS_NEW,
68
+ TEST_IS_RUM_ACTIVE,
69
+ TEST_BROWSER_DRIVER,
70
+ TEST_MANAGEMENT_IS_QUARANTINED,
71
+ TEST_MANAGEMENT_IS_DISABLED,
72
+ TEST_IS_MODIFIED,
73
+ TEST_IS_RETRY,
74
+ TEST_RETRY_REASON,
67
75
  } = require('./util/test')
68
76
 
69
77
  const FRAMEWORK_TO_TRIMMED_COMMAND = {
@@ -354,12 +362,50 @@ module.exports = class CiPlugin extends Plugin {
354
362
 
355
363
  get telemetry () {
356
364
  const testFramework = this.constructor.id
365
+ const exporter = this.tracer?._exporter
366
+ // TODO: only jest worker supported yet
367
+ const isSupportedWorker = exporter && typeof exporter.exportTelemetry === 'function'
368
+ const ciProviderName = this.ciProviderName
369
+
370
+ if (isSupportedWorker) {
371
+ // In supported worker: send telemetry events to main process
372
+ return {
373
+ ciVisEvent: function (name, testLevel, tags = {}) {
374
+ exporter.exportTelemetry({
375
+ type: 'ciVisEvent',
376
+ name,
377
+ testLevel,
378
+ testFramework,
379
+ isUnsupportedCIProvider: !ciProviderName,
380
+ tags,
381
+ })
382
+ },
383
+ count: function (name, tags, value = 1) {
384
+ exporter.exportTelemetry({
385
+ type: 'count',
386
+ name,
387
+ tags,
388
+ value,
389
+ })
390
+ },
391
+ distribution: function (name, tags, measure) {
392
+ exporter.exportTelemetry({
393
+ type: 'distribution',
394
+ name,
395
+ tags,
396
+ measure,
397
+ })
398
+ },
399
+ }
400
+ }
401
+
402
+ // In main process or unsupported worker: execute telemetry directly
357
403
  return {
358
404
  ciVisEvent: function (name, testLevel, tags = {}) {
359
405
  incrementCountMetric(name, {
360
406
  testLevel,
361
407
  testFramework,
362
- isUnsupportedCIProvider: !this.ciProviderName,
408
+ isUnsupportedCIProvider: !ciProviderName,
363
409
  ...tags,
364
410
  })
365
411
  },
@@ -669,4 +715,20 @@ module.exports = class CiPlugin extends Plugin {
669
715
 
670
716
  uploadNextReport()
671
717
  }
718
+
719
+ getTestTelemetryTags (testSpan) {
720
+ const activeSpanTags = testSpan.context()._tags
721
+ return {
722
+ hasCodeOwners: !!activeSpanTags[TEST_CODE_OWNERS] || undefined,
723
+ isNew: activeSpanTags[TEST_IS_NEW] === 'true' || undefined,
724
+ isRum: activeSpanTags[TEST_IS_RUM_ACTIVE] === 'true' || undefined,
725
+ browserDriver: activeSpanTags[TEST_BROWSER_DRIVER],
726
+ isQuarantined: activeSpanTags[TEST_MANAGEMENT_IS_QUARANTINED] === 'true' || undefined,
727
+ isDisabled: activeSpanTags[TEST_MANAGEMENT_IS_DISABLED] === 'true' || undefined,
728
+ isModified: activeSpanTags[TEST_IS_MODIFIED] === 'true' || undefined,
729
+ isRetry: activeSpanTags[TEST_IS_RETRY] === 'true' || undefined,
730
+ retryReason: activeSpanTags[TEST_RETRY_REASON],
731
+ isFailedTestReplayEnabled: activeSpanTags[DI_ERROR_DEBUG_INFO_CAPTURED] === 'true' || undefined,
732
+ }
733
+ }
672
734
  }
@@ -47,40 +47,37 @@ function sanitizedExec (
47
47
  errorMetric,
48
48
  shouldTrim = true
49
49
  ) {
50
- const store = storage('legacy').getStore()
51
- storage('legacy').enterWith({ noop: true })
52
-
53
- let startTime
54
- if (operationMetric) {
55
- incrementCountMetric(operationMetric.name, operationMetric.tags)
56
- }
57
- if (durationMetric) {
58
- startTime = Date.now()
59
- }
60
- try {
61
- let result = cachedExec(cmd, flags, { stdio: 'pipe' }).toString()
62
-
63
- if (shouldTrim) {
64
- result = result.replaceAll(/(\r\n|\n|\r)/gm, '')
50
+ return storage('legacy').run({ noop: true }, () => {
51
+ let startTime
52
+ if (operationMetric) {
53
+ incrementCountMetric(operationMetric.name, operationMetric.tags)
65
54
  }
66
-
67
55
  if (durationMetric) {
68
- distributionMetric(durationMetric.name, durationMetric.tags, Date.now() - startTime)
56
+ startTime = Date.now()
69
57
  }
70
- return result
71
- } catch (err) {
72
- if (errorMetric) {
73
- incrementCountMetric(errorMetric.name, {
74
- ...errorMetric.tags,
75
- errorType: err.code,
76
- exitCode: err.status || err.errno,
77
- })
58
+ try {
59
+ let result = cachedExec(cmd, flags, { stdio: 'pipe' }).toString()
60
+
61
+ if (shouldTrim) {
62
+ result = result.replaceAll(/(\r\n|\n|\r)/gm, '')
63
+ }
64
+
65
+ if (durationMetric) {
66
+ distributionMetric(durationMetric.name, durationMetric.tags, Date.now() - startTime)
67
+ }
68
+ return result
69
+ } catch (err) {
70
+ if (errorMetric) {
71
+ incrementCountMetric(errorMetric.name, {
72
+ ...errorMetric.tags,
73
+ errorType: err.code,
74
+ exitCode: err.status || err.errno,
75
+ })
76
+ }
77
+ log.error('Git plugin error executing command', err)
78
+ return ''
78
79
  }
79
- log.error('Git plugin error executing command', err)
80
- return ''
81
- } finally {
82
- storage('legacy').enterWith(store)
83
- }
80
+ })
84
81
  }
85
82
 
86
83
  function isDirectory (path) {
@@ -119,6 +119,7 @@ const TEST_BROWSER_VERSION = 'test.browser.version'
119
119
  const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
120
120
  const JEST_WORKER_COVERAGE_PAYLOAD_CODE = 61
121
121
  const JEST_WORKER_LOGS_PAYLOAD_CODE = 62
122
+ const JEST_WORKER_TELEMETRY_PAYLOAD_CODE = 63
122
123
 
123
124
  // cucumber worker variables
124
125
  const CUCUMBER_WORKER_TRACE_PAYLOAD_CODE = 70
@@ -225,6 +226,7 @@ module.exports = {
225
226
  JEST_WORKER_TRACE_PAYLOAD_CODE,
226
227
  JEST_WORKER_COVERAGE_PAYLOAD_CODE,
227
228
  JEST_WORKER_LOGS_PAYLOAD_CODE,
229
+ JEST_WORKER_TELEMETRY_PAYLOAD_CODE,
228
230
  CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
229
231
  MOCHA_WORKER_TRACE_PAYLOAD_CODE,
230
232
  PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE,
@@ -573,7 +575,7 @@ function getTestSuitePath (testSuiteAbsolutePath, sourceRoot) {
573
575
  ? testSuiteAbsolutePath
574
576
  : path.relative(sourceRoot, testSuiteAbsolutePath)
575
577
 
576
- return testSuitePath.replace(path.sep, '/')
578
+ return testSuitePath.replaceAll(path.sep, '/')
577
579
  }
578
580
 
579
581
  const POSSIBLE_CODEOWNERS_LOCATIONS = [
@@ -54,6 +54,7 @@ function startSpanHelper (tracer, name, options, traceCtx, config = {}) {
54
54
 
55
55
  const web = {
56
56
  TYPE: WEB,
57
+ /** @type {TracingPlugin | null} */
57
58
  plugin: null,
58
59
 
59
60
  // Ensure the configuration has the correct structure and defaults.
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
- const os = require('os')
4
3
  const path = require('path')
5
4
  const { pathToFileURL } = require('url')
5
+
6
6
  const satisfies = require('../../../../vendor/dist/semifies')
7
7
  const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
8
8
  const { getIsAzureFunction } = require('../serverless')
@@ -10,6 +10,8 @@ const { isFalse, isTrue } = require('../util')
10
10
  const { getAzureTagsFromMetadata, getAzureAppMetadata, getAzureFunctionMetadata } = require('../azure_metadata')
11
11
  const { getEnvironmentVariable, getValueFromEnvSources } = require('../config/helper')
12
12
  const { getAgentUrl } = require('../agent/url')
13
+ const { isACFActive } = require('../../../datadog-core/src/storage')
14
+
13
15
  const { AgentExporter } = require('./exporters/agent')
14
16
  const { FileExporter } = require('./exporters/file')
15
17
  const { ConsoleLogger } = require('./loggers/console')
@@ -18,12 +20,12 @@ const SpaceProfiler = require('./profilers/space')
18
20
  const EventsProfiler = require('./profilers/events')
19
21
  const { oomExportStrategies, snapshotKinds } = require('./constants')
20
22
  const { tagger } = require('./tagger')
23
+
21
24
  class Config {
22
25
  constructor (options = {}) {
23
26
  // TODO: Remove entries that were already resolved in config.
24
27
  // For the others, move them over to config.
25
28
  const AWS_LAMBDA_FUNCTION_NAME = getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME')
26
- const NODE_OPTIONS = getEnvironmentVariable('NODE_OPTIONS')
27
29
 
28
30
  // TODO: Move initialization of these values to packages/dd-trace/src/config/index.js, and just read from config
29
31
  const {
@@ -50,7 +52,6 @@ class Config {
50
52
  DD_TAGS,
51
53
  } = getProfilingEnvValues()
52
54
 
53
- const host = os.hostname()
54
55
  // Must be longer than one minute so pad with five seconds
55
56
  const flushInterval = options.interval ?? (Number(DD_PROFILING_UPLOAD_PERIOD) * 1000 || 65 * 1000)
56
57
  const uploadTimeout = options.uploadTimeout ?? (Number(DD_PROFILING_UPLOAD_TIMEOUT) || 60 * 1000)
@@ -59,7 +60,6 @@ class Config {
59
60
  // TODO: Remove the fallback. Just use the value from the config.
60
61
  this.service = options.service || 'node'
61
62
  this.env = options.env
62
- this.host = host
63
63
  this.functionname = AWS_LAMBDA_FUNCTION_NAME
64
64
 
65
65
  this.version = options.version
@@ -68,7 +68,7 @@ class Config {
68
68
  tagger.parse(options.tags),
69
69
  tagger.parse({
70
70
  env: options.env,
71
- host,
71
+ host: options.reportHostname ? require('os').hostname() : undefined,
72
72
  service: this.service,
73
73
  version: this.version,
74
74
  functionname: AWS_LAMBDA_FUNCTION_NAME,
@@ -219,16 +219,8 @@ class Config {
219
219
  that.asyncContextFrameEnabled = false
220
220
  }
221
221
 
222
- const hasExecArg = (arg) => process.execArgv.includes(arg) || String(NODE_OPTIONS).includes(arg)
222
+ const canUseAsyncContextFrame = samplingContextsAvailable && isACFActive
223
223
 
224
- let canUseAsyncContextFrame = false
225
- if (samplingContextsAvailable) {
226
- if (isAtLeast24) {
227
- canUseAsyncContextFrame = !hasExecArg('--no-async-context-frame')
228
- } else if (satisfies(process.versions.node, '>=22.9.0')) {
229
- canUseAsyncContextFrame = hasExecArg('--experimental-async-context-frame')
230
- }
231
- }
232
224
  this.asyncContextFrameEnabled = isTrue(DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED ?? canUseAsyncContextFrame)
233
225
  if (this.asyncContextFrameEnabled && !canUseAsyncContextFrame) {
234
226
  if (!samplingContextsAvailable) {
@@ -38,32 +38,31 @@ function countStatusCode (statusCode) {
38
38
  function sendRequest (options, form, callback) {
39
39
  const request = options.protocol === 'https:' ? httpsRequest : httpRequest
40
40
 
41
- const store = storage('legacy').getStore()
42
- storage('legacy').enterWith({ noop: true })
43
- requestCounter.inc()
44
- const start = perf.now()
45
- const req = request(options, res => {
46
- durationDistribution.track(perf.now() - start)
47
- countStatusCode(res.statusCode)
48
- if (res.statusCode >= 400) {
49
- statusCodeErrorCounter.inc()
50
- const error = new Error(`HTTP Error ${res.statusCode}`)
51
- error.status = res.statusCode
52
- callback(error)
53
- } else {
54
- callback(null, res)
55
- }
56
- })
41
+ storage('legacy').run({ noop: true }, () => {
42
+ requestCounter.inc()
43
+ const start = perf.now()
44
+ const req = request(options, res => {
45
+ durationDistribution.track(perf.now() - start)
46
+ countStatusCode(res.statusCode)
47
+ if (res.statusCode >= 400) {
48
+ statusCodeErrorCounter.inc()
49
+ const error = new Error(`HTTP Error ${res.statusCode}`)
50
+ error.status = res.statusCode
51
+ callback(error)
52
+ } else {
53
+ callback(null, res)
54
+ }
55
+ })
57
56
 
58
- req.on('error', (err) => {
59
- networkErrorCounter.inc()
60
- callback(err)
57
+ req.on('error', (err) => {
58
+ networkErrorCounter.inc()
59
+ callback(err)
60
+ })
61
+ if (form) {
62
+ sizeDistribution.track(form.size())
63
+ form.pipe(req)
64
+ }
61
65
  })
62
- if (form) {
63
- sizeDistribution.track(form.size())
64
- form.pipe(req)
65
- }
66
- storage('legacy').enterWith(store)
67
66
  }
68
67
 
69
68
  function getBody (stream, callback) {
@@ -76,6 +76,7 @@ class Profiler extends EventEmitter {
76
76
  repositoryUrl,
77
77
  commitSHA,
78
78
  injectionEnabled,
79
+ reportHostname,
79
80
  } = config
80
81
  const { enabled, sourceMap, exporters } = config.profiling
81
82
  const { heartbeatInterval } = config.telemetry
@@ -112,6 +113,7 @@ class Profiler extends EventEmitter {
112
113
  libraryInjected,
113
114
  activation,
114
115
  heartbeatInterval,
116
+ reportHostname,
115
117
  }
116
118
 
117
119
  return this._start(options).catch((err) => {
@@ -75,6 +75,7 @@ function tracerInfo () {
75
75
  profiling_enabled: config.profiling?.enabled === 'true' || config.profiling?.enabled === 'auto',
76
76
  integrations_loaded: Object.keys(pluginManager._pluginsByName),
77
77
  appsec_enabled: !!config.appsec.enabled,
78
+ data_streams_enabled: !!config.dsmEnabled,
78
79
  }
79
80
 
80
81
  return out