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.
- package/index.d.ts +20 -1
- package/package.json +1 -1
- package/packages/datadog-core/src/storage.js +30 -12
- package/packages/datadog-instrumentations/src/jest.js +34 -9
- package/packages/datadog-instrumentations/src/mocha/main.js +9 -0
- package/packages/datadog-instrumentations/src/prisma.js +225 -30
- package/packages/datadog-instrumentations/src/ws.js +22 -0
- package/packages/datadog-plugin-cucumber/src/index.js +4 -10
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +5 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -4
- package/packages/datadog-plugin-http/src/server.js +23 -8
- package/packages/datadog-plugin-jest/src/index.js +29 -10
- package/packages/datadog-plugin-jest/src/util.js +7 -1
- package/packages/datadog-plugin-mocha/src/index.js +5 -17
- package/packages/datadog-plugin-playwright/src/index.js +3 -0
- package/packages/datadog-plugin-prisma/src/datadog-tracing-helper.js +37 -14
- package/packages/datadog-plugin-prisma/src/index.js +8 -5
- package/packages/datadog-plugin-router/src/index.js +28 -19
- package/packages/datadog-plugin-vitest/src/index.js +6 -10
- package/packages/datadog-plugin-ws/src/server.js +8 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +1 -0
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +1 -1
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +19 -0
- package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +15 -0
- package/packages/dd-trace/src/ci-visibility/telemetry.js +36 -0
- package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +44 -1
- package/packages/dd-trace/src/exporters/common/request.js +35 -35
- package/packages/dd-trace/src/id.js +1 -1
- package/packages/dd-trace/src/lambda/context.js +27 -0
- package/packages/dd-trace/src/lambda/handler.js +5 -18
- package/packages/dd-trace/src/log/writer.js +1 -5
- package/packages/dd-trace/src/plugins/ci_plugin.js +63 -1
- package/packages/dd-trace/src/plugins/util/git.js +27 -30
- package/packages/dd-trace/src/plugins/util/test.js +3 -1
- package/packages/dd-trace/src/plugins/util/web.js +1 -0
- package/packages/dd-trace/src/profiling/config.js +6 -14
- package/packages/dd-trace/src/profiling/exporters/agent.js +23 -24
- package/packages/dd-trace/src/profiling/profiler.js +2 -0
- 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
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
139
|
+
const req = client.request(options, (res) => onResponse(res, finalize))
|
|
142
140
|
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
req.once('close', finalize)
|
|
142
|
+
req.once('timeout', finalize)
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
144
|
+
req.once('error', err => {
|
|
145
|
+
finalize()
|
|
146
|
+
onError(err)
|
|
147
|
+
})
|
|
150
148
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
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
|
-
}
|
|
159
|
-
|
|
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
|
-
//
|
|
174
|
-
//
|
|
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)))
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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: !
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
|
|
56
|
+
startTime = Date.now()
|
|
69
57
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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.
|
|
578
|
+
return testSuitePath.replaceAll(path.sep, '/')
|
|
577
579
|
}
|
|
578
580
|
|
|
579
581
|
const POSSIBLE_CODEOWNERS_LOCATIONS = [
|
|
@@ -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
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
59
|
-
|
|
60
|
-
|
|
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
|