dd-trace 5.96.0 → 5.97.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 +34 -0
- package/package.json +9 -7
- package/packages/datadog-esbuild/index.js +20 -9
- package/packages/datadog-instrumentations/src/child_process.js +7 -17
- package/packages/datadog-instrumentations/src/crypto.js +1 -2
- package/packages/datadog-instrumentations/src/cucumber.js +4 -1
- package/packages/datadog-instrumentations/src/cypress-config.js +324 -0
- package/packages/datadog-instrumentations/src/cypress.js +86 -4
- package/packages/datadog-instrumentations/src/dns.js +1 -2
- package/packages/datadog-instrumentations/src/express.js +4 -4
- package/packages/datadog-instrumentations/src/fs.js +27 -29
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
- package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
- package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
- package/packages/datadog-instrumentations/src/http/client.js +2 -3
- package/packages/datadog-instrumentations/src/http/server.js +2 -5
- package/packages/datadog-instrumentations/src/http2/client.js +1 -3
- package/packages/datadog-instrumentations/src/http2/server.js +1 -3
- package/packages/datadog-instrumentations/src/jest.js +13 -4
- package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +4 -1
- package/packages/datadog-instrumentations/src/net.js +2 -8
- package/packages/datadog-instrumentations/src/pino.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +4 -1
- package/packages/datadog-instrumentations/src/prisma.js +1 -2
- package/packages/datadog-instrumentations/src/selenium.js +4 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/url.js +1 -3
- package/packages/datadog-instrumentations/src/vitest.js +5 -1
- package/packages/datadog-instrumentations/src/vm.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +4 -3
- package/packages/datadog-plugin-cucumber/src/index.js +7 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +57 -5
- package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
- package/packages/datadog-plugin-jest/src/index.js +4 -2
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
- package/packages/datadog-plugin-mocha/src/index.js +5 -2
- package/packages/datadog-plugin-next/src/index.js +2 -14
- package/packages/datadog-plugin-openai/src/services.js +1 -0
- package/packages/datadog-webpack/index.js +3 -3
- package/packages/dd-trace/index.js +12 -10
- package/packages/dd-trace/src/agent/url.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +4 -0
- package/packages/dd-trace/src/appsec/blocking.js +3 -0
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config.js +1 -0
- package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/config/defaults.js +316 -146
- package/packages/dd-trace/src/config/generated-config-types.d.ts +4 -1
- package/packages/dd-trace/src/config/helper.js +59 -10
- package/packages/dd-trace/src/config/index.js +569 -1505
- package/packages/dd-trace/src/config/parsers.js +256 -0
- package/packages/dd-trace/src/config/remote_config.js +59 -2
- package/packages/dd-trace/src/config/supported-configurations.json +350 -433
- package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
- package/packages/dd-trace/src/crashtracking/index.js +1 -7
- package/packages/dd-trace/src/debugger/index.js +1 -1
- package/packages/dd-trace/src/dogstatsd.js +12 -9
- package/packages/dd-trace/src/encode/0.4.js +1 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
- package/packages/dd-trace/src/exporters/common/request.js +9 -0
- package/packages/dd-trace/src/exporters/common/writer.js +12 -2
- package/packages/dd-trace/src/heap_snapshots.js +3 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
- package/packages/dd-trace/src/llmobs/index.js +4 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
- package/packages/dd-trace/src/llmobs/sdk.js +12 -8
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +9 -6
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
- package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
- package/packages/dd-trace/src/log/index.js +26 -55
- package/packages/dd-trace/src/log/writer.js +7 -19
- package/packages/dd-trace/src/noop/proxy.js +8 -0
- package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
- package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
- package/packages/dd-trace/src/plugin_manager.js +8 -6
- package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
- package/packages/dd-trace/src/plugins/plugin.js +7 -4
- package/packages/dd-trace/src/process-tags/index.js +3 -0
- package/packages/dd-trace/src/profiler.js +27 -2
- package/packages/dd-trace/src/profiling/config.js +73 -241
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
- package/packages/dd-trace/src/profiling/profiler.js +56 -44
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
- package/packages/dd-trace/src/propagation-hash/index.js +2 -1
- package/packages/dd-trace/src/proxy.js +32 -3
- package/packages/dd-trace/src/remote_config/index.js +3 -0
- package/packages/dd-trace/src/require-package-json.js +8 -4
- package/packages/dd-trace/src/ritm.js +58 -26
- package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +3 -0
- package/packages/dd-trace/src/sampler.js +1 -1
- package/packages/dd-trace/src/standalone/index.js +3 -0
- package/packages/dd-trace/src/telemetry/index.js +2 -3
- package/packages/dd-trace/src/telemetry/send-data.js +5 -19
- package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
- package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
- package/packages/dd-trace/src/util.js +0 -9
|
@@ -6,9 +6,8 @@ const { pathToFileURL } = require('url')
|
|
|
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')
|
|
9
|
-
const { isFalse, isTrue } = require('../util')
|
|
10
9
|
const { getAzureTagsFromMetadata, getAzureAppMetadata, getAzureFunctionMetadata } = require('../azure_metadata')
|
|
11
|
-
const { getEnvironmentVariable
|
|
10
|
+
const { getEnvironmentVariable } = require('../config/helper')
|
|
12
11
|
const { getAgentUrl } = require('../agent/url')
|
|
13
12
|
const { isACFActive } = require('../../../datadog-core/src/storage')
|
|
14
13
|
|
|
@@ -22,59 +21,22 @@ const { oomExportStrategies, snapshotKinds } = require('./constants')
|
|
|
22
21
|
const { tagger } = require('./tagger')
|
|
23
22
|
|
|
24
23
|
class Config {
|
|
25
|
-
constructor (options
|
|
26
|
-
// TODO: Remove entries that were already resolved in config.
|
|
27
|
-
// For the others, move them over to config.
|
|
24
|
+
constructor (options) {
|
|
28
25
|
const AWS_LAMBDA_FUNCTION_NAME = getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME')
|
|
29
26
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED,
|
|
33
|
-
DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED,
|
|
34
|
-
DD_PROFILING_CODEHOTSPOTS_ENABLED,
|
|
35
|
-
DD_PROFILING_CPU_ENABLED,
|
|
36
|
-
DD_PROFILING_DEBUG_SOURCE_MAPS,
|
|
37
|
-
DD_PROFILING_DEBUG_UPLOAD_COMPRESSION,
|
|
38
|
-
DD_PROFILING_ENDPOINT_COLLECTION_ENABLED,
|
|
39
|
-
DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES,
|
|
40
|
-
DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE,
|
|
41
|
-
DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT,
|
|
42
|
-
DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED,
|
|
43
|
-
DD_PROFILING_HEAP_ENABLED,
|
|
44
|
-
DD_PROFILING_HEAP_SAMPLING_INTERVAL,
|
|
45
|
-
DD_PROFILING_PPROF_PREFIX,
|
|
46
|
-
DD_PROFILING_PROFILERS,
|
|
47
|
-
DD_PROFILING_TIMELINE_ENABLED,
|
|
48
|
-
DD_PROFILING_UPLOAD_PERIOD,
|
|
49
|
-
DD_PROFILING_UPLOAD_TIMEOUT,
|
|
50
|
-
DD_PROFILING_V8_PROFILER_BUG_WORKAROUND,
|
|
51
|
-
DD_PROFILING_WALLTIME_ENABLED,
|
|
52
|
-
DD_TAGS,
|
|
53
|
-
} = getProfilingEnvValues()
|
|
54
|
-
|
|
55
|
-
// Must be longer than one minute so pad with five seconds
|
|
56
|
-
const flushInterval = options.interval ?? (Number(DD_PROFILING_UPLOAD_PERIOD) * 1000 || 65 * 1000)
|
|
57
|
-
const uploadTimeout = options.uploadTimeout ?? (Number(DD_PROFILING_UPLOAD_TIMEOUT) || 60 * 1000)
|
|
58
|
-
const pprofPrefix = options.pprofPrefix ?? DD_PROFILING_PPROF_PREFIX ?? ''
|
|
59
|
-
|
|
60
|
-
// TODO: Remove the fallback. Just use the value from the config.
|
|
61
|
-
this.service = options.service || 'node'
|
|
27
|
+
this.version = options.version
|
|
28
|
+
this.service = options.service
|
|
62
29
|
this.env = options.env
|
|
63
30
|
this.functionname = AWS_LAMBDA_FUNCTION_NAME
|
|
64
31
|
|
|
65
|
-
this.
|
|
66
|
-
|
|
67
|
-
tagger.parse(
|
|
68
|
-
tagger.parse(options.tags),
|
|
69
|
-
tagger.parse({
|
|
70
|
-
env: options.env,
|
|
32
|
+
this.tags = {
|
|
33
|
+
...options.tags,
|
|
34
|
+
...tagger.parse({
|
|
71
35
|
host: options.reportHostname ? require('os').hostname() : undefined,
|
|
72
|
-
service: this.service,
|
|
73
|
-
version: this.version,
|
|
74
36
|
functionname: AWS_LAMBDA_FUNCTION_NAME,
|
|
75
37
|
}),
|
|
76
|
-
getAzureTagsFromMetadata(getIsAzureFunction() ? getAzureFunctionMetadata() : getAzureAppMetadata())
|
|
77
|
-
|
|
38
|
+
...getAzureTagsFromMetadata(getIsAzureFunction() ? getAzureFunctionMetadata() : getAzureAppMetadata()),
|
|
39
|
+
}
|
|
78
40
|
|
|
79
41
|
// Add source code integration tags if available
|
|
80
42
|
if (options.repositoryUrl && options.commitSHA) {
|
|
@@ -82,58 +44,35 @@ class Config {
|
|
|
82
44
|
this.tags[GIT_COMMIT_SHA] = options.commitSHA
|
|
83
45
|
}
|
|
84
46
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
// sets an environment variable to its non-default value on the platform.
|
|
94
|
-
// In practical terms, it'd require someone explicitly turning on OOM
|
|
95
|
-
// monitoring, code hotspots, endpoint profiling, or CPU profiling on
|
|
96
|
-
// Windows, where it is not supported.
|
|
97
|
-
throw new Error(`${description} not supported on ${process.platform}.`)
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function checkOptionWithSamplingContextAllowed (option, description) {
|
|
101
|
-
checkOptionAllowed(option, description, samplingContextsAvailable)
|
|
102
|
-
}
|
|
47
|
+
// Normalize from seconds to milliseconds. Default must be longer than a minute.
|
|
48
|
+
this.flushInterval = options.DD_PROFILING_UPLOAD_PERIOD * 1000
|
|
49
|
+
this.uploadTimeout = options.DD_PROFILING_UPLOAD_TIMEOUT
|
|
50
|
+
this.sourceMap = options.DD_PROFILING_SOURCE_MAP
|
|
51
|
+
this.debugSourceMaps = options.DD_PROFILING_DEBUG_SOURCE_MAPS
|
|
52
|
+
this.endpointCollectionEnabled = options.DD_PROFILING_ENDPOINT_COLLECTION_ENABLED
|
|
53
|
+
this.pprofPrefix = options.DD_PROFILING_PPROF_PREFIX
|
|
54
|
+
this.v8ProfilerBugWorkaroundEnabled = options.DD_PROFILING_V8_PROFILER_BUG_WORKAROUND
|
|
103
55
|
|
|
104
|
-
this.
|
|
105
|
-
this.uploadTimeout = uploadTimeout
|
|
106
|
-
this.sourceMap = options.sourceMap
|
|
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
|
-
checkOptionWithSamplingContextAllowed(this.endpointCollectionEnabled, 'Endpoint collection')
|
|
111
|
-
|
|
112
|
-
this.pprofPrefix = pprofPrefix
|
|
113
|
-
this.v8ProfilerBugWorkaroundEnabled = isTrue(options.v8ProfilerBugWorkaround ??
|
|
114
|
-
DD_PROFILING_V8_PROFILER_BUG_WORKAROUND ?? true)
|
|
56
|
+
this.logger = ensureLogger(options.logger)
|
|
115
57
|
this.url = getAgentUrl(options)
|
|
116
58
|
|
|
117
|
-
this.libraryInjected = options.
|
|
118
|
-
this.activation = options.activation
|
|
119
|
-
this.exporters = ensureExporters(options.exporters || [
|
|
120
|
-
new AgentExporter(this),
|
|
121
|
-
], this)
|
|
59
|
+
this.libraryInjected = !!options.DD_INJECTION_ENABLED
|
|
122
60
|
|
|
123
|
-
|
|
124
|
-
|
|
61
|
+
let activation
|
|
62
|
+
if (options.profiling.enabled === 'auto') {
|
|
63
|
+
activation = 'auto'
|
|
64
|
+
} else if (options.profiling.enabled === 'true') {
|
|
65
|
+
activation = 'manual'
|
|
66
|
+
} // else activation = undefined
|
|
125
67
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
checkOptionAllowed(oomMonitoringEnabled, 'OOM monitoring', oomMonitoringSupported)
|
|
68
|
+
this.activation = activation
|
|
69
|
+
this.exporters = ensureExporters(options.DD_PROFILING_EXPORTERS, this)
|
|
129
70
|
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
const maxHeapExtensionCount = options.
|
|
133
|
-
(Number(DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT) || 0)
|
|
71
|
+
const oomMonitoringEnabled = options.DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED
|
|
72
|
+
const heapLimitExtensionSize = options.DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE
|
|
73
|
+
const maxHeapExtensionCount = options.DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT
|
|
134
74
|
const exportStrategies = oomMonitoringEnabled
|
|
135
|
-
? ensureOOMExportStrategies(options.
|
|
136
|
-
[oomExportStrategies.PROCESS], this)
|
|
75
|
+
? ensureOOMExportStrategies(options.DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES, this)
|
|
137
76
|
: []
|
|
138
77
|
const exportCommand = oomMonitoringEnabled ? buildExportCommand(this) : undefined
|
|
139
78
|
this.oomMonitoring = {
|
|
@@ -144,61 +83,26 @@ class Config {
|
|
|
144
83
|
exportCommand,
|
|
145
84
|
}
|
|
146
85
|
|
|
147
|
-
const profilers =
|
|
148
|
-
DD_PROFILING_HEAP_ENABLED,
|
|
149
|
-
DD_PROFILING_WALLTIME_ENABLED,
|
|
150
|
-
DD_PROFILING_PROFILERS,
|
|
151
|
-
})
|
|
86
|
+
const profilers = getProfilers(options)
|
|
152
87
|
|
|
153
|
-
this.timelineEnabled =
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.
|
|
158
|
-
options.timelineSamplingEnabled ?? DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED ?? true
|
|
159
|
-
)
|
|
88
|
+
this.timelineEnabled = options.DD_PROFILING_TIMELINE_ENABLED
|
|
89
|
+
this.timelineSamplingEnabled = options.DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED
|
|
90
|
+
this.codeHotspotsEnabled = options.DD_PROFILING_CODEHOTSPOTS_ENABLED
|
|
91
|
+
this.cpuProfilingEnabled = options.DD_PROFILING_CPU_ENABLED
|
|
92
|
+
this.heapSamplingInterval = options.DD_PROFILING_HEAP_SAMPLING_INTERVAL
|
|
160
93
|
|
|
161
|
-
this.
|
|
162
|
-
options.codeHotspotsEnabled ?? DD_PROFILING_CODEHOTSPOTS_ENABLED ?? samplingContextsAvailable
|
|
163
|
-
)
|
|
164
|
-
checkOptionWithSamplingContextAllowed(this.codeHotspotsEnabled, 'Code hotspots')
|
|
165
|
-
|
|
166
|
-
this.cpuProfilingEnabled = isTrue(
|
|
167
|
-
options.cpuProfilingEnabled ?? DD_PROFILING_CPU_ENABLED ?? samplingContextsAvailable
|
|
168
|
-
)
|
|
169
|
-
checkOptionWithSamplingContextAllowed(this.cpuProfilingEnabled, 'CPU profiling')
|
|
170
|
-
|
|
171
|
-
this.samplingInterval = options.samplingInterval || 1e3 / 99 // 99hz in millis
|
|
172
|
-
|
|
173
|
-
this.heapSamplingInterval = options.heapSamplingInterval ??
|
|
174
|
-
(Number(DD_PROFILING_HEAP_SAMPLING_INTERVAL) || 512 * 1024)
|
|
94
|
+
this.samplingInterval = 1e3 / 99 // 99hz in milliseconds
|
|
175
95
|
|
|
176
96
|
const isAtLeast24 = satisfies(process.versions.node, '>=24.0.0')
|
|
177
97
|
|
|
178
|
-
const uploadCompression0 = options.
|
|
98
|
+
const uploadCompression0 = options.DD_PROFILING_DEBUG_UPLOAD_COMPRESSION
|
|
179
99
|
let [uploadCompression, level0] = uploadCompression0.split('-')
|
|
180
|
-
if (!['on', 'off', 'gzip', 'zstd'].includes(uploadCompression)) {
|
|
181
|
-
this.logger.warn(`Invalid profile upload compression method "${uploadCompression0}". Will use "on".`)
|
|
182
|
-
uploadCompression = 'on'
|
|
183
|
-
}
|
|
184
100
|
let level = level0 ? Number.parseInt(level0, 10) : undefined
|
|
185
101
|
if (level !== undefined) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
level
|
|
189
|
-
|
|
190
|
-
this.logger.warn(
|
|
191
|
-
`Invalid compression level "${level0}". Will use default level.`)
|
|
192
|
-
level = undefined
|
|
193
|
-
} else if (level < 1) {
|
|
194
|
-
this.logger.warn(`Invalid compression level ${level}. Will use 1.`)
|
|
195
|
-
level = 1
|
|
196
|
-
} else {
|
|
197
|
-
const maxLevel = { gzip: 9, zstd: 22 }[uploadCompression]
|
|
198
|
-
if (level > maxLevel) {
|
|
199
|
-
this.logger.warn(`Invalid compression level ${level}. Will use ${maxLevel}.`)
|
|
200
|
-
level = maxLevel
|
|
201
|
-
}
|
|
102
|
+
const maxLevel = { gzip: 9, zstd: 22 }[uploadCompression]
|
|
103
|
+
if (level > maxLevel) {
|
|
104
|
+
this.logger.warn(`Invalid compression level ${level}. Will use ${maxLevel}.`)
|
|
105
|
+
level = maxLevel
|
|
202
106
|
}
|
|
203
107
|
}
|
|
204
108
|
|
|
@@ -219,13 +123,9 @@ class Config {
|
|
|
219
123
|
that.asyncContextFrameEnabled = false
|
|
220
124
|
}
|
|
221
125
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
if (this.asyncContextFrameEnabled && !canUseAsyncContextFrame) {
|
|
226
|
-
if (!samplingContextsAvailable) {
|
|
227
|
-
turnOffAsyncContextFrame(`on ${process.platform}`)
|
|
228
|
-
} else if (isAtLeast24) {
|
|
126
|
+
this.asyncContextFrameEnabled = options.DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED ?? isACFActive
|
|
127
|
+
if (this.asyncContextFrameEnabled && !isACFActive) {
|
|
128
|
+
if (isAtLeast24) {
|
|
229
129
|
turnOffAsyncContextFrame('with --no-async-context-frame')
|
|
230
130
|
} else if (satisfies(process.versions.node, '>=22.9.0')) {
|
|
231
131
|
turnOffAsyncContextFrame('without --experimental-async-context-frame')
|
|
@@ -234,7 +134,7 @@ class Config {
|
|
|
234
134
|
}
|
|
235
135
|
}
|
|
236
136
|
|
|
237
|
-
this.heartbeatInterval = options.heartbeatInterval
|
|
137
|
+
this.heartbeatInterval = options.telemetry.heartbeatInterval
|
|
238
138
|
|
|
239
139
|
this.profilers = ensureProfilers(profilers, this)
|
|
240
140
|
}
|
|
@@ -248,7 +148,7 @@ class Config {
|
|
|
248
148
|
endpointCollectionEnabled: this.endpointCollectionEnabled,
|
|
249
149
|
heapSamplingInterval: this.heapSamplingInterval,
|
|
250
150
|
oomMonitoring: { ...this.oomMonitoring },
|
|
251
|
-
profilerTypes: this.profilers.map(
|
|
151
|
+
profilerTypes: this.profilers.map(profiler => profiler.type),
|
|
252
152
|
sourceMap: this.sourceMap,
|
|
253
153
|
timelineEnabled: this.timelineEnabled,
|
|
254
154
|
timelineSamplingEnabled: this.timelineSamplingEnabled,
|
|
@@ -263,7 +163,9 @@ class Config {
|
|
|
263
163
|
module.exports = { Config }
|
|
264
164
|
|
|
265
165
|
function getProfilers ({
|
|
266
|
-
DD_PROFILING_HEAP_ENABLED,
|
|
166
|
+
DD_PROFILING_HEAP_ENABLED,
|
|
167
|
+
DD_PROFILING_WALLTIME_ENABLED,
|
|
168
|
+
DD_PROFILING_PROFILERS,
|
|
267
169
|
}) {
|
|
268
170
|
// First consider "legacy" DD_PROFILING_PROFILERS env variable, defaulting to space + wall
|
|
269
171
|
// Use a Set to avoid duplicates
|
|
@@ -272,26 +174,26 @@ function getProfilers ({
|
|
|
272
174
|
// snapshots the space profile won't include memory taken by profiles created
|
|
273
175
|
// before it in the sequence. That memory is ultimately transient and will be
|
|
274
176
|
// released when all profiles are subsequently encoded.
|
|
275
|
-
const profilers = new Set(
|
|
177
|
+
const profilers = new Set(DD_PROFILING_PROFILERS)
|
|
276
178
|
|
|
277
179
|
let spaceExplicitlyEnabled = false
|
|
278
180
|
// Add/remove space depending on the value of DD_PROFILING_HEAP_ENABLED
|
|
279
|
-
if (DD_PROFILING_HEAP_ENABLED
|
|
280
|
-
if (
|
|
181
|
+
if (DD_PROFILING_HEAP_ENABLED !== undefined) {
|
|
182
|
+
if (DD_PROFILING_HEAP_ENABLED) {
|
|
281
183
|
if (!profilers.has('space')) {
|
|
282
184
|
profilers.add('space')
|
|
283
185
|
spaceExplicitlyEnabled = true
|
|
284
186
|
}
|
|
285
|
-
} else
|
|
187
|
+
} else {
|
|
286
188
|
profilers.delete('space')
|
|
287
189
|
}
|
|
288
190
|
}
|
|
289
191
|
|
|
290
192
|
// Add/remove wall depending on the value of DD_PROFILING_WALLTIME_ENABLED
|
|
291
|
-
if (DD_PROFILING_WALLTIME_ENABLED
|
|
292
|
-
if (
|
|
193
|
+
if (DD_PROFILING_WALLTIME_ENABLED !== undefined) {
|
|
194
|
+
if (DD_PROFILING_WALLTIME_ENABLED) {
|
|
293
195
|
profilers.add('wall')
|
|
294
|
-
} else
|
|
196
|
+
} else {
|
|
295
197
|
profilers.delete('wall')
|
|
296
198
|
profilers.delete('cpu') // remove alias too
|
|
297
199
|
}
|
|
@@ -321,22 +223,12 @@ function getExportStrategy (name, options) {
|
|
|
321
223
|
}
|
|
322
224
|
|
|
323
225
|
function ensureOOMExportStrategies (strategies, options) {
|
|
324
|
-
|
|
325
|
-
|
|
226
|
+
const set = new Set()
|
|
227
|
+
for (const strategy of strategies) {
|
|
228
|
+
set.add(getExportStrategy(strategy, options))
|
|
326
229
|
}
|
|
327
230
|
|
|
328
|
-
|
|
329
|
-
strategies = strategies.split(',')
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
for (let i = 0; i < strategies.length; i++) {
|
|
333
|
-
const strategy = strategies[i]
|
|
334
|
-
if (typeof strategy === 'string') {
|
|
335
|
-
strategies[i] = getExportStrategy(strategy, options)
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return [...new Set(strategies)]
|
|
231
|
+
return [...set]
|
|
340
232
|
}
|
|
341
233
|
|
|
342
234
|
function getExporter (name, options) {
|
|
@@ -345,22 +237,13 @@ function getExporter (name, options) {
|
|
|
345
237
|
return new AgentExporter(options)
|
|
346
238
|
case 'file':
|
|
347
239
|
return new FileExporter(options)
|
|
240
|
+
default:
|
|
241
|
+
options.logger.error(`Unknown exporter "${name}"`)
|
|
348
242
|
}
|
|
349
243
|
}
|
|
350
244
|
|
|
351
245
|
function ensureExporters (exporters, options) {
|
|
352
|
-
|
|
353
|
-
exporters = exporters.split(',')
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
for (let i = 0; i < exporters.length; i++) {
|
|
357
|
-
const exporter = exporters[i]
|
|
358
|
-
if (typeof exporter === 'string') {
|
|
359
|
-
exporters[i] = getExporter(exporter, options)
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
return exporters
|
|
246
|
+
return exporters.map((exporter) => getExporter(exporter, options))
|
|
364
247
|
}
|
|
365
248
|
|
|
366
249
|
function getProfiler (name, options) {
|
|
@@ -376,30 +259,26 @@ function getProfiler (name, options) {
|
|
|
376
259
|
}
|
|
377
260
|
|
|
378
261
|
function ensureProfilers (profilers, options) {
|
|
379
|
-
|
|
380
|
-
profilers = profilers.split(',')
|
|
381
|
-
}
|
|
262
|
+
const filteredProfilers = []
|
|
382
263
|
|
|
383
264
|
for (let i = 0; i < profilers.length; i++) {
|
|
384
|
-
const profiler = profilers[i]
|
|
385
|
-
if (
|
|
386
|
-
|
|
265
|
+
const profiler = getProfiler(profilers[i], options)
|
|
266
|
+
if (profiler !== undefined) {
|
|
267
|
+
filteredProfilers.push(profiler)
|
|
387
268
|
}
|
|
388
269
|
}
|
|
389
270
|
|
|
390
271
|
// Events profiler is a profiler that produces timeline events. It is only
|
|
391
272
|
// added if timeline is enabled and there's a wall profiler.
|
|
392
|
-
if (options.timelineEnabled &&
|
|
393
|
-
|
|
273
|
+
if (options.timelineEnabled && filteredProfilers.some(profiler => profiler instanceof WallProfiler)) {
|
|
274
|
+
filteredProfilers.push(new EventsProfiler(options))
|
|
394
275
|
}
|
|
395
276
|
|
|
396
|
-
|
|
397
|
-
return profilers.filter(Boolean)
|
|
277
|
+
return filteredProfilers
|
|
398
278
|
}
|
|
399
279
|
|
|
400
280
|
function ensureLogger (logger) {
|
|
401
|
-
if (typeof logger !== '
|
|
402
|
-
typeof logger.debug !== 'function' ||
|
|
281
|
+
if (typeof logger?.debug !== 'function' ||
|
|
403
282
|
typeof logger.info !== 'function' ||
|
|
404
283
|
typeof logger.warn !== 'function' ||
|
|
405
284
|
typeof logger.error !== 'function') {
|
|
@@ -424,50 +303,3 @@ function buildExportCommand (options) {
|
|
|
424
303
|
path.join(__dirname, 'exporter_cli.js'),
|
|
425
304
|
urls.join(','), tags, 'space']
|
|
426
305
|
}
|
|
427
|
-
|
|
428
|
-
function getProfilingEnvValues () {
|
|
429
|
-
return {
|
|
430
|
-
DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED:
|
|
431
|
-
getValueFromEnvSources('DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED'),
|
|
432
|
-
DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED:
|
|
433
|
-
getValueFromEnvSources('DD_PROFILING_ASYNC_CONTEXT_FRAME_ENABLED'),
|
|
434
|
-
DD_PROFILING_CODEHOTSPOTS_ENABLED:
|
|
435
|
-
getValueFromEnvSources('DD_PROFILING_CODEHOTSPOTS_ENABLED'),
|
|
436
|
-
DD_PROFILING_CPU_ENABLED:
|
|
437
|
-
getValueFromEnvSources('DD_PROFILING_CPU_ENABLED'),
|
|
438
|
-
DD_PROFILING_DEBUG_SOURCE_MAPS:
|
|
439
|
-
getValueFromEnvSources('DD_PROFILING_DEBUG_SOURCE_MAPS'),
|
|
440
|
-
DD_PROFILING_DEBUG_UPLOAD_COMPRESSION:
|
|
441
|
-
getValueFromEnvSources('DD_PROFILING_DEBUG_UPLOAD_COMPRESSION'),
|
|
442
|
-
DD_PROFILING_ENDPOINT_COLLECTION_ENABLED:
|
|
443
|
-
getValueFromEnvSources('DD_PROFILING_ENDPOINT_COLLECTION_ENABLED'),
|
|
444
|
-
DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES:
|
|
445
|
-
getValueFromEnvSources('DD_PROFILING_EXPERIMENTAL_OOM_EXPORT_STRATEGIES'),
|
|
446
|
-
DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE:
|
|
447
|
-
getValueFromEnvSources('DD_PROFILING_EXPERIMENTAL_OOM_HEAP_LIMIT_EXTENSION_SIZE'),
|
|
448
|
-
DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT:
|
|
449
|
-
getValueFromEnvSources('DD_PROFILING_EXPERIMENTAL_OOM_MAX_HEAP_EXTENSION_COUNT'),
|
|
450
|
-
DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED:
|
|
451
|
-
getValueFromEnvSources('DD_PROFILING_EXPERIMENTAL_OOM_MONITORING_ENABLED'),
|
|
452
|
-
DD_PROFILING_HEAP_ENABLED:
|
|
453
|
-
getValueFromEnvSources('DD_PROFILING_HEAP_ENABLED'),
|
|
454
|
-
DD_PROFILING_HEAP_SAMPLING_INTERVAL:
|
|
455
|
-
getValueFromEnvSources('DD_PROFILING_HEAP_SAMPLING_INTERVAL'),
|
|
456
|
-
DD_PROFILING_PPROF_PREFIX:
|
|
457
|
-
getValueFromEnvSources('DD_PROFILING_PPROF_PREFIX'),
|
|
458
|
-
DD_PROFILING_PROFILERS:
|
|
459
|
-
getValueFromEnvSources('DD_PROFILING_PROFILERS'),
|
|
460
|
-
DD_PROFILING_TIMELINE_ENABLED:
|
|
461
|
-
getValueFromEnvSources('DD_PROFILING_TIMELINE_ENABLED'),
|
|
462
|
-
DD_PROFILING_UPLOAD_PERIOD:
|
|
463
|
-
getValueFromEnvSources('DD_PROFILING_UPLOAD_PERIOD'),
|
|
464
|
-
DD_PROFILING_UPLOAD_TIMEOUT:
|
|
465
|
-
getValueFromEnvSources('DD_PROFILING_UPLOAD_TIMEOUT'),
|
|
466
|
-
DD_PROFILING_V8_PROFILER_BUG_WORKAROUND:
|
|
467
|
-
getValueFromEnvSources('DD_PROFILING_V8_PROFILER_BUG_WORKAROUND'),
|
|
468
|
-
DD_PROFILING_WALLTIME_ENABLED:
|
|
469
|
-
getValueFromEnvSources('DD_PROFILING_WALLTIME_ENABLED'),
|
|
470
|
-
DD_TAGS:
|
|
471
|
-
getValueFromEnvSources('DD_TAGS'),
|
|
472
|
-
}
|
|
473
|
-
}
|
|
@@ -17,9 +17,6 @@ function exporterFromURL (url) {
|
|
|
17
17
|
if (url.protocol === 'file:') {
|
|
18
18
|
return new FileExporter({ pprofPrefix: fileURLToPath(url) })
|
|
19
19
|
}
|
|
20
|
-
// TODO: Why is DD_INJECTION_ENABLED a comma separated list?
|
|
21
|
-
const injectionEnabled = (getValueFromEnvSources('DD_INJECTION_ENABLED') ?? '').split(',')
|
|
22
|
-
const libraryInjected = injectionEnabled.length > 0
|
|
23
20
|
const profilingEnabled = (getValueFromEnvSources('DD_PROFILING_ENABLED') ?? '').toLowerCase()
|
|
24
21
|
const activation = ['true', '1'].includes(profilingEnabled)
|
|
25
22
|
? 'manual'
|
|
@@ -30,7 +27,7 @@ function exporterFromURL (url) {
|
|
|
30
27
|
url,
|
|
31
28
|
logger,
|
|
32
29
|
uploadTimeout: timeoutMs,
|
|
33
|
-
libraryInjected,
|
|
30
|
+
libraryInjected: !!getValueFromEnvSources('DD_INJECTION_ENABLED'),
|
|
34
31
|
activation,
|
|
35
32
|
})
|
|
36
33
|
}
|
|
@@ -14,7 +14,7 @@ class EventSerializer {
|
|
|
14
14
|
this._host = host
|
|
15
15
|
this._service = service
|
|
16
16
|
this._appVersion = version
|
|
17
|
-
this._libraryInjected =
|
|
17
|
+
this._libraryInjected = libraryInjected
|
|
18
18
|
this._activation = activation || 'unknown'
|
|
19
19
|
}
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ class EventSerializer {
|
|
|
22
22
|
return `${type}.pprof`
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
getEventJSON ({ profiles, infos, start, end, tags = {}, endpointCounts }) {
|
|
25
|
+
getEventJSON ({ profiles, infos, start, end, tags = {}, endpointCounts, customAttributes }) {
|
|
26
26
|
const event = {
|
|
27
27
|
attachments: Object.keys(profiles).map(t => this.typeToFile(t)),
|
|
28
28
|
start: start.toISOString(),
|
|
@@ -80,6 +80,10 @@ class EventSerializer {
|
|
|
80
80
|
},
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
if (customAttributes) {
|
|
84
|
+
event.custom_attributes = customAttributes
|
|
85
|
+
}
|
|
86
|
+
|
|
83
87
|
if (processTags.serialized) {
|
|
84
88
|
event[processTags.PROFILING_FIELD_NAME] = processTags.serialized
|
|
85
89
|
}
|
|
@@ -51,6 +51,7 @@ class Profiler extends EventEmitter {
|
|
|
51
51
|
#compressionFnInitialized = false
|
|
52
52
|
#compressionOptions
|
|
53
53
|
#config
|
|
54
|
+
#customLabelKeys = new Set()
|
|
54
55
|
#enabled = false
|
|
55
56
|
#endpointCounts = new Map()
|
|
56
57
|
#lastStart
|
|
@@ -70,56 +71,22 @@ class Profiler extends EventEmitter {
|
|
|
70
71
|
return this.#config?.flushInterval
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @param {import('../config/config-base')} config - Tracer configuration
|
|
76
|
+
*/
|
|
73
77
|
start (config) {
|
|
74
|
-
const {
|
|
75
|
-
service,
|
|
76
|
-
version,
|
|
77
|
-
env,
|
|
78
|
-
url,
|
|
79
|
-
hostname,
|
|
80
|
-
port,
|
|
81
|
-
tags,
|
|
82
|
-
repositoryUrl,
|
|
83
|
-
commitSHA,
|
|
84
|
-
injectionEnabled,
|
|
85
|
-
reportHostname,
|
|
86
|
-
} = config
|
|
87
|
-
const { enabled, sourceMap, exporters } = config.profiling
|
|
88
|
-
const { heartbeatInterval } = config.telemetry
|
|
89
|
-
|
|
90
78
|
// TODO: Unify with main logger and rewrite template strings to use printf formatting.
|
|
91
79
|
const logger = {
|
|
92
|
-
debug
|
|
93
|
-
info
|
|
94
|
-
warn
|
|
95
|
-
error
|
|
80
|
+
debug: log.debug.bind(log),
|
|
81
|
+
info: log.info.bind(log),
|
|
82
|
+
warn: log.warn.bind(log),
|
|
83
|
+
error: log.error.bind(log),
|
|
96
84
|
}
|
|
97
85
|
|
|
98
|
-
|
|
99
|
-
let activation
|
|
100
|
-
if (enabled === 'auto') {
|
|
101
|
-
activation = 'auto'
|
|
102
|
-
} else if (enabled === 'true') {
|
|
103
|
-
activation = 'manual'
|
|
104
|
-
} // else activation = undefined
|
|
105
|
-
|
|
86
|
+
// TODO: Rewrite this to not need to copy the config.
|
|
106
87
|
const options = {
|
|
107
|
-
|
|
108
|
-
version,
|
|
109
|
-
env,
|
|
88
|
+
...config,
|
|
110
89
|
logger,
|
|
111
|
-
sourceMap,
|
|
112
|
-
exporters,
|
|
113
|
-
url,
|
|
114
|
-
hostname,
|
|
115
|
-
port,
|
|
116
|
-
tags,
|
|
117
|
-
repositoryUrl,
|
|
118
|
-
commitSHA,
|
|
119
|
-
libraryInjected,
|
|
120
|
-
activation,
|
|
121
|
-
heartbeatInterval,
|
|
122
|
-
reportHostname,
|
|
123
90
|
}
|
|
124
91
|
|
|
125
92
|
try {
|
|
@@ -135,6 +102,45 @@ class Profiler extends EventEmitter {
|
|
|
135
102
|
return this.#enabled
|
|
136
103
|
}
|
|
137
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Declares the set of custom label keys that will be used with
|
|
107
|
+
* {@link runWithLabels}. This is used for profile upload metadata and
|
|
108
|
+
* for pprof serialization optimization (low-cardinality deduplication).
|
|
109
|
+
*
|
|
110
|
+
* @param {Iterable<string>} keys - Custom label key names
|
|
111
|
+
*/
|
|
112
|
+
setCustomLabelKeys (keys) {
|
|
113
|
+
this.#customLabelKeys.clear()
|
|
114
|
+
for (const key of keys) {
|
|
115
|
+
this.#customLabelKeys.add(key)
|
|
116
|
+
}
|
|
117
|
+
if (this.#config) {
|
|
118
|
+
for (const profiler of this.#config.profilers) {
|
|
119
|
+
profiler.setCustomLabelKeys?.(this.#customLabelKeys)
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Runs a function with custom profiling labels attached to wall profiler samples.
|
|
126
|
+
*
|
|
127
|
+
* @param {Record<string, string | number>} labels - Custom labels to attach
|
|
128
|
+
* @param {function(): T} fn - Function to execute with the labels
|
|
129
|
+
* @returns {T} The return value of fn
|
|
130
|
+
* @template T
|
|
131
|
+
*/
|
|
132
|
+
runWithLabels (labels, fn) {
|
|
133
|
+
if (!this.#enabled || !this.#config) {
|
|
134
|
+
return fn()
|
|
135
|
+
}
|
|
136
|
+
for (const profiler of this.#config.profilers) {
|
|
137
|
+
if (profiler.runWithLabels) {
|
|
138
|
+
return profiler.runWithLabels(labels, fn)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return fn()
|
|
142
|
+
}
|
|
143
|
+
|
|
138
144
|
#logError (err) {
|
|
139
145
|
logError(this.#logger, err)
|
|
140
146
|
}
|
|
@@ -182,6 +188,9 @@ class Profiler extends EventEmitter {
|
|
|
182
188
|
return this.#compressionFn
|
|
183
189
|
}
|
|
184
190
|
|
|
191
|
+
/**
|
|
192
|
+
* @param {import('../config/config-base')} options - Tracer configuration
|
|
193
|
+
*/
|
|
185
194
|
_start (options) {
|
|
186
195
|
if (this.enabled) return true
|
|
187
196
|
|
|
@@ -410,7 +419,10 @@ class Profiler extends EventEmitter {
|
|
|
410
419
|
|
|
411
420
|
tags.snapshot = snapshotKind
|
|
412
421
|
tags.profile_seq = this.#profileSeq++
|
|
413
|
-
const
|
|
422
|
+
const customAttributes = this.#customLabelKeys.size > 0
|
|
423
|
+
? [...this.#customLabelKeys]
|
|
424
|
+
: undefined
|
|
425
|
+
const exportSpec = { profiles, infos, start, end, tags, endpointCounts, customAttributes }
|
|
414
426
|
const tasks = this.#config.exporters.map(exporter =>
|
|
415
427
|
exporter.export(exportSpec).catch(err => {
|
|
416
428
|
if (this.#logger) {
|
|
@@ -51,8 +51,7 @@ function labelFromStrStr (stringTable, keyStr, valStr) {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
function getMaxSamples (options) {
|
|
54
|
-
const
|
|
55
|
-
const maxCpuSamples = flushInterval / options.samplingInterval
|
|
54
|
+
const maxCpuSamples = options.flushInterval / options.samplingInterval
|
|
56
55
|
|
|
57
56
|
// The lesser of max parallelism and libuv thread pool size, plus one so we can detect
|
|
58
57
|
// oversubscription on libuv thread pool, plus another one for GC.
|
|
@@ -403,7 +402,7 @@ class EventsProfiler {
|
|
|
403
402
|
|
|
404
403
|
get type () { return 'events' }
|
|
405
404
|
|
|
406
|
-
constructor (options
|
|
405
|
+
constructor (options) {
|
|
407
406
|
this.#maxSamples = getMaxSamples(options)
|
|
408
407
|
this.#timelineSamplingEnabled = !!options.timelineSamplingEnabled
|
|
409
408
|
this.#eventSerializer = new EventSerializer(this.#maxSamples)
|