dd-trace 5.30.0 → 5.32.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 +1 -0
- package/README.md +9 -7
- package/package.json +7 -6
- package/packages/datadog-core/src/storage.js +11 -2
- package/packages/datadog-instrumentations/src/aerospike.js +1 -1
- package/packages/datadog-instrumentations/src/aws-sdk.js +2 -1
- package/packages/datadog-instrumentations/src/cucumber.js +14 -5
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/jest.js +70 -36
- package/packages/datadog-instrumentations/src/mocha/utils.js +23 -7
- package/packages/datadog-instrumentations/src/node-serialize.js +22 -0
- package/packages/datadog-instrumentations/src/openai.js +2 -0
- package/packages/datadog-instrumentations/src/vitest.js +107 -59
- package/packages/datadog-instrumentations/src/vm.js +49 -0
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime.js +295 -0
- package/packages/datadog-plugin-aws-sdk/src/services/index.js +1 -0
- package/packages/datadog-plugin-cucumber/src/index.js +30 -32
- package/packages/datadog-plugin-jest/src/index.js +34 -37
- package/packages/datadog-plugin-langchain/src/index.js +12 -80
- package/packages/datadog-plugin-langchain/src/tracing.js +89 -0
- package/packages/datadog-plugin-mocha/src/index.js +18 -36
- package/packages/datadog-plugin-vitest/src/index.js +20 -34
- package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +2 -0
- package/packages/dd-trace/src/appsec/iast/analyzers/untrusted-deserialization-analyzer.js +16 -0
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +9 -8
- package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
- package/packages/dd-trace/src/appsec/remote_config/manager.js +11 -1
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +37 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +65 -28
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +57 -17
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +18 -3
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +20 -3
- package/packages/dd-trace/src/config.js +39 -3
- package/packages/dd-trace/src/crashtracking/crashtracker.js +9 -0
- package/packages/dd-trace/src/crashtracking/noop.js +3 -0
- package/packages/dd-trace/src/datastreams/fnv.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/config.js +3 -1
- package/packages/dd-trace/src/debugger/devtools_client/defaults.js +1 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +32 -14
- package/packages/dd-trace/src/debugger/devtools_client/json-buffer.js +36 -0
- package/packages/dd-trace/src/debugger/devtools_client/send.js +29 -10
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +35 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/redaction.js +112 -0
- package/packages/dd-trace/src/debugger/devtools_client/status.js +20 -11
- package/packages/dd-trace/src/debugger/index.js +2 -13
- package/packages/dd-trace/src/llmobs/plugins/base.js +40 -11
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +24 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +111 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +42 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +102 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/llm.js +32 -0
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +131 -0
- package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -1
- package/packages/dd-trace/src/llmobs/sdk.js +90 -26
- package/packages/dd-trace/src/llmobs/tagger.js +11 -3
- package/packages/dd-trace/src/llmobs/util.js +7 -1
- package/packages/dd-trace/src/llmobs/writers/spans/agentProxy.js +3 -3
- package/packages/dd-trace/src/log/index.js +8 -9
- package/packages/dd-trace/src/noop/proxy.js +2 -2
- package/packages/dd-trace/src/noop/span.js +1 -1
- package/packages/dd-trace/src/opentelemetry/context_manager.js +43 -3
- package/packages/dd-trace/src/opentracing/span.js +11 -1
- package/packages/dd-trace/src/opentracing/span_context.js +12 -0
- package/packages/dd-trace/src/plugins/ci_plugin.js +57 -27
- package/packages/dd-trace/src/plugins/util/test.js +42 -12
- package/packages/dd-trace/src/priority_sampler.js +7 -2
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +21 -0
- package/packages/dd-trace/src/profiling/profiler.js +11 -8
- package/packages/dd-trace/src/profiling/profilers/events.js +17 -1
- package/packages/dd-trace/src/proxy.js +6 -3
- package/packages/dd-trace/src/scope.js +1 -1
- package/packages/dd-trace/src/telemetry/index.js +2 -0
|
@@ -10,7 +10,7 @@ const noopAppsec = new NoopAppsecSdk()
|
|
|
10
10
|
const noopDogStatsDClient = new NoopDogStatsDClient()
|
|
11
11
|
const noopLLMObs = new NoopLLMObsSDK(noop)
|
|
12
12
|
|
|
13
|
-
class
|
|
13
|
+
class NoopProxy {
|
|
14
14
|
constructor () {
|
|
15
15
|
this._tracer = noop
|
|
16
16
|
this.appsec = noopAppsec
|
|
@@ -91,4 +91,4 @@ class Tracer {
|
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
module.exports =
|
|
94
|
+
module.exports = NoopProxy
|
|
@@ -6,7 +6,7 @@ const { storage } = require('../../../datadog-core') // TODO: noop storage?
|
|
|
6
6
|
|
|
7
7
|
class NoopSpan {
|
|
8
8
|
constructor (tracer, parent) {
|
|
9
|
-
this._store = storage.
|
|
9
|
+
this._store = storage.getHandle()
|
|
10
10
|
this._noopTracer = tracer
|
|
11
11
|
this._noopContext = this._createContext(parent)
|
|
12
12
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { storage } = require('../../../datadog-core')
|
|
4
|
-
const { trace, ROOT_CONTEXT } = require('@opentelemetry/api')
|
|
4
|
+
const { trace, ROOT_CONTEXT, propagation } = require('@opentelemetry/api')
|
|
5
5
|
const DataDogSpanContext = require('../opentracing/span_context')
|
|
6
6
|
|
|
7
7
|
const SpanContext = require('./span_context')
|
|
@@ -18,17 +18,40 @@ class ContextManager {
|
|
|
18
18
|
const context = (activeSpan && activeSpan.context()) || store || ROOT_CONTEXT
|
|
19
19
|
|
|
20
20
|
if (!(context instanceof DataDogSpanContext)) {
|
|
21
|
+
const span = trace.getSpan(context)
|
|
22
|
+
// span instanceof NonRecordingSpan
|
|
23
|
+
if (span && span._spanContext && span._spanContext._ddContext && span._spanContext._ddContext._baggageItems) {
|
|
24
|
+
const baggages = span._spanContext._ddContext._baggageItems
|
|
25
|
+
const entries = {}
|
|
26
|
+
for (const [key, value] of Object.entries(baggages)) {
|
|
27
|
+
entries[key] = { value }
|
|
28
|
+
}
|
|
29
|
+
const otelBaggages = propagation.createBaggage(entries)
|
|
30
|
+
return propagation.setBaggage(context, otelBaggages)
|
|
31
|
+
}
|
|
21
32
|
return context
|
|
22
33
|
}
|
|
23
34
|
|
|
35
|
+
const baggages = JSON.parse(activeSpan.getAllBaggageItems())
|
|
36
|
+
const entries = {}
|
|
37
|
+
for (const [key, value] of Object.entries(baggages)) {
|
|
38
|
+
entries[key] = { value }
|
|
39
|
+
}
|
|
40
|
+
const otelBaggages = propagation.createBaggage(entries)
|
|
41
|
+
|
|
24
42
|
if (!context._otelSpanContext) {
|
|
25
43
|
const newSpanContext = new SpanContext(context)
|
|
26
44
|
context._otelSpanContext = newSpanContext
|
|
27
45
|
}
|
|
28
46
|
if (store && trace.getSpanContext(store) === context._otelSpanContext) {
|
|
29
|
-
return
|
|
47
|
+
return otelBaggages
|
|
48
|
+
? propagation.setBaggage(store, otelBaggages)
|
|
49
|
+
: store
|
|
30
50
|
}
|
|
31
|
-
|
|
51
|
+
const wrappedContext = trace.setSpanContext(store || ROOT_CONTEXT, context._otelSpanContext)
|
|
52
|
+
return otelBaggages
|
|
53
|
+
? propagation.setBaggage(wrappedContext, otelBaggages)
|
|
54
|
+
: wrappedContext
|
|
32
55
|
}
|
|
33
56
|
|
|
34
57
|
with (context, fn, thisArg, ...args) {
|
|
@@ -38,9 +61,26 @@ class ContextManager {
|
|
|
38
61
|
const cb = thisArg == null ? fn : fn.bind(thisArg)
|
|
39
62
|
return this._store.run(context, cb, ...args)
|
|
40
63
|
}
|
|
64
|
+
const baggages = propagation.getBaggage(context)
|
|
65
|
+
let baggageItems = []
|
|
66
|
+
if (baggages) {
|
|
67
|
+
baggageItems = baggages.getAllEntries()
|
|
68
|
+
}
|
|
41
69
|
if (span && span._ddSpan) {
|
|
70
|
+
// does otel always override datadog?
|
|
71
|
+
span._ddSpan.removeAllBaggageItems()
|
|
72
|
+
for (const baggage of baggageItems) {
|
|
73
|
+
span._ddSpan.setBaggageItem(baggage[0], baggage[1].value)
|
|
74
|
+
}
|
|
42
75
|
return ddScope.activate(span._ddSpan, run)
|
|
43
76
|
}
|
|
77
|
+
// span instanceof NonRecordingSpan
|
|
78
|
+
if (span && span._spanContext && span._spanContext._ddContext && span._spanContext._ddContext._baggageItems) {
|
|
79
|
+
span._spanContext._ddContext._baggageItems = {}
|
|
80
|
+
for (const baggage of baggageItems) {
|
|
81
|
+
span._spanContext._ddContext._baggageItems[baggage[0]] = baggage[1].value
|
|
82
|
+
}
|
|
83
|
+
}
|
|
44
84
|
return run()
|
|
45
85
|
}
|
|
46
86
|
|
|
@@ -14,6 +14,7 @@ const { storage } = require('../../../datadog-core')
|
|
|
14
14
|
const telemetryMetrics = require('../telemetry/metrics')
|
|
15
15
|
const { channel } = require('dc-polyfill')
|
|
16
16
|
const spanleak = require('../spanleak')
|
|
17
|
+
const util = require('util')
|
|
17
18
|
|
|
18
19
|
const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
|
|
19
20
|
|
|
@@ -64,7 +65,7 @@ class DatadogSpan {
|
|
|
64
65
|
this._debug = debug
|
|
65
66
|
this._processor = processor
|
|
66
67
|
this._prioritySampler = prioritySampler
|
|
67
|
-
this._store = storage.
|
|
68
|
+
this._store = storage.getHandle()
|
|
68
69
|
this._duration = undefined
|
|
69
70
|
|
|
70
71
|
this._events = []
|
|
@@ -105,6 +106,15 @@ class DatadogSpan {
|
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
|
|
109
|
+
[util.inspect.custom] () {
|
|
110
|
+
return {
|
|
111
|
+
...this,
|
|
112
|
+
_parentTracer: `[${this._parentTracer.constructor.name}]`,
|
|
113
|
+
_prioritySampler: `[${this._prioritySampler.constructor.name}]`,
|
|
114
|
+
_processor: `[${this._processor.constructor.name}]`
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
108
118
|
toString () {
|
|
109
119
|
const spanContext = this.context()
|
|
110
120
|
const resourceName = spanContext._tags['resource.name'] || ''
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const util = require('util')
|
|
3
4
|
const { AUTO_KEEP } = require('../../../../ext/priority')
|
|
4
5
|
|
|
5
6
|
// the lowercase, hex encoded upper 64 bits of a 128-bit trace id, if present
|
|
@@ -31,6 +32,17 @@ class DatadogSpanContext {
|
|
|
31
32
|
this._otelSpanContext = undefined
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
[util.inspect.custom] () {
|
|
36
|
+
return {
|
|
37
|
+
...this,
|
|
38
|
+
_trace: {
|
|
39
|
+
...this._trace,
|
|
40
|
+
started: '[Array]',
|
|
41
|
+
finished: '[Array]'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
34
46
|
toTraceId (get128bitId = false) {
|
|
35
47
|
if (get128bitId) {
|
|
36
48
|
return this._traceId.toBuffer().length <= 8 && this._trace.tags[TRACE_ID_128]
|
|
@@ -23,7 +23,11 @@ const {
|
|
|
23
23
|
TEST_LEVEL_EVENT_TYPES,
|
|
24
24
|
TEST_SUITE,
|
|
25
25
|
getFileAndLineNumberFromError,
|
|
26
|
-
|
|
26
|
+
DI_ERROR_DEBUG_INFO_CAPTURED,
|
|
27
|
+
DI_DEBUG_ERROR_PREFIX,
|
|
28
|
+
DI_DEBUG_ERROR_SNAPSHOT_ID_SUFFIX,
|
|
29
|
+
DI_DEBUG_ERROR_FILE_SUFFIX,
|
|
30
|
+
DI_DEBUG_ERROR_LINE_SUFFIX
|
|
27
31
|
} = require('./util/test')
|
|
28
32
|
const Plugin = require('./plugin')
|
|
29
33
|
const { COMPONENT } = require('../constants')
|
|
@@ -180,14 +184,18 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
180
184
|
}
|
|
181
185
|
}
|
|
182
186
|
|
|
183
|
-
configure (config) {
|
|
187
|
+
configure (config, shouldGetEnvironmentData = true) {
|
|
184
188
|
super.configure(config)
|
|
185
189
|
|
|
186
|
-
if (config.isTestDynamicInstrumentationEnabled) {
|
|
190
|
+
if (config.isTestDynamicInstrumentationEnabled && !this.di) {
|
|
187
191
|
const testVisibilityDynamicInstrumentation = require('../ci-visibility/dynamic-instrumentation')
|
|
188
192
|
this.di = testVisibilityDynamicInstrumentation
|
|
189
193
|
}
|
|
190
194
|
|
|
195
|
+
if (!shouldGetEnvironmentData) {
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
191
199
|
this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.id, this.config)
|
|
192
200
|
|
|
193
201
|
const {
|
|
@@ -292,37 +300,59 @@ module.exports = class CiPlugin extends Plugin {
|
|
|
292
300
|
return testSpan
|
|
293
301
|
}
|
|
294
302
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
303
|
+
onDiBreakpointHit ({ snapshot }) {
|
|
304
|
+
if (!this.activeTestSpan || this.activeTestSpan.context()._isFinished) {
|
|
305
|
+
// This is unexpected and is caused by a race condition.
|
|
306
|
+
log.warn('Breakpoint snapshot could not be attached to the active test span')
|
|
307
|
+
return
|
|
308
|
+
}
|
|
298
309
|
|
|
299
|
-
const
|
|
310
|
+
const stackIndex = this.testErrorStackIndex
|
|
311
|
+
|
|
312
|
+
this.activeTestSpan.setTag(DI_ERROR_DEBUG_INFO_CAPTURED, 'true')
|
|
313
|
+
this.activeTestSpan.setTag(
|
|
314
|
+
`${DI_DEBUG_ERROR_PREFIX}.${stackIndex}.${DI_DEBUG_ERROR_SNAPSHOT_ID_SUFFIX}`,
|
|
315
|
+
snapshot.id
|
|
316
|
+
)
|
|
317
|
+
this.activeTestSpan.setTag(
|
|
318
|
+
`${DI_DEBUG_ERROR_PREFIX}.${stackIndex}.${DI_DEBUG_ERROR_FILE_SUFFIX}`,
|
|
319
|
+
snapshot.probe.location.file
|
|
320
|
+
)
|
|
321
|
+
this.activeTestSpan.setTag(
|
|
322
|
+
`${DI_DEBUG_ERROR_PREFIX}.${stackIndex}.${DI_DEBUG_ERROR_LINE_SUFFIX}`,
|
|
323
|
+
Number(snapshot.probe.location.lines[0])
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
const activeTestSpanContext = this.activeTestSpan.context()
|
|
327
|
+
|
|
328
|
+
this.tracer._exporter.exportDiLogs(this.testEnvironmentMetadata, {
|
|
329
|
+
debugger: { snapshot },
|
|
330
|
+
dd: {
|
|
331
|
+
trace_id: activeTestSpanContext.toTraceId(),
|
|
332
|
+
span_id: activeTestSpanContext.toSpanId()
|
|
333
|
+
}
|
|
334
|
+
})
|
|
335
|
+
}
|
|
300
336
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
337
|
+
removeDiProbe (probeId) {
|
|
338
|
+
return this.di.removeProbe(probeId)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
addDiProbe (err) {
|
|
342
|
+
const [file, line, stackIndex] = getFileAndLineNumberFromError(err, this.repositoryRoot)
|
|
306
343
|
|
|
307
|
-
if (
|
|
308
|
-
|
|
344
|
+
if (!file || !Number.isInteger(line)) {
|
|
345
|
+
log.warn('Could not add breakpoint for dynamic instrumentation')
|
|
346
|
+
return
|
|
309
347
|
}
|
|
310
348
|
|
|
311
|
-
|
|
312
|
-
// TODO: handle race conditions for this.retriedTestIds
|
|
313
|
-
const { traceId, spanId } = this.retriedTestIds
|
|
314
|
-
this.tracer._exporter.exportDiLogs(this.testEnvironmentMetadata, {
|
|
315
|
-
debugger: { snapshot },
|
|
316
|
-
dd: {
|
|
317
|
-
trace_id: traceId,
|
|
318
|
-
span_id: spanId
|
|
319
|
-
}
|
|
320
|
-
})
|
|
321
|
-
})
|
|
349
|
+
const [probeId, setProbePromise] = this.di.addLineProbe({ file, line }, this.onDiBreakpointHit.bind(this))
|
|
322
350
|
|
|
323
351
|
return {
|
|
324
|
-
|
|
325
|
-
|
|
352
|
+
probeId,
|
|
353
|
+
setProbePromise,
|
|
354
|
+
stackIndex,
|
|
355
|
+
file,
|
|
326
356
|
line
|
|
327
357
|
}
|
|
328
358
|
}
|
|
@@ -88,6 +88,7 @@ const TEST_BROWSER_VERSION = 'test.browser.version'
|
|
|
88
88
|
// jest worker variables
|
|
89
89
|
const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
|
|
90
90
|
const JEST_WORKER_COVERAGE_PAYLOAD_CODE = 61
|
|
91
|
+
const JEST_WORKER_LOGS_PAYLOAD_CODE = 62
|
|
91
92
|
|
|
92
93
|
// cucumber worker variables
|
|
93
94
|
const CUCUMBER_WORKER_TRACE_PAYLOAD_CODE = 70
|
|
@@ -108,10 +109,10 @@ const TEST_LEVEL_EVENT_TYPES = [
|
|
|
108
109
|
|
|
109
110
|
// Dynamic instrumentation - Test optimization integration tags
|
|
110
111
|
const DI_ERROR_DEBUG_INFO_CAPTURED = 'error.debug_info_captured'
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const
|
|
112
|
+
const DI_DEBUG_ERROR_PREFIX = '_dd.debug.error'
|
|
113
|
+
const DI_DEBUG_ERROR_SNAPSHOT_ID_SUFFIX = 'snapshot_id'
|
|
114
|
+
const DI_DEBUG_ERROR_FILE_SUFFIX = 'file'
|
|
115
|
+
const DI_DEBUG_ERROR_LINE_SUFFIX = 'line'
|
|
115
116
|
|
|
116
117
|
module.exports = {
|
|
117
118
|
TEST_CODE_OWNERS,
|
|
@@ -134,6 +135,7 @@ module.exports = {
|
|
|
134
135
|
LIBRARY_VERSION,
|
|
135
136
|
JEST_WORKER_TRACE_PAYLOAD_CODE,
|
|
136
137
|
JEST_WORKER_COVERAGE_PAYLOAD_CODE,
|
|
138
|
+
JEST_WORKER_LOGS_PAYLOAD_CODE,
|
|
137
139
|
CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
|
|
138
140
|
MOCHA_WORKER_TRACE_PAYLOAD_CODE,
|
|
139
141
|
TEST_SOURCE_START,
|
|
@@ -191,9 +193,11 @@ module.exports = {
|
|
|
191
193
|
getNumFromKnownTests,
|
|
192
194
|
getFileAndLineNumberFromError,
|
|
193
195
|
DI_ERROR_DEBUG_INFO_CAPTURED,
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
196
|
+
DI_DEBUG_ERROR_PREFIX,
|
|
197
|
+
DI_DEBUG_ERROR_SNAPSHOT_ID_SUFFIX,
|
|
198
|
+
DI_DEBUG_ERROR_FILE_SUFFIX,
|
|
199
|
+
DI_DEBUG_ERROR_LINE_SUFFIX,
|
|
200
|
+
getFormattedError
|
|
197
201
|
}
|
|
198
202
|
|
|
199
203
|
// Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
|
|
@@ -650,13 +654,30 @@ function getNumFromKnownTests (knownTests) {
|
|
|
650
654
|
return totalNumTests
|
|
651
655
|
}
|
|
652
656
|
|
|
653
|
-
|
|
657
|
+
const DEPENDENCY_FOLDERS = [
|
|
658
|
+
'node_modules',
|
|
659
|
+
'node:',
|
|
660
|
+
'.pnpm',
|
|
661
|
+
'.yarn',
|
|
662
|
+
'.pnp'
|
|
663
|
+
]
|
|
664
|
+
|
|
665
|
+
function getFileAndLineNumberFromError (error, repositoryRoot) {
|
|
654
666
|
// Split the stack trace into individual lines
|
|
655
667
|
const stackLines = error.stack.split('\n')
|
|
656
668
|
|
|
657
|
-
//
|
|
658
|
-
const
|
|
669
|
+
// Remove potential messages on top of the stack that are not frames
|
|
670
|
+
const frames = stackLines.filter(line => line.includes('at ') && line.includes(repositoryRoot))
|
|
671
|
+
|
|
672
|
+
const topRelevantFrameIndex = frames.findIndex(line =>
|
|
673
|
+
line.includes(repositoryRoot) && !DEPENDENCY_FOLDERS.some(pattern => line.includes(pattern))
|
|
674
|
+
)
|
|
675
|
+
|
|
676
|
+
if (topRelevantFrameIndex === -1) {
|
|
677
|
+
return []
|
|
678
|
+
}
|
|
659
679
|
|
|
680
|
+
const topFrame = frames[topRelevantFrameIndex]
|
|
660
681
|
// Regular expression to match the file path, line number, and column number
|
|
661
682
|
const regex = /\s*at\s+(?:.*\()?(.+):(\d+):(\d+)\)?/
|
|
662
683
|
const match = topFrame.match(regex)
|
|
@@ -664,9 +685,18 @@ function getFileAndLineNumberFromError (error) {
|
|
|
664
685
|
if (match) {
|
|
665
686
|
const filePath = match[1]
|
|
666
687
|
const lineNumber = Number(match[2])
|
|
667
|
-
const columnNumber = Number(match[3])
|
|
668
688
|
|
|
669
|
-
return [filePath, lineNumber,
|
|
689
|
+
return [filePath, lineNumber, topRelevantFrameIndex]
|
|
670
690
|
}
|
|
671
691
|
return []
|
|
672
692
|
}
|
|
693
|
+
|
|
694
|
+
function getFormattedError (error, repositoryRoot) {
|
|
695
|
+
const newError = new Error(error.message)
|
|
696
|
+
if (error.stack) {
|
|
697
|
+
newError.stack = error.stack.split('\n').filter(line => line.includes(repositoryRoot)).join('\n')
|
|
698
|
+
}
|
|
699
|
+
newError.name = error.name
|
|
700
|
+
|
|
701
|
+
return newError
|
|
702
|
+
}
|
|
@@ -120,13 +120,18 @@ class PrioritySampler {
|
|
|
120
120
|
if (!span || !this.validate(samplingPriority)) return
|
|
121
121
|
|
|
122
122
|
const context = this._getContext(span)
|
|
123
|
+
const root = context._trace.started[0]
|
|
124
|
+
|
|
125
|
+
if (!root) {
|
|
126
|
+
log.error('Skipping the setPriority on noop span')
|
|
127
|
+
return // noop span
|
|
128
|
+
}
|
|
123
129
|
|
|
124
130
|
context._sampling.priority = samplingPriority
|
|
125
131
|
context._sampling.mechanism = mechanism
|
|
126
132
|
|
|
127
|
-
const root = context._trace.started[0]
|
|
128
|
-
|
|
129
133
|
log.trace(span, samplingPriority, mechanism)
|
|
134
|
+
|
|
130
135
|
this._addDecisionMaker(root)
|
|
131
136
|
}
|
|
132
137
|
|
|
@@ -2,6 +2,22 @@ const os = require('os')
|
|
|
2
2
|
const perf = require('perf_hooks').performance
|
|
3
3
|
const version = require('../../../../../package.json').version
|
|
4
4
|
|
|
5
|
+
const libuvThreadPoolSize = (() => {
|
|
6
|
+
const ss = process.env.UV_THREADPOOL_SIZE
|
|
7
|
+
if (ss === undefined) {
|
|
8
|
+
// Backend will apply the default size based on Node version.
|
|
9
|
+
return undefined
|
|
10
|
+
}
|
|
11
|
+
// libuv uses atoi to parse the value, which is almost the same as parseInt, except that parseInt
|
|
12
|
+
// will return NaN on invalid input, while atoi will return 0. This is handled at return.
|
|
13
|
+
const s = parseInt(ss)
|
|
14
|
+
// We dont' interpret the value further here in the library. Backend will interpret the number
|
|
15
|
+
// based on Node version. In all currently known Node versions, 0 results in 1 worker thread,
|
|
16
|
+
// negative values (because they're assigned to an unsigned int) become very high positive values,
|
|
17
|
+
// and the value is finally capped at 1024.
|
|
18
|
+
return isNaN(s) ? 0 : s
|
|
19
|
+
})()
|
|
20
|
+
|
|
5
21
|
class EventSerializer {
|
|
6
22
|
constructor ({ env, host, service, version, libraryInjected, activation } = {}) {
|
|
7
23
|
this._env = env
|
|
@@ -56,11 +72,16 @@ class EventSerializer {
|
|
|
56
72
|
version
|
|
57
73
|
},
|
|
58
74
|
runtime: {
|
|
75
|
+
// os.availableParallelism only available in node 18.14.0/19.4.0 and above
|
|
76
|
+
available_processors: typeof os.availableParallelism === 'function'
|
|
77
|
+
? os.availableParallelism()
|
|
78
|
+
: os.cpus().length,
|
|
59
79
|
// Using `nodejs` for consistency with the existing `runtime` tag.
|
|
60
80
|
// Note that the event `family` property uses `node`, as that's what's
|
|
61
81
|
// proscribed by the Intake API, but that's an internal enum and is
|
|
62
82
|
// not customer visible.
|
|
63
83
|
engine: 'nodejs',
|
|
84
|
+
libuv_threadpool_size: libuvThreadPoolSize,
|
|
64
85
|
// strip off leading 'v'. This makes the format consistent with other
|
|
65
86
|
// runtimes (e.g. Ruby) but not with the existing `runtime_version` tag.
|
|
66
87
|
// We'll keep it like this as we want cross-engine consistency. We
|
|
@@ -6,6 +6,7 @@ const { snapshotKinds } = require('./constants')
|
|
|
6
6
|
const { threadNamePrefix } = require('./profilers/shared')
|
|
7
7
|
const { isWebServerSpan, endpointNameFromTags, getStartedSpans } = require('./webspan-utils')
|
|
8
8
|
const dc = require('dc-polyfill')
|
|
9
|
+
const crashtracker = require('../crashtracking')
|
|
9
10
|
|
|
10
11
|
const profileSubmittedChannel = dc.channel('datadog:profiling:profile-submitted')
|
|
11
12
|
const spanFinishedChannel = dc.channel('dd-trace:span:finish')
|
|
@@ -197,15 +198,17 @@ class Profiler extends EventEmitter {
|
|
|
197
198
|
throw new Error('No profile types configured.')
|
|
198
199
|
}
|
|
199
200
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
crashtracker.withProfilerSerializing(() => {
|
|
202
|
+
// collect profiles synchronously so that profilers can be safely stopped asynchronously
|
|
203
|
+
for (const profiler of this._config.profilers) {
|
|
204
|
+
const profile = profiler.profile(restart, startDate, endDate)
|
|
205
|
+
if (!restart) {
|
|
206
|
+
this._logger.debug(`Stopped ${profiler.type} profiler in ${threadNamePrefix} thread`)
|
|
207
|
+
}
|
|
208
|
+
if (!profile) continue
|
|
209
|
+
profiles.push({ profiler, profile })
|
|
205
210
|
}
|
|
206
|
-
|
|
207
|
-
profiles.push({ profiler, profile })
|
|
208
|
-
}
|
|
211
|
+
})
|
|
209
212
|
|
|
210
213
|
if (restart) {
|
|
211
214
|
this._capture(this._timeoutInterval, endDate)
|
|
@@ -14,7 +14,23 @@ const pprofValueUnit = 'nanoseconds'
|
|
|
14
14
|
const dateOffset = BigInt(Math.round(performance.timeOrigin * MS_TO_NS))
|
|
15
15
|
|
|
16
16
|
function labelFromStr (stringTable, key, valStr) {
|
|
17
|
-
return new Label({ key, str: stringTable.dedup(valStr) })
|
|
17
|
+
return new Label({ key, str: stringTable.dedup(safeToString(valStr)) })
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// We don't want to invoke toString for objects and functions, rather we'll
|
|
21
|
+
// provide dummy values. These values are not meant to emulate built-in toString
|
|
22
|
+
// behavior.
|
|
23
|
+
function safeToString (val) {
|
|
24
|
+
switch (typeof val) {
|
|
25
|
+
case 'string':
|
|
26
|
+
return val
|
|
27
|
+
case 'object':
|
|
28
|
+
return '[object]'
|
|
29
|
+
case 'function':
|
|
30
|
+
return '[function]'
|
|
31
|
+
default:
|
|
32
|
+
return String(val)
|
|
33
|
+
}
|
|
18
34
|
}
|
|
19
35
|
|
|
20
36
|
function labelFromStrStr (stringTable, keyStr, valStr) {
|
|
@@ -119,7 +119,7 @@ class Tracer extends NoopProxy {
|
|
|
119
119
|
this._flare.module.send(conf.args)
|
|
120
120
|
})
|
|
121
121
|
|
|
122
|
-
if (config.
|
|
122
|
+
if (config.dynamicInstrumentation.enabled) {
|
|
123
123
|
DynamicInstrumentation.start(config, rc)
|
|
124
124
|
}
|
|
125
125
|
}
|
|
@@ -166,7 +166,10 @@ class Tracer extends NoopProxy {
|
|
|
166
166
|
if (config.isManualApiEnabled) {
|
|
167
167
|
const TestApiManualPlugin = require('./ci-visibility/test-api-manual/test-api-manual-plugin')
|
|
168
168
|
this._testApiManualPlugin = new TestApiManualPlugin(this)
|
|
169
|
-
|
|
169
|
+
// `shouldGetEnvironmentData` is passed as false so that we only lazily calculate it
|
|
170
|
+
// This is the only place where we need to do this because the rest of the plugins
|
|
171
|
+
// are lazily configured when the library is imported.
|
|
172
|
+
this._testApiManualPlugin.configure({ ...config, enabled: true }, false)
|
|
170
173
|
}
|
|
171
174
|
}
|
|
172
175
|
if (config.ciVisAgentlessLogSubmissionEnabled) {
|
|
@@ -184,7 +187,7 @@ class Tracer extends NoopProxy {
|
|
|
184
187
|
|
|
185
188
|
if (config.isTestDynamicInstrumentationEnabled) {
|
|
186
189
|
const testVisibilityDynamicInstrumentation = require('./ci-visibility/dynamic-instrumentation')
|
|
187
|
-
testVisibilityDynamicInstrumentation.start()
|
|
190
|
+
testVisibilityDynamicInstrumentation.start(config)
|
|
188
191
|
}
|
|
189
192
|
} catch (e) {
|
|
190
193
|
log.error('Error initialising tracer', e)
|
|
@@ -17,7 +17,7 @@ class Scope {
|
|
|
17
17
|
if (typeof callback !== 'function') return callback
|
|
18
18
|
|
|
19
19
|
const oldStore = storage.getStore()
|
|
20
|
-
const newStore = span ? span._store : oldStore
|
|
20
|
+
const newStore = span ? storage.getStore(span._store) : oldStore
|
|
21
21
|
|
|
22
22
|
storage.enterWith({ ...newStore, span })
|
|
23
23
|
|