dd-trace 5.67.0 → 5.68.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/LICENSE-3rdparty.csv +0 -3
- package/README.md +0 -2
- package/ci/init.js +52 -54
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +47 -2
- package/initialize.mjs +1 -1
- package/package.json +8 -11
- package/packages/datadog-esbuild/index.js +56 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +42 -4
- package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
- package/packages/datadog-instrumentations/src/azure-service-bus.js +1 -1
- package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
- package/packages/datadog-instrumentations/src/connect.js +6 -2
- package/packages/datadog-instrumentations/src/cucumber.js +31 -6
- package/packages/datadog-instrumentations/src/express.js +5 -6
- package/packages/datadog-instrumentations/src/fastify.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/hook.js +28 -15
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +11 -2
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -3
- package/packages/datadog-instrumentations/src/http2/client.js +1 -0
- package/packages/datadog-instrumentations/src/http2/server.js +0 -1
- package/packages/datadog-instrumentations/src/ioredis.js +12 -1
- package/packages/datadog-instrumentations/src/jest.js +48 -36
- package/packages/datadog-instrumentations/src/limitd-client.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +15 -7
- package/packages/datadog-instrumentations/src/mocha/utils.js +3 -0
- package/packages/datadog-instrumentations/src/mongoose.js +2 -1
- package/packages/datadog-instrumentations/src/oracledb.js +19 -13
- package/packages/datadog-instrumentations/src/pg.js +9 -5
- package/packages/datadog-instrumentations/src/pino.js +18 -6
- package/packages/datadog-instrumentations/src/playwright.js +15 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +155 -62
- package/packages/datadog-plugin-ai/src/tracing.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +23 -8
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +101 -2
- package/packages/datadog-plugin-aws-sdk/src/util.js +1 -1
- package/packages/datadog-plugin-cucumber/src/index.js +4 -56
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -2
- package/packages/datadog-plugin-cypress/src/support.js +4 -0
- package/packages/datadog-plugin-express/src/code_origin.js +2 -2
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -2
- package/packages/datadog-plugin-jest/src/index.js +0 -21
- package/packages/datadog-plugin-mocha/src/index.js +3 -57
- package/packages/datadog-plugin-mongodb-core/src/index.js +20 -7
- package/packages/datadog-plugin-playwright/src/index.js +11 -5
- package/packages/datadog-plugin-vitest/src/index.js +5 -1
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-plugin-ws/src/producer.js +6 -1
- package/packages/datadog-plugin-ws/src/receiver.js +6 -1
- package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +1 -1
- package/packages/dd-trace/src/appsec/telemetry/waf.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -4
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +11 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +10 -1
- package/packages/dd-trace/src/config.js +69 -304
- package/packages/dd-trace/src/config_defaults.js +186 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -1
- package/packages/dd-trace/src/datastreams/fnv.js +2 -2
- package/packages/dd-trace/src/datastreams/writer.js +3 -2
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
- package/packages/dd-trace/src/dogstatsd.js +4 -3
- package/packages/dd-trace/src/encode/0.4.js +1 -5
- package/packages/dd-trace/src/exporter.js +1 -0
- package/packages/dd-trace/src/exporters/agent/index.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +2 -1
- package/packages/dd-trace/src/exporters/span-stats/index.js +3 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +4 -3
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -1
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +40 -13
- package/packages/dd-trace/src/llmobs/plugins/openai.js +7 -1
- package/packages/dd-trace/src/llmobs/tagger.js +8 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
- package/packages/dd-trace/src/log/index.js +28 -17
- package/packages/dd-trace/src/log/log.js +29 -5
- package/packages/dd-trace/src/log/writer.js +5 -5
- package/packages/dd-trace/src/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentracing/span.js +18 -4
- package/packages/dd-trace/src/plugin_manager.js +20 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +97 -3
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/util/git-cache.js +129 -0
- package/packages/dd-trace/src/plugins/util/git.js +40 -26
- package/packages/dd-trace/src/plugins/util/test.js +37 -27
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/profiler.js +4 -1
- package/packages/dd-trace/src/profiling/config.js +73 -42
- package/packages/dd-trace/src/profiling/profiler.js +3 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -8
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -0
- package/packages/dd-trace/src/profiling/profilers/wall.js +196 -117
- package/packages/dd-trace/src/remote_config/capabilities.js +5 -0
- package/packages/dd-trace/src/remote_config/manager.js +3 -2
- package/packages/dd-trace/src/startup-log.js +2 -1
- package/packages/dd-trace/src/supported-configurations.json +3 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/register.js +1 -1
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const cp = require('child_process')
|
|
4
3
|
const os = require('os')
|
|
5
4
|
const path = require('path')
|
|
6
5
|
const fs = require('fs')
|
|
@@ -36,6 +35,7 @@ const {
|
|
|
36
35
|
} = require('../../ci-visibility/telemetry')
|
|
37
36
|
const { filterSensitiveInfoFromRepository } = require('./url')
|
|
38
37
|
const { storage } = require('../../../../datadog-core')
|
|
38
|
+
const { cachedExec } = require('./git-cache')
|
|
39
39
|
|
|
40
40
|
const GIT_REV_LIST_MAX_BUFFER = 12 * 1024 * 1024 // 12MB
|
|
41
41
|
|
|
@@ -58,10 +58,12 @@ function sanitizedExec (
|
|
|
58
58
|
startTime = Date.now()
|
|
59
59
|
}
|
|
60
60
|
try {
|
|
61
|
-
let result =
|
|
61
|
+
let result = cachedExec(cmd, flags, { stdio: 'pipe' }).toString()
|
|
62
|
+
|
|
62
63
|
if (shouldTrim) {
|
|
63
64
|
result = result.replaceAll(/(\r\n|\n|\r)/gm, '')
|
|
64
65
|
}
|
|
66
|
+
|
|
65
67
|
if (durationMetric) {
|
|
66
68
|
distributionMetric(durationMetric.name, durationMetric.tags, Date.now() - startTime)
|
|
67
69
|
}
|
|
@@ -94,7 +96,7 @@ function isGitAvailable () {
|
|
|
94
96
|
const isWindows = os.platform() === 'win32'
|
|
95
97
|
const command = isWindows ? 'where' : 'which'
|
|
96
98
|
try {
|
|
97
|
-
|
|
99
|
+
cachedExec(command, ['git'])
|
|
98
100
|
return true
|
|
99
101
|
} catch {
|
|
100
102
|
incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'check_git', exitCode: 'missing' })
|
|
@@ -150,27 +152,32 @@ function unshallowRepository (parentOnly = false) {
|
|
|
150
152
|
|
|
151
153
|
incrementCountMetric(TELEMETRY_GIT_COMMAND, { command: 'unshallow' })
|
|
152
154
|
const start = Date.now()
|
|
155
|
+
let flags = [
|
|
156
|
+
...baseGitOptions,
|
|
157
|
+
revParseHead
|
|
158
|
+
]
|
|
153
159
|
try {
|
|
154
|
-
|
|
155
|
-
...baseGitOptions,
|
|
156
|
-
revParseHead
|
|
157
|
-
], { stdio: 'pipe' })
|
|
160
|
+
cachedExec('git', flags)
|
|
158
161
|
} catch (err) {
|
|
159
162
|
// If the local HEAD is a commit that has not been pushed to the remote, the above command will fail.
|
|
160
|
-
log.
|
|
163
|
+
log.warn(`Git unshallow failed: ${flags.join(' ')}`)
|
|
161
164
|
incrementCountMetric(
|
|
162
165
|
TELEMETRY_GIT_COMMAND_ERRORS,
|
|
163
166
|
{ command: 'unshallow', errorType: err.code, exitCode: err.status || err.errno }
|
|
164
167
|
)
|
|
165
|
-
const upstreamRemote = sanitizedExec(
|
|
168
|
+
const upstreamRemote = sanitizedExec(
|
|
169
|
+
'git',
|
|
170
|
+
['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}']
|
|
171
|
+
)
|
|
172
|
+
flags = [
|
|
173
|
+
...baseGitOptions,
|
|
174
|
+
upstreamRemote
|
|
175
|
+
]
|
|
166
176
|
try {
|
|
167
|
-
|
|
168
|
-
...baseGitOptions,
|
|
169
|
-
upstreamRemote
|
|
170
|
-
], { stdio: 'pipe' })
|
|
177
|
+
cachedExec('git', flags)
|
|
171
178
|
} catch (err) {
|
|
172
|
-
// If the CI is working on a detached HEAD or branch tracking hasn
|
|
173
|
-
log.
|
|
179
|
+
// If the CI is working on a detached HEAD or branch tracking hasn't been set up, the above command will fail.
|
|
180
|
+
log.warn(`Git unshallow failed again: ${flags.join(' ')}`)
|
|
174
181
|
incrementCountMetric(
|
|
175
182
|
TELEMETRY_GIT_COMMAND_ERRORS,
|
|
176
183
|
{ command: 'unshallow', errorType: err.code, exitCode: err.status || err.errno }
|
|
@@ -202,7 +209,7 @@ function getLatestCommits () {
|
|
|
202
209
|
incrementCountMetric(TELEMETRY_GIT_COMMAND, { command: 'get_local_commits' })
|
|
203
210
|
const startTime = Date.now()
|
|
204
211
|
try {
|
|
205
|
-
const result =
|
|
212
|
+
const result = cachedExec('git', ['log', '--format=%H', '-n 1000', '--since="1 month ago"'])
|
|
206
213
|
.toString()
|
|
207
214
|
.split('\n')
|
|
208
215
|
.filter(Boolean)
|
|
@@ -272,10 +279,9 @@ function checkAndFetchBranch (branch, remoteName) {
|
|
|
272
279
|
try {
|
|
273
280
|
// `git show-ref --verify --quiet refs/remotes/${remoteName}/${branch}` will exit 0 if the branch exists
|
|
274
281
|
// Otherwise it will exit 1
|
|
275
|
-
|
|
282
|
+
cachedExec(
|
|
276
283
|
'git',
|
|
277
284
|
['show-ref', '--verify', '--quiet', `refs/remotes/${remoteName}/${branch}`],
|
|
278
|
-
{ stdio: 'pipe' }
|
|
279
285
|
)
|
|
280
286
|
// branch exists locally, so we finish
|
|
281
287
|
} catch {
|
|
@@ -285,22 +291,22 @@ function checkAndFetchBranch (branch, remoteName) {
|
|
|
285
291
|
// `git ls-remote --heads origin my-branch` will exit 0 even if the branch doesn't exist.
|
|
286
292
|
// The piece of information we need is whether the command outputs anything.
|
|
287
293
|
// `git ls-remote --heads origin my-branch` could exit an error code if the remote does not exist.
|
|
288
|
-
const remoteHeads =
|
|
294
|
+
const remoteHeads = cachedExec(
|
|
289
295
|
'git',
|
|
290
296
|
['ls-remote', '--heads', remoteName, branch],
|
|
291
297
|
{ stdio: 'pipe', timeout: 2000 }
|
|
292
298
|
)
|
|
293
299
|
if (remoteHeads) {
|
|
294
300
|
// branch exists, so we'll fetch it
|
|
295
|
-
|
|
301
|
+
cachedExec(
|
|
296
302
|
'git',
|
|
297
303
|
['fetch', '--depth', '1', remoteName, branch],
|
|
298
304
|
{ stdio: 'pipe', timeout: 5000 }
|
|
299
305
|
)
|
|
300
306
|
}
|
|
301
|
-
} catch (
|
|
307
|
+
} catch (err) {
|
|
302
308
|
// branch does not exist or couldn't be fetched, so we can't do anything
|
|
303
|
-
log.
|
|
309
|
+
log.debug('Git plugin error checking and fetching branch', err)
|
|
304
310
|
}
|
|
305
311
|
}
|
|
306
312
|
}
|
|
@@ -358,7 +364,7 @@ function getCommitsRevList (commitsToExclude, commitsToInclude) {
|
|
|
358
364
|
incrementCountMetric(TELEMETRY_GIT_COMMAND, { command: 'get_objects' })
|
|
359
365
|
const startTime = Date.now()
|
|
360
366
|
try {
|
|
361
|
-
result =
|
|
367
|
+
result = cachedExec(
|
|
362
368
|
'git',
|
|
363
369
|
[
|
|
364
370
|
'rev-list',
|
|
@@ -403,7 +409,7 @@ function generatePackFilesForCommits (commitsToUpload) {
|
|
|
403
409
|
// Generates pack files to upload and
|
|
404
410
|
// returns the ordered list of packfiles' paths
|
|
405
411
|
function execGitPackObjects (targetPath) {
|
|
406
|
-
return
|
|
412
|
+
return cachedExec(
|
|
407
413
|
'git',
|
|
408
414
|
[
|
|
409
415
|
'pack-objects',
|
|
@@ -450,6 +456,13 @@ function generatePackFilesForCommits (commitsToUpload) {
|
|
|
450
456
|
return result
|
|
451
457
|
}
|
|
452
458
|
|
|
459
|
+
function getRepositoryRoot () {
|
|
460
|
+
return sanitizedExec(
|
|
461
|
+
'git',
|
|
462
|
+
['rev-parse', '--show-toplevel']
|
|
463
|
+
)
|
|
464
|
+
}
|
|
465
|
+
|
|
453
466
|
// If there is ciMetadata, it takes precedence.
|
|
454
467
|
function getGitMetadata (ciMetadata) {
|
|
455
468
|
const {
|
|
@@ -480,7 +493,7 @@ function getGitMetadata (ciMetadata) {
|
|
|
480
493
|
commitMessage || sanitizedExec('git', ['show', '-s', '--format=%B'], null, null, null, false),
|
|
481
494
|
[GIT_BRANCH]: branch || sanitizedExec('git', ['rev-parse', '--abbrev-ref', 'HEAD']),
|
|
482
495
|
[GIT_COMMIT_SHA]: commitSHA || sanitizedExec('git', ['rev-parse', 'HEAD']),
|
|
483
|
-
[CI_WORKSPACE_PATH]: ciWorkspacePath ||
|
|
496
|
+
[CI_WORKSPACE_PATH]: ciWorkspacePath || getRepositoryRoot(),
|
|
484
497
|
}
|
|
485
498
|
|
|
486
499
|
if (headCommitSha) {
|
|
@@ -596,5 +609,6 @@ module.exports = {
|
|
|
596
609
|
getLocalBranches,
|
|
597
610
|
getMergeBase,
|
|
598
611
|
getCounts,
|
|
599
|
-
fetchHeadCommitSha
|
|
612
|
+
fetchHeadCommitSha,
|
|
613
|
+
getRepositoryRoot
|
|
600
614
|
}
|
|
@@ -119,6 +119,10 @@ const MOCHA_WORKER_TRACE_PAYLOAD_CODE = 80
|
|
|
119
119
|
// playwright worker variables
|
|
120
120
|
const PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE = 90
|
|
121
121
|
|
|
122
|
+
// vitest worker variables
|
|
123
|
+
const VITEST_WORKER_TRACE_PAYLOAD_CODE = 100
|
|
124
|
+
const VITEST_WORKER_LOGS_PAYLOAD_CODE = 102
|
|
125
|
+
|
|
122
126
|
// Early flake detection util strings
|
|
123
127
|
const EFD_STRING = "Retried by Datadog's Early Flake Detection"
|
|
124
128
|
const EFD_TEST_NAME_REGEX = new RegExp(EFD_STRING + String.raw` \(#\d+\): `, 'g')
|
|
@@ -218,6 +222,8 @@ module.exports = {
|
|
|
218
222
|
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
|
|
219
223
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
220
224
|
PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE,
|
|
225
|
+
VITEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
226
|
+
VITEST_WORKER_LOGS_PAYLOAD_CODE,
|
|
221
227
|
TEST_SOURCE_START,
|
|
222
228
|
TEST_SKIPPED_BY_ITR,
|
|
223
229
|
TEST_IS_NEW,
|
|
@@ -438,36 +444,40 @@ function checkShaDiscrepancies (ciMetadata, userProvidedGitMetadata) {
|
|
|
438
444
|
)
|
|
439
445
|
}
|
|
440
446
|
|
|
441
|
-
function getTestEnvironmentMetadata (testFramework, config) {
|
|
442
|
-
// TODO: eventually these will come from the tracer (generally available)
|
|
447
|
+
function getTestEnvironmentMetadata (testFramework, config, shouldSkipGitMetadataExtraction = false) {
|
|
443
448
|
const ciMetadata = getCIMetadata()
|
|
444
|
-
const {
|
|
445
|
-
[GIT_COMMIT_SHA]: commitSHA,
|
|
446
|
-
[GIT_BRANCH]: branch,
|
|
447
|
-
[GIT_REPOSITORY_URL]: repositoryUrl,
|
|
448
|
-
[GIT_TAG]: tag,
|
|
449
|
-
[GIT_COMMIT_AUTHOR_NAME]: authorName,
|
|
450
|
-
[GIT_COMMIT_AUTHOR_EMAIL]: authorEmail,
|
|
451
|
-
[GIT_COMMIT_MESSAGE]: commitMessage,
|
|
452
|
-
[CI_WORKSPACE_PATH]: ciWorkspacePath,
|
|
453
|
-
[GIT_COMMIT_HEAD_SHA]: headCommitSha
|
|
454
|
-
} = ciMetadata
|
|
455
|
-
|
|
456
|
-
const gitMetadata = getGitMetadata({
|
|
457
|
-
commitSHA,
|
|
458
|
-
branch,
|
|
459
|
-
repositoryUrl,
|
|
460
|
-
tag,
|
|
461
|
-
authorName,
|
|
462
|
-
authorEmail,
|
|
463
|
-
commitMessage,
|
|
464
|
-
ciWorkspacePath,
|
|
465
|
-
headCommitSha
|
|
466
|
-
})
|
|
467
|
-
|
|
468
449
|
const userProvidedGitMetadata = getUserProviderGitMetadata()
|
|
469
450
|
|
|
470
|
-
|
|
451
|
+
let gitMetadata = {}
|
|
452
|
+
|
|
453
|
+
// We don't execute git in test framework workers since the information is in the parent process
|
|
454
|
+
// and git metadata does not affect the execution of the tests
|
|
455
|
+
if (!shouldSkipGitMetadataExtraction) {
|
|
456
|
+
checkShaDiscrepancies(ciMetadata, userProvidedGitMetadata)
|
|
457
|
+
|
|
458
|
+
const {
|
|
459
|
+
[GIT_COMMIT_SHA]: commitSHA,
|
|
460
|
+
[GIT_BRANCH]: branch,
|
|
461
|
+
[GIT_REPOSITORY_URL]: repositoryUrl,
|
|
462
|
+
[GIT_TAG]: tag,
|
|
463
|
+
[GIT_COMMIT_AUTHOR_NAME]: authorName,
|
|
464
|
+
[GIT_COMMIT_AUTHOR_EMAIL]: authorEmail,
|
|
465
|
+
[GIT_COMMIT_MESSAGE]: commitMessage,
|
|
466
|
+
[CI_WORKSPACE_PATH]: ciWorkspacePath,
|
|
467
|
+
[GIT_COMMIT_HEAD_SHA]: headCommitSha
|
|
468
|
+
} = ciMetadata
|
|
469
|
+
gitMetadata = getGitMetadata({
|
|
470
|
+
commitSHA,
|
|
471
|
+
branch,
|
|
472
|
+
repositoryUrl,
|
|
473
|
+
tag,
|
|
474
|
+
authorName,
|
|
475
|
+
authorEmail,
|
|
476
|
+
commitMessage,
|
|
477
|
+
ciWorkspacePath,
|
|
478
|
+
headCommitSha
|
|
479
|
+
})
|
|
480
|
+
}
|
|
471
481
|
|
|
472
482
|
const runtimeAndOSMetadata = getRuntimeAndOSMetadata()
|
|
473
483
|
|
|
@@ -387,7 +387,7 @@ const web = {
|
|
|
387
387
|
|
|
388
388
|
return function (statusCode, statusMessage, headers) {
|
|
389
389
|
headers = typeof statusMessage === 'string' ? headers : statusMessage
|
|
390
|
-
headers =
|
|
390
|
+
headers = { ...res.getHeaders(), ...headers }
|
|
391
391
|
|
|
392
392
|
if (req.method.toLowerCase() === 'options' && isOriginAllowed(req, headers)) {
|
|
393
393
|
addAllowHeaders(req, res, headers)
|
|
@@ -10,6 +10,8 @@ module.exports = {
|
|
|
10
10
|
start: config => {
|
|
11
11
|
const { service, version, env, url, hostname, port, tags, repositoryUrl, commitSHA, injectionEnabled } = config
|
|
12
12
|
const { enabled, sourceMap, exporters } = config.profiling
|
|
13
|
+
const { heartbeatInterval } = config.telemetry
|
|
14
|
+
|
|
13
15
|
const logger = {
|
|
14
16
|
debug: (message) => log.debug(message),
|
|
15
17
|
info: (message) => log.info(message),
|
|
@@ -39,7 +41,8 @@ module.exports = {
|
|
|
39
41
|
repositoryUrl,
|
|
40
42
|
commitSHA,
|
|
41
43
|
libraryInjected,
|
|
42
|
-
activation
|
|
44
|
+
activation,
|
|
45
|
+
heartbeatInterval
|
|
43
46
|
})
|
|
44
47
|
},
|
|
45
48
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const coalesce = require('koalas')
|
|
4
3
|
const os = require('os')
|
|
5
4
|
const path = require('path')
|
|
6
5
|
const { URL, format, pathToFileURL } = require('url')
|
|
6
|
+
const satisfies = require('semifies')
|
|
7
7
|
const { AgentExporter } = require('./exporters/agent')
|
|
8
8
|
const { FileExporter } = require('./exporters/file')
|
|
9
9
|
const { ConsoleLogger } = require('./loggers/console')
|
|
@@ -16,6 +16,7 @@ const { tagger } = require('./tagger')
|
|
|
16
16
|
const { isFalse, isTrue } = require('../util')
|
|
17
17
|
const { getAzureTagsFromMetadata, getAzureAppMetadata } = require('../azure_metadata')
|
|
18
18
|
const { getEnvironmentVariables } = require('../config-helper')
|
|
19
|
+
const defaults = require('../config_defaults')
|
|
19
20
|
|
|
20
21
|
class Config {
|
|
21
22
|
constructor (options = {}) {
|
|
@@ -41,27 +42,26 @@ class Config {
|
|
|
41
42
|
DD_PROFILING_TIMELINE_ENABLED,
|
|
42
43
|
DD_PROFILING_UPLOAD_PERIOD,
|
|
43
44
|
DD_PROFILING_UPLOAD_TIMEOUT,
|
|
45
|
+
DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED,
|
|
44
46
|
DD_PROFILING_V8_PROFILER_BUG_WORKAROUND,
|
|
45
47
|
DD_PROFILING_WALLTIME_ENABLED,
|
|
46
48
|
DD_SERVICE,
|
|
47
49
|
DD_TAGS,
|
|
48
50
|
DD_TRACE_AGENT_PORT,
|
|
49
51
|
DD_TRACE_AGENT_URL,
|
|
50
|
-
DD_VERSION
|
|
52
|
+
DD_VERSION,
|
|
53
|
+
NODE_OPTIONS
|
|
51
54
|
} = getEnvironmentVariables()
|
|
52
55
|
|
|
53
|
-
const env =
|
|
56
|
+
const env = options.env ?? DD_ENV
|
|
54
57
|
const service = options.service || DD_SERVICE || 'node'
|
|
55
58
|
const host = os.hostname()
|
|
56
|
-
const version =
|
|
59
|
+
const version = options.version ?? DD_VERSION
|
|
57
60
|
// Must be longer than one minute so pad with five seconds
|
|
58
|
-
const flushInterval =
|
|
59
|
-
const uploadTimeout =
|
|
60
|
-
|
|
61
|
-
const
|
|
62
|
-
DD_PROFILING_SOURCE_MAP, true)
|
|
63
|
-
const pprofPrefix = coalesce(options.pprofPrefix,
|
|
64
|
-
DD_PROFILING_PPROF_PREFIX, '')
|
|
61
|
+
const flushInterval = options.interval ?? (Number(DD_PROFILING_UPLOAD_PERIOD) * 1000 || 65 * 1000)
|
|
62
|
+
const uploadTimeout = options.uploadTimeout ?? (Number(DD_PROFILING_UPLOAD_TIMEOUT) || 60 * 1000)
|
|
63
|
+
const sourceMap = options.sourceMap ?? DD_PROFILING_SOURCE_MAP ?? true
|
|
64
|
+
const pprofPrefix = options.pprofPrefix ?? DD_PROFILING_PPROF_PREFIX ?? ''
|
|
65
65
|
|
|
66
66
|
this.service = service
|
|
67
67
|
this.env = env
|
|
@@ -104,21 +104,21 @@ class Config {
|
|
|
104
104
|
this.flushInterval = flushInterval
|
|
105
105
|
this.uploadTimeout = uploadTimeout
|
|
106
106
|
this.sourceMap = sourceMap
|
|
107
|
-
this.debugSourceMaps = isTrue(
|
|
108
|
-
this.endpointCollectionEnabled = isTrue(
|
|
109
|
-
DD_PROFILING_ENDPOINT_COLLECTION_ENABLED
|
|
107
|
+
this.debugSourceMaps = isTrue(options.debugSourceMaps ?? DD_PROFILING_DEBUG_SOURCE_MAPS)
|
|
108
|
+
this.endpointCollectionEnabled = isTrue(options.endpointCollection ??
|
|
109
|
+
DD_PROFILING_ENDPOINT_COLLECTION_ENABLED ?? samplingContextsAvailable)
|
|
110
110
|
checkOptionWithSamplingContextAllowed(this.endpointCollectionEnabled, 'Endpoint collection')
|
|
111
111
|
|
|
112
112
|
this.pprofPrefix = pprofPrefix
|
|
113
|
-
this.v8ProfilerBugWorkaroundEnabled = isTrue(
|
|
114
|
-
DD_PROFILING_V8_PROFILER_BUG_WORKAROUND
|
|
115
|
-
const hostname =
|
|
116
|
-
const port =
|
|
117
|
-
this.url = new URL(
|
|
113
|
+
this.v8ProfilerBugWorkaroundEnabled = isTrue(options.v8ProfilerBugWorkaround ??
|
|
114
|
+
DD_PROFILING_V8_PROFILER_BUG_WORKAROUND ?? true)
|
|
115
|
+
const hostname = (options.hostname ?? DD_AGENT_HOST) || defaults.hostname
|
|
116
|
+
const port = (options.port ?? DD_TRACE_AGENT_PORT) || defaults.port
|
|
117
|
+
this.url = new URL(options.url ?? DD_TRACE_AGENT_URL ?? format({
|
|
118
118
|
protocol: 'http:',
|
|
119
119
|
hostname,
|
|
120
120
|
port
|
|
121
|
-
}))
|
|
121
|
+
}))
|
|
122
122
|
|
|
123
123
|
this.libraryInjected = options.libraryInjected
|
|
124
124
|
this.activation = options.activation
|
|
@@ -129,17 +129,17 @@ class Config {
|
|
|
129
129
|
// OOM monitoring does not work well on Windows, so it is disabled by default.
|
|
130
130
|
const oomMonitoringSupported = process.platform !== 'win32'
|
|
131
131
|
|
|
132
|
-
const oomMonitoringEnabled = isTrue(
|
|
133
|
-
DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED
|
|
132
|
+
const oomMonitoringEnabled = isTrue(options.oomMonitoring ??
|
|
133
|
+
DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED ?? oomMonitoringSupported)
|
|
134
134
|
checkOptionAllowed(oomMonitoringEnabled, 'OOM monitoring', oomMonitoringSupported)
|
|
135
135
|
|
|
136
|
-
const heapLimitExtensionSize =
|
|
137
|
-
Number(DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE)
|
|
138
|
-
const maxHeapExtensionCount =
|
|
139
|
-
Number(DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT)
|
|
136
|
+
const heapLimitExtensionSize = options.oomHeapLimitExtensionSize ??
|
|
137
|
+
(Number(DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE) || 0)
|
|
138
|
+
const maxHeapExtensionCount = options.oomMaxHeapExtensionCount ??
|
|
139
|
+
(Number(DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT) || 0)
|
|
140
140
|
const exportStrategies = oomMonitoringEnabled
|
|
141
|
-
? ensureOOMExportStrategies(
|
|
142
|
-
[oomExportStrategies.PROCESS]
|
|
141
|
+
? ensureOOMExportStrategies(options.oomExportStrategies ?? DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES ??
|
|
142
|
+
[oomExportStrategies.PROCESS], this)
|
|
143
143
|
: []
|
|
144
144
|
const exportCommand = oomMonitoringEnabled ? buildExportCommand(this) : undefined
|
|
145
145
|
this.oomMonitoring = {
|
|
@@ -156,26 +156,29 @@ class Config {
|
|
|
156
156
|
DD_PROFILING_PROFILERS
|
|
157
157
|
})
|
|
158
158
|
|
|
159
|
-
this.timelineEnabled = isTrue(
|
|
160
|
-
DD_PROFILING_TIMELINE_ENABLED
|
|
159
|
+
this.timelineEnabled = isTrue(
|
|
160
|
+
options.timelineEnabled ?? DD_PROFILING_TIMELINE_ENABLED ?? samplingContextsAvailable
|
|
161
|
+
)
|
|
161
162
|
checkOptionWithSamplingContextAllowed(this.timelineEnabled, 'Timeline view')
|
|
162
|
-
this.timelineSamplingEnabled = isTrue(
|
|
163
|
-
DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED
|
|
163
|
+
this.timelineSamplingEnabled = isTrue(
|
|
164
|
+
options.timelineSamplingEnabled ?? DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED ?? true
|
|
165
|
+
)
|
|
164
166
|
|
|
165
|
-
this.codeHotspotsEnabled = isTrue(
|
|
166
|
-
DD_PROFILING_CODEHOTSPOTS_ENABLED
|
|
167
|
+
this.codeHotspotsEnabled = isTrue(
|
|
168
|
+
options.codeHotspotsEnabled ?? DD_PROFILING_CODEHOTSPOTS_ENABLED ?? samplingContextsAvailable
|
|
169
|
+
)
|
|
167
170
|
checkOptionWithSamplingContextAllowed(this.codeHotspotsEnabled, 'Code hotspots')
|
|
168
171
|
|
|
169
|
-
this.cpuProfilingEnabled = isTrue(
|
|
170
|
-
DD_PROFILING_CPU_ENABLED
|
|
171
|
-
|
|
172
|
+
this.cpuProfilingEnabled = isTrue(
|
|
173
|
+
options.cpuProfilingEnabled ?? DD_PROFILING_CPU_ENABLED ?? samplingContextsAvailable
|
|
174
|
+
)
|
|
172
175
|
checkOptionWithSamplingContextAllowed(this.cpuProfilingEnabled, 'CPU profiling')
|
|
173
176
|
|
|
174
|
-
this.samplingInterval =
|
|
177
|
+
this.samplingInterval = options.samplingInterval || 1e3 / 99 // 99hz in millis
|
|
175
178
|
|
|
176
|
-
this.heapSamplingInterval =
|
|
177
|
-
Number(DD_PROFILING_HEAP_SAMPLING_INTERVAL))
|
|
178
|
-
const uploadCompression0 =
|
|
179
|
+
this.heapSamplingInterval = options.heapSamplingInterval ??
|
|
180
|
+
(Number(DD_PROFILING_HEAP_SAMPLING_INTERVAL) || 512 * 1024)
|
|
181
|
+
const uploadCompression0 = options.uploadCompression ?? DD_PROFILING_DEBUG_UPLOAD_COMPRESSION ?? 'on'
|
|
179
182
|
let [uploadCompression, level0] = uploadCompression0.split('-')
|
|
180
183
|
if (!['on', 'off', 'gzip', 'zstd'].includes(uploadCompression)) {
|
|
181
184
|
this.logger.warn(`Invalid profile upload compression method "${uploadCompression0}". Will use "on".`)
|
|
@@ -209,6 +212,34 @@ class Config {
|
|
|
209
212
|
|
|
210
213
|
this.uploadCompression = { method: uploadCompression, level }
|
|
211
214
|
|
|
215
|
+
const that = this
|
|
216
|
+
function turnOffAsyncContextFrame (msg) {
|
|
217
|
+
that.logger.warn(
|
|
218
|
+
`DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED was set ${msg}, it will have no effect.`)
|
|
219
|
+
that.asyncContextFrameEnabled = false
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const hasExecArg = (arg) => process.execArgv.includes(arg) || String(NODE_OPTIONS).includes(arg)
|
|
223
|
+
|
|
224
|
+
this.asyncContextFrameEnabled = isTrue(options.useAsyncContextFrame ?? DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED)
|
|
225
|
+
if (this.asyncContextFrameEnabled) {
|
|
226
|
+
if (satisfies(process.versions.node, '>=24.0.0')) {
|
|
227
|
+
if (hasExecArg('--no-async-context-frame')) {
|
|
228
|
+
turnOffAsyncContextFrame('with --no-async-context-frame')
|
|
229
|
+
}
|
|
230
|
+
} else if (satisfies(process.versions.node, '>=23.0.0')) {
|
|
231
|
+
if (!hasExecArg('--experimental-async-context-frame')) {
|
|
232
|
+
turnOffAsyncContextFrame('without --experimental-async-context-frame')
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
// NOTE: technically, this should work starting with 22.7.0 which is when
|
|
236
|
+
// AsyncContextFrame debuted, but it would require a change in pprof-nodejs too.
|
|
237
|
+
turnOffAsyncContextFrame('but it requires at least Node.js 23')
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
this.heartbeatInterval = options.heartbeatInterval || 60 * 1000 // 1 minute
|
|
242
|
+
|
|
212
243
|
this.profilers = ensureProfilers(profilers, this)
|
|
213
244
|
}
|
|
214
245
|
}
|
|
@@ -220,7 +251,7 @@ function getProfilers ({
|
|
|
220
251
|
}) {
|
|
221
252
|
// First consider "legacy" DD_PROFILING_PROFILERS env variable, defaulting to wall + space
|
|
222
253
|
// Use a Set to avoid duplicates
|
|
223
|
-
const profilers = new Set(
|
|
254
|
+
const profilers = new Set((DD_PROFILING_PROFILERS ?? 'wall,space').split(','))
|
|
224
255
|
|
|
225
256
|
// Add/remove wall depending on the value of DD_PROFILING_WALLTIME_ENABLED
|
|
226
257
|
if (DD_PROFILING_WALLTIME_ENABLED != null) {
|
|
@@ -110,11 +110,13 @@ class Profiler extends EventEmitter {
|
|
|
110
110
|
}
|
|
111
111
|
break
|
|
112
112
|
case 'zstd':
|
|
113
|
-
if (typeof zlib.zstdCompress === 'function') {
|
|
113
|
+
if (typeof zlib.zstdCompress === 'function') { // eslint-disable-line n/no-unsupported-features/node-builtins
|
|
114
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
114
115
|
this.#compressionFn = promisify(zlib.zstdCompress)
|
|
115
116
|
if (clevel !== undefined) {
|
|
116
117
|
this.#compressionOptions = {
|
|
117
118
|
params: {
|
|
119
|
+
// eslint-disable-next-line n/no-unsupported-features/node-builtins
|
|
118
120
|
[zlib.constants.ZSTD_c_compressionLevel]: clevel
|
|
119
121
|
}
|
|
120
122
|
}
|
|
@@ -41,14 +41,9 @@ function labelFromStrStr (stringTable, keyStr, valStr) {
|
|
|
41
41
|
return labelFromStr(stringTable, stringTable.dedup(keyStr), valStr)
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function getSamplingIntervalMillis (options) {
|
|
45
|
-
return (options.samplingInterval || 1e3 / 99) // 99Hz
|
|
46
|
-
}
|
|
47
|
-
|
|
48
44
|
function getMaxSamples (options) {
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const maxCpuSamples = flushInterval / cpuSamplingInterval
|
|
45
|
+
const flushInterval = options.flushInterval || 65 * 1e3 // 65 seconds
|
|
46
|
+
const maxCpuSamples = flushInterval / options.samplingInterval
|
|
52
47
|
|
|
53
48
|
// The lesser of max parallelism and libuv thread pool size, plus one so we can detect
|
|
54
49
|
// oversubscription on libuv thread pool, plus another one for GC.
|
|
@@ -399,7 +394,7 @@ class EventsProfiler {
|
|
|
399
394
|
|
|
400
395
|
const eventHandler = event => this.#eventSerializer.addEvent(event)
|
|
401
396
|
const eventFilter = options.timelineSamplingEnabled
|
|
402
|
-
? createPoissonProcessSamplingFilter(
|
|
397
|
+
? createPoissonProcessSamplingFilter(options.samplingInterval)
|
|
403
398
|
: () => true
|
|
404
399
|
const filteringEventHandler = event => {
|
|
405
400
|
if (eventFilter(event)) {
|
|
@@ -13,6 +13,7 @@ class NativeSpaceProfiler {
|
|
|
13
13
|
_started = false
|
|
14
14
|
|
|
15
15
|
constructor (options = {}) {
|
|
16
|
+
// TODO: Remove default value. It is only used in testing.
|
|
16
17
|
this._samplingInterval = options.heapSamplingInterval || 512 * 1024
|
|
17
18
|
this._stackDepth = options.stackDepth || 64
|
|
18
19
|
this._oomMonitoring = options.oomMonitoring || {}
|