dd-trace 5.46.0 → 5.47.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 -2
- package/package.json +8 -9
- package/packages/datadog-instrumentations/orchestrion.yml +52 -0
- package/packages/datadog-instrumentations/src/cucumber.js +2 -1
- package/packages/datadog-instrumentations/src/jest.js +11 -2
- package/packages/datadog-instrumentations/src/langchain.js +49 -53
- package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +11 -3
- package/packages/datadog-instrumentations/src/orchestrion-config/index.js +5 -0
- package/packages/datadog-instrumentations/src/playwright.js +14 -2
- package/packages/datadog-instrumentations/src/vitest.js +11 -3
- package/packages/datadog-plugin-cucumber/src/index.js +11 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +17 -5
- package/packages/datadog-plugin-jest/src/index.js +11 -4
- package/packages/datadog-plugin-langchain/src/index.js +18 -12
- package/packages/datadog-plugin-langchain/src/tracing.js +66 -6
- package/packages/datadog-plugin-mocha/src/index.js +17 -5
- package/packages/datadog-plugin-mongodb-core/src/index.js +5 -1
- package/packages/datadog-plugin-playwright/src/index.js +10 -3
- package/packages/datadog-plugin-vitest/src/index.js +13 -8
- package/packages/datadog-shimmer/src/shimmer.js +3 -42
- package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +3 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +0 -3
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +24 -11
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +3 -32
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +98 -56
- package/packages/dd-trace/src/config.js +9 -0
- package/packages/dd-trace/src/exporters/common/docker.js +37 -7
- package/packages/dd-trace/src/exporters/common/request.js +1 -4
- package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +62 -3
- package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -0
- package/packages/dd-trace/src/llmobs/plugins/vertexai.js +2 -1
- package/packages/dd-trace/src/log/index.js +2 -0
- package/packages/dd-trace/src/log/writer.js +19 -2
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +17 -3
- package/packages/dd-trace/src/opentracing/span.js +10 -0
- package/packages/dd-trace/src/plugins/util/test.js +7 -0
- package/packages/dd-trace/src/profiling/exporters/agent.js +1 -5
- package/packages/dd-trace/src/profiling/profilers/wall.js +3 -1
- package/packages/dd-trace/src/proxy.js +5 -1
|
@@ -4,44 +4,48 @@ const Module = require('module')
|
|
|
4
4
|
const { pathToFileURL } = require('url')
|
|
5
5
|
const { MessageChannel } = require('worker_threads')
|
|
6
6
|
const shimmer = require('../../../../../datadog-shimmer')
|
|
7
|
-
const { isPrivateModule,
|
|
7
|
+
const { isPrivateModule, isDdTrace } = require('./filter')
|
|
8
8
|
const { csiMethods } = require('./csi-methods')
|
|
9
9
|
const { getName } = require('../telemetry/verbosity')
|
|
10
|
-
const
|
|
10
|
+
const telemetry = require('../telemetry')
|
|
11
|
+
const { incrementTelemetryIfNeeded } = require('./rewriter-telemetry')
|
|
11
12
|
const dc = require('dc-polyfill')
|
|
12
13
|
const log = require('../../../log')
|
|
13
14
|
const { isMainThread } = require('worker_threads')
|
|
14
15
|
const { LOG_MESSAGE, REWRITTEN_MESSAGE } = require('./constants')
|
|
16
|
+
const orchestrionConfig = require('../../../../../datadog-instrumentations/src/orchestrion-config')
|
|
15
17
|
|
|
18
|
+
let config
|
|
16
19
|
const hardcodedSecretCh = dc.channel('datadog:secrets:result')
|
|
17
20
|
let rewriter
|
|
21
|
+
let unwrapCompile = () => {}
|
|
18
22
|
let getPrepareStackTrace, cacheRewrittenSourceMap
|
|
19
23
|
let kSymbolPrepareStackTrace
|
|
20
24
|
let esmRewriterEnabled = false
|
|
21
25
|
|
|
22
|
-
let getRewriterOriginalPathAndLineFromSourceMap = function (path, line, column) {
|
|
23
|
-
return { path, line, column }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
26
|
function isFlagPresent (flag) {
|
|
27
27
|
return process.env.NODE_OPTIONS?.includes(flag) ||
|
|
28
28
|
process.execArgv?.some(arg => arg.includes(flag))
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
let getRewriterOriginalPathAndLineFromSourceMap = function (path, line, column) {
|
|
32
|
+
return { path, line, column }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function setGetOriginalPathAndLineFromSourceMapFunction (chainSourceMap, { getOriginalPathAndLineFromSourceMap }) {
|
|
36
|
+
if (!getOriginalPathAndLineFromSourceMap) return
|
|
37
|
+
|
|
38
|
+
getRewriterOriginalPathAndLineFromSourceMap = chainSourceMap
|
|
39
|
+
? (path, line, column) => {
|
|
34
40
|
// if --enable-source-maps is present stacktraces of the rewritten files contain the original path, file and
|
|
35
41
|
// column because the sourcemap chaining is done during the rewriting process so we can skip it
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
if (isPrivateModule(path) && !isDdTrace(path)) {
|
|
43
|
+
return { path, line, column }
|
|
44
|
+
} else {
|
|
45
|
+
return getOriginalPathAndLineFromSourceMap(path, line, column)
|
|
46
|
+
}
|
|
40
47
|
}
|
|
41
|
-
|
|
42
|
-
} else {
|
|
43
|
-
return getOriginalPathAndLineFromSourceMap
|
|
44
|
-
}
|
|
48
|
+
: getOriginalPathAndLineFromSourceMap
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
function getRewriter (telemetryVerbosity) {
|
|
@@ -54,19 +58,16 @@ function getRewriter (telemetryVerbosity) {
|
|
|
54
58
|
cacheRewrittenSourceMap = iastRewriter.cacheRewrittenSourceMap
|
|
55
59
|
|
|
56
60
|
const chainSourceMap = isFlagPresent('--enable-source-maps')
|
|
57
|
-
|
|
58
|
-
if (getOriginalPathAndLineFromSourceMap) {
|
|
59
|
-
getRewriterOriginalPathAndLineFromSourceMap =
|
|
60
|
-
getGetOriginalPathAndLineFromSourceMapFunction(chainSourceMap, getOriginalPathAndLineFromSourceMap)
|
|
61
|
-
}
|
|
61
|
+
setGetOriginalPathAndLineFromSourceMapFunction(chainSourceMap, iastRewriter)
|
|
62
62
|
|
|
63
63
|
rewriter = new Rewriter({
|
|
64
64
|
csiMethods,
|
|
65
65
|
telemetryVerbosity: getName(telemetryVerbosity),
|
|
66
|
-
chainSourceMap
|
|
66
|
+
chainSourceMap,
|
|
67
|
+
orchestrion: orchestrionConfig
|
|
67
68
|
})
|
|
68
69
|
} catch (e) {
|
|
69
|
-
log.error('
|
|
70
|
+
log.error('Unable to initialize Rewriter', e)
|
|
70
71
|
}
|
|
71
72
|
}
|
|
72
73
|
return rewriter
|
|
@@ -74,6 +75,9 @@ function getRewriter (telemetryVerbosity) {
|
|
|
74
75
|
|
|
75
76
|
let originalPrepareStackTrace
|
|
76
77
|
function getPrepareStackTraceAccessor () {
|
|
78
|
+
if (!getPrepareStackTrace) {
|
|
79
|
+
getPrepareStackTrace = require('@datadog/wasm-js-rewriter/js/stack-trace').getPrepareStackTrace
|
|
80
|
+
}
|
|
77
81
|
originalPrepareStackTrace = Error.prepareStackTrace
|
|
78
82
|
let actual = getPrepareStackTrace(originalPrepareStackTrace)
|
|
79
83
|
return {
|
|
@@ -89,25 +93,42 @@ function getPrepareStackTraceAccessor () {
|
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
function getCompileMethodFn (compileMethod) {
|
|
92
|
-
|
|
93
|
-
return function (content, filename) {
|
|
96
|
+
let delegate = function (content, filename) {
|
|
94
97
|
try {
|
|
95
|
-
if (
|
|
96
|
-
|
|
98
|
+
if (isDdTrace(filename)) {
|
|
99
|
+
return compileMethod.apply(this, [content, filename])
|
|
100
|
+
}
|
|
101
|
+
if (!isPrivateModule(filename) || !config.iast?.enabled) {
|
|
102
|
+
return compileMethod.apply(this, [content, filename])
|
|
103
|
+
}
|
|
104
|
+
// TODO when we have CJS support for orchestrion and taint-tracking, add
|
|
105
|
+
// them here as appropriate
|
|
106
|
+
const rewritten = rewriter.rewrite(content, filename, ['iast'])
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
hardcodedSecretCh.publish(rewritten.literalsResult)
|
|
100
|
-
}
|
|
108
|
+
incrementTelemetryIfNeeded(rewritten.metrics)
|
|
101
109
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
if (rewritten?.literalsResult && hardcodedSecretCh.hasSubscribers) {
|
|
111
|
+
hardcodedSecretCh.publish(rewritten.literalsResult)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (rewritten?.content) {
|
|
115
|
+
return compileMethod.apply(this, [rewritten.content, filename])
|
|
105
116
|
}
|
|
106
117
|
} catch (e) {
|
|
107
|
-
log.error('
|
|
118
|
+
log.error('Error rewriting file %s', filename, e)
|
|
108
119
|
}
|
|
109
120
|
return compileMethod.apply(this, [content, filename])
|
|
110
121
|
}
|
|
122
|
+
|
|
123
|
+
const shim = function () {
|
|
124
|
+
return delegate.apply(this, arguments)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
unwrapCompile = function () {
|
|
128
|
+
delegate = compileMethod
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return shim
|
|
111
132
|
}
|
|
112
133
|
|
|
113
134
|
function esmRewritePostProcess (rewritten, filename) {
|
|
@@ -128,20 +149,31 @@ function esmRewritePostProcess (rewritten, filename) {
|
|
|
128
149
|
}
|
|
129
150
|
}
|
|
130
151
|
|
|
152
|
+
let shimmedPrepareStackTrace = false
|
|
153
|
+
function shimPrepareStackTrace () {
|
|
154
|
+
if (shimmedPrepareStackTrace) {
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
const pstDescriptor = Object.getOwnPropertyDescriptor(global.Error, 'prepareStackTrace')
|
|
158
|
+
if (!pstDescriptor || pstDescriptor.configurable) {
|
|
159
|
+
Object.defineProperty(global.Error, 'prepareStackTrace', getPrepareStackTraceAccessor())
|
|
160
|
+
}
|
|
161
|
+
shimmedPrepareStackTrace = true
|
|
162
|
+
}
|
|
163
|
+
|
|
131
164
|
function enableRewriter (telemetryVerbosity) {
|
|
132
165
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
166
|
+
if (config.iast?.enabled) {
|
|
167
|
+
const rewriter = getRewriter(telemetryVerbosity)
|
|
168
|
+
if (rewriter) {
|
|
169
|
+
shimPrepareStackTrace()
|
|
170
|
+
shimmer.wrap(Module.prototype, '_compile', compileMethod => getCompileMethodFn(compileMethod))
|
|
138
171
|
}
|
|
139
|
-
shimmer.wrap(Module.prototype, '_compile', compileMethod => getCompileMethodFn(compileMethod))
|
|
140
172
|
}
|
|
141
173
|
|
|
142
174
|
enableEsmRewriter(telemetryVerbosity)
|
|
143
175
|
} catch (e) {
|
|
144
|
-
log.error('
|
|
176
|
+
log.error('Error enabling Rewriter', e)
|
|
145
177
|
}
|
|
146
178
|
}
|
|
147
179
|
|
|
@@ -155,6 +187,8 @@ function isEsmConfigured () {
|
|
|
155
187
|
|
|
156
188
|
function enableEsmRewriter (telemetryVerbosity) {
|
|
157
189
|
if (isMainThread && Module.register && !esmRewriterEnabled && isEsmConfigured()) {
|
|
190
|
+
shimPrepareStackTrace()
|
|
191
|
+
|
|
158
192
|
esmRewriterEnabled = true
|
|
159
193
|
|
|
160
194
|
const { port1, port2 } = new MessageChannel()
|
|
@@ -175,30 +209,31 @@ function enableEsmRewriter (telemetryVerbosity) {
|
|
|
175
209
|
port1.unref()
|
|
176
210
|
port2.unref()
|
|
177
211
|
|
|
178
|
-
const chainSourceMap = isFlagPresent('--enable-source-maps')
|
|
179
|
-
const data = {
|
|
180
|
-
port: port2,
|
|
181
|
-
csiMethods,
|
|
182
|
-
telemetryVerbosity,
|
|
183
|
-
chainSourceMap
|
|
184
|
-
}
|
|
185
|
-
|
|
186
212
|
try {
|
|
187
213
|
Module.register('./rewriter-esm.mjs', {
|
|
188
214
|
parentURL: pathToFileURL(__filename),
|
|
189
215
|
transferList: [port2],
|
|
190
|
-
data
|
|
216
|
+
data: {
|
|
217
|
+
port: port2,
|
|
218
|
+
csiMethods,
|
|
219
|
+
telemetryVerbosity,
|
|
220
|
+
chainSourceMap: isFlagPresent('--enable-source-maps'),
|
|
221
|
+
orchestrionConfig,
|
|
222
|
+
iastEnabled: config?.iast?.enabled
|
|
223
|
+
}
|
|
191
224
|
})
|
|
192
225
|
} catch (e) {
|
|
193
|
-
log.error('
|
|
226
|
+
log.error('Error enabling ESM Rewriter', e)
|
|
194
227
|
port1.close()
|
|
195
228
|
port2.close()
|
|
196
229
|
}
|
|
230
|
+
|
|
231
|
+
cacheRewrittenSourceMap = require('@datadog/wasm-js-rewriter/js/source-map').cacheRewrittenSourceMap
|
|
197
232
|
}
|
|
198
233
|
}
|
|
199
234
|
|
|
200
|
-
function
|
|
201
|
-
|
|
235
|
+
function disable () {
|
|
236
|
+
unwrapCompile()
|
|
202
237
|
|
|
203
238
|
if (!Error.prepareStackTrace?.[kSymbolPrepareStackTrace]) return
|
|
204
239
|
|
|
@@ -206,8 +241,10 @@ function disableRewriter () {
|
|
|
206
241
|
delete Error.prepareStackTrace
|
|
207
242
|
|
|
208
243
|
Error.prepareStackTrace = originalPrepareStackTrace
|
|
244
|
+
|
|
245
|
+
shimmedPrepareStackTrace = false
|
|
209
246
|
} catch (e) {
|
|
210
|
-
log.warn('
|
|
247
|
+
log.warn('Error disabling Rewriter', e)
|
|
211
248
|
}
|
|
212
249
|
}
|
|
213
250
|
|
|
@@ -215,6 +252,11 @@ function getOriginalPathAndLineFromSourceMap ({ path, line, column }) {
|
|
|
215
252
|
return getRewriterOriginalPathAndLineFromSourceMap(path, line, column)
|
|
216
253
|
}
|
|
217
254
|
|
|
255
|
+
function enable (configArg) {
|
|
256
|
+
config = configArg
|
|
257
|
+
enableRewriter(telemetry.verbosity || 'OFF')
|
|
258
|
+
}
|
|
259
|
+
|
|
218
260
|
module.exports = {
|
|
219
|
-
|
|
261
|
+
enable, disable, getOriginalPathAndLineFromSourceMap
|
|
220
262
|
}
|
|
@@ -63,6 +63,8 @@ const otelDdEnvMapping = {
|
|
|
63
63
|
|
|
64
64
|
const VALID_PROPAGATION_STYLES = new Set(['datadog', 'tracecontext', 'b3', 'b3 single header', 'none'])
|
|
65
65
|
|
|
66
|
+
const VALID_PROPAGATION_BEHAVIOR_EXTRACT = new Set(['continue', 'restart', 'ignore'])
|
|
67
|
+
|
|
66
68
|
const VALID_LOG_LEVELS = new Set(['debug', 'info', 'warn', 'error'])
|
|
67
69
|
|
|
68
70
|
function getFromOtelSamplerMap (otelTracesSampler, otelTracesSamplerArg) {
|
|
@@ -584,6 +586,7 @@ class Config {
|
|
|
584
586
|
this._setValue(defaults, 'traceId128BitGenerationEnabled', true)
|
|
585
587
|
this._setValue(defaults, 'traceId128BitLoggingEnabled', true)
|
|
586
588
|
this._setValue(defaults, 'tracePropagationExtractFirst', false)
|
|
589
|
+
this._setValue(defaults, 'tracePropagationBehaviorExtract', 'continue')
|
|
587
590
|
this._setValue(defaults, 'tracePropagationStyle.inject', ['datadog', 'tracecontext', 'baggage'])
|
|
588
591
|
this._setValue(defaults, 'tracePropagationStyle.extract', ['datadog', 'tracecontext', 'baggage'])
|
|
589
592
|
this._setValue(defaults, 'tracePropagationStyle.otelPropagators', false)
|
|
@@ -746,6 +749,7 @@ class Config {
|
|
|
746
749
|
DD_TRACE_PARTIAL_FLUSH_MIN_SPANS,
|
|
747
750
|
DD_TRACE_PEER_SERVICE_MAPPING,
|
|
748
751
|
DD_TRACE_PROPAGATION_EXTRACT_FIRST,
|
|
752
|
+
DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT,
|
|
749
753
|
DD_TRACE_PROPAGATION_STYLE,
|
|
750
754
|
DD_TRACE_PROPAGATION_STYLE_INJECT,
|
|
751
755
|
DD_TRACE_PROPAGATION_STYLE_EXTRACT,
|
|
@@ -967,6 +971,11 @@ class Config {
|
|
|
967
971
|
this._setBoolean(env, 'traceId128BitGenerationEnabled', DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
|
|
968
972
|
this._setBoolean(env, 'traceId128BitLoggingEnabled', DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
|
|
969
973
|
this._setBoolean(env, 'tracePropagationExtractFirst', DD_TRACE_PROPAGATION_EXTRACT_FIRST)
|
|
974
|
+
const stringPropagationBehaviorExtract = String(DD_TRACE_PROPAGATION_BEHAVIOR_EXTRACT)
|
|
975
|
+
this._setValue(env, 'tracePropagationBehaviorExtract',
|
|
976
|
+
VALID_PROPAGATION_BEHAVIOR_EXTRACT.has(stringPropagationBehaviorExtract)
|
|
977
|
+
? stringPropagationBehaviorExtract
|
|
978
|
+
: 'continue')
|
|
970
979
|
this._setBoolean(env, 'tracePropagationStyle.otelPropagators',
|
|
971
980
|
DD_TRACE_PROPAGATION_STYLE ||
|
|
972
981
|
DD_TRACE_PROPAGATION_STYLE_INJECT ||
|
|
@@ -2,34 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
|
|
5
|
+
const { DD_EXTERNAL_ENV } = process.env
|
|
6
|
+
|
|
5
7
|
// The second part is the PCF / Garden regexp. We currently assume no suffix($) to avoid matching pod UIDs
|
|
6
8
|
// See https://github.com/DataDog/datadog-agent/blob/7.40.x/pkg/util/cgroups/reader.go#L50
|
|
7
9
|
const uuidSource =
|
|
8
10
|
'[0-9a-f]{8}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{4}[-_][0-9a-f]{12}|[0-9a-f]{8}(?:-[0-9a-f]{4}){4}$'
|
|
9
11
|
const containerSource = '[0-9a-f]{64}'
|
|
10
12
|
const taskSource = '[0-9a-f]{32}-\\d+'
|
|
13
|
+
const lineReg = /^(\d+):([^:]*):(.+)$/
|
|
11
14
|
const entityReg = new RegExp(`.*(${uuidSource}|${containerSource}|${taskSource})(?:\\.scope)?$`, 'm')
|
|
12
15
|
|
|
16
|
+
const cgroup = readControlGroup()
|
|
13
17
|
const entityId = getEntityId()
|
|
18
|
+
const inode = getInode()
|
|
14
19
|
|
|
15
20
|
function getEntityId () {
|
|
16
|
-
const
|
|
17
|
-
const match = cgroup.trim().match(entityReg) || []
|
|
21
|
+
const match = cgroup.match(entityReg) || []
|
|
18
22
|
|
|
19
23
|
return match[1]
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
function getInode () {
|
|
27
|
+
const match = cgroup.match(lineReg) || []
|
|
28
|
+
|
|
29
|
+
return readInode(match[3])
|
|
30
|
+
}
|
|
31
|
+
|
|
22
32
|
function readControlGroup () {
|
|
23
33
|
try {
|
|
24
|
-
return fs.readFileSync('/proc/self/cgroup').toString()
|
|
34
|
+
return fs.readFileSync('/proc/self/cgroup').toString().trim()
|
|
35
|
+
} catch (err) {
|
|
36
|
+
return ''
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readInode (path) {
|
|
41
|
+
if (!path) return 0
|
|
42
|
+
|
|
43
|
+
const strippedPath = path.replace(/^\//, '').replace(/\/$/, '')
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
return fs.statSync(`/sys/fs/cgroup/${strippedPath}`).ino
|
|
25
47
|
} catch (err) {
|
|
26
|
-
|
|
48
|
+
return 0
|
|
27
49
|
}
|
|
28
50
|
}
|
|
29
51
|
|
|
30
52
|
module.exports = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
53
|
+
inject (carrier) {
|
|
54
|
+
if (entityId) {
|
|
55
|
+
carrier['Datadog-Container-Id'] = entityId
|
|
56
|
+
carrier['Datadog-Entity-ID'] = `ci-${entityId}`
|
|
57
|
+
} else if (inode) {
|
|
58
|
+
carrier['Datadog-Entity-ID'] = `in-${inode}`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (DD_EXTERNAL_ENV) {
|
|
62
|
+
carrier['Datadog-External-Env'] = DD_EXTERNAL_ENV
|
|
63
|
+
}
|
|
34
64
|
}
|
|
35
65
|
}
|
|
@@ -15,7 +15,6 @@ const { storage } = require('../../../../datadog-core')
|
|
|
15
15
|
const log = require('../../log')
|
|
16
16
|
|
|
17
17
|
const maxActiveRequests = 8
|
|
18
|
-
const containerId = docker.id()
|
|
19
18
|
|
|
20
19
|
let activeRequests = 0
|
|
21
20
|
|
|
@@ -63,9 +62,7 @@ function request (data, options, callback) {
|
|
|
63
62
|
options.headers['Content-Length'] = byteLength(dataArray)
|
|
64
63
|
}
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
options.headers['Datadog-Container-ID'] = containerId
|
|
68
|
-
}
|
|
65
|
+
docker.inject(options.headers)
|
|
69
66
|
|
|
70
67
|
options.agent = isSecure ? httpsAgent : httpAgent
|
|
71
68
|
|
|
@@ -37,13 +37,13 @@ class LLMObsPlugin extends TracingPlugin {
|
|
|
37
37
|
// register options may not be set for operations we do not trace with llmobs
|
|
38
38
|
// ie OpenAI fine tuning jobs, file jobs, etc.
|
|
39
39
|
if (registerOptions) {
|
|
40
|
-
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: this.constructor.
|
|
40
|
+
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: this.constructor.integration })
|
|
41
41
|
|
|
42
42
|
ctx.llmobs = {} // initialize context-based namespace
|
|
43
43
|
llmobsStorage.enterWith({ span })
|
|
44
44
|
ctx.llmobs.parent = parent
|
|
45
45
|
|
|
46
|
-
this._tagger.registerLLMObsSpan(span, { parent, integration: this.constructor.
|
|
46
|
+
this._tagger.registerLLMObsSpan(span, { parent, integration: this.constructor.integration, ...registerOptions })
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -20,7 +20,8 @@ const ChatModelHandler = require('./handlers/chat_model')
|
|
|
20
20
|
const LlmHandler = require('./handlers/llm')
|
|
21
21
|
const EmbeddingHandler = require('./handlers/embedding')
|
|
22
22
|
|
|
23
|
-
class
|
|
23
|
+
class BaseLangChainLLMObsPlugin extends LLMObsPlugin {
|
|
24
|
+
static get integration () { return 'langchain' }
|
|
24
25
|
static get id () { return 'langchain' }
|
|
25
26
|
static get prefix () {
|
|
26
27
|
return 'tracing:apm:langchain:invoke'
|
|
@@ -55,8 +56,11 @@ class LangChainLLMObsPlugin extends LLMObsPlugin {
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
setLLMObsTags (ctx) {
|
|
59
|
+
ctx.args = ctx.arguments
|
|
60
|
+
ctx.instance = ctx.self
|
|
61
|
+
|
|
58
62
|
const span = ctx.currentStore?.span
|
|
59
|
-
const type = ctx.type // langchain operation type (oneof chain,chat_model,llm,embedding)
|
|
63
|
+
const type = ctx.type = this.constructor.lcType // langchain operation type (oneof chain,chat_model,llm,embedding)
|
|
60
64
|
|
|
61
65
|
if (!Object.keys(this._handlers).includes(type)) {
|
|
62
66
|
log.warn(`Unsupported LangChain operation type: ${type}`)
|
|
@@ -129,4 +133,59 @@ class LangChainLLMObsPlugin extends LLMObsPlugin {
|
|
|
129
133
|
}
|
|
130
134
|
}
|
|
131
135
|
|
|
132
|
-
|
|
136
|
+
class RunnableSequenceInvokePlugin extends BaseLangChainLLMObsPlugin {
|
|
137
|
+
static get id () { return 'llmobs_langchain_rs_invoke' }
|
|
138
|
+
static get lcType () { return 'chain' }
|
|
139
|
+
static get prefix () {
|
|
140
|
+
return 'tracing:orchestrion:@langchain/core:RunnableSequence_invoke'
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
class RunnableSequenceBatchPlugin extends BaseLangChainLLMObsPlugin {
|
|
145
|
+
static get id () { return 'llmobs_langchain_rs_batch' }
|
|
146
|
+
static get lcType () { return 'chain' }
|
|
147
|
+
static get prefix () {
|
|
148
|
+
return 'tracing:orchestrion:@langchain/core:RunnableSequence_batch'
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
class BaseChatModelGeneratePlugin extends BaseLangChainLLMObsPlugin {
|
|
153
|
+
static get id () { return 'llmobs_langchain_chat_model_generate' }
|
|
154
|
+
static get lcType () { return 'chat_model' }
|
|
155
|
+
static get prefix () {
|
|
156
|
+
return 'tracing:orchestrion:@langchain/core:BaseChatModel_generate'
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
class BaseLLMGeneratePlugin extends BaseLangChainLLMObsPlugin {
|
|
161
|
+
static get id () { return 'llmobs_langchain_llm_generate' }
|
|
162
|
+
static get lcType () { return 'llm' }
|
|
163
|
+
static get prefix () {
|
|
164
|
+
return 'tracing:orchestrion:@langchain/core:BaseLLM_generate'
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
class EmbeddingsEmbedQueryPlugin extends BaseLangChainLLMObsPlugin {
|
|
169
|
+
static get id () { return 'llmobs_langchain_embeddings_embed_query' }
|
|
170
|
+
static get lcType () { return 'embedding' }
|
|
171
|
+
static get prefix () {
|
|
172
|
+
return 'tracing:apm:@langchain/core:Embeddings_embedQuery'
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
class EmbeddingsEmbedDocumentsPlugin extends BaseLangChainLLMObsPlugin {
|
|
177
|
+
static get id () { return 'llmobs_langchain_embeddings_embed_documents' }
|
|
178
|
+
static get lcType () { return 'embedding' }
|
|
179
|
+
static get prefix () {
|
|
180
|
+
return 'tracing:apm:@langchain/core:Embeddings_embedDocuments'
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = [
|
|
185
|
+
RunnableSequenceInvokePlugin,
|
|
186
|
+
RunnableSequenceBatchPlugin,
|
|
187
|
+
BaseChatModelGeneratePlugin,
|
|
188
|
+
BaseLLMGeneratePlugin,
|
|
189
|
+
EmbeddingsEmbedQueryPlugin,
|
|
190
|
+
EmbeddingsEmbedDocumentsPlugin
|
|
191
|
+
]
|
|
@@ -7,7 +7,8 @@ const {
|
|
|
7
7
|
} = require('../../../../datadog-plugin-google-cloud-vertexai/src/utils')
|
|
8
8
|
|
|
9
9
|
class VertexAILLMObsPlugin extends LLMObsPlugin {
|
|
10
|
-
static get
|
|
10
|
+
static get integration () { return 'vertexai' } // used for llmobs telemetry
|
|
11
|
+
static get id () { return 'vertexai' }
|
|
11
12
|
static get prefix () {
|
|
12
13
|
return 'tracing:apm:vertexai:request'
|
|
13
14
|
}
|
|
@@ -13,6 +13,7 @@ const defaultLogger = {
|
|
|
13
13
|
let enabled = false
|
|
14
14
|
let logger = defaultLogger
|
|
15
15
|
let logChannel = new LogChannel()
|
|
16
|
+
let stackTraceLimitFunction = onError
|
|
16
17
|
|
|
17
18
|
function withNoop (fn) {
|
|
18
19
|
const store = storage('legacy').getStore()
|
|
@@ -61,12 +62,28 @@ function getErrorLog (err) {
|
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
function setStackTraceLimitFunction (fn) {
|
|
66
|
+
if (typeof fn !== 'function') {
|
|
67
|
+
throw new TypeError('stackTraceLimitFunction must be a function')
|
|
68
|
+
}
|
|
69
|
+
stackTraceLimitFunction = fn
|
|
70
|
+
}
|
|
71
|
+
|
|
64
72
|
function onError (err) {
|
|
65
73
|
const { formatted, cause } = getErrorLog(err)
|
|
66
74
|
|
|
67
75
|
// calling twice logger.error() because Error cause is only available in nodejs v16.9.0
|
|
68
76
|
// TODO: replace it with Error(message, { cause }) when cause has broad support
|
|
69
|
-
if (formatted)
|
|
77
|
+
if (formatted) {
|
|
78
|
+
withNoop(() => {
|
|
79
|
+
const l = Error.stackTraceLimit
|
|
80
|
+
Error.stackTraceLimit = 0
|
|
81
|
+
const e = new Error(formatted)
|
|
82
|
+
Error.stackTraceLimit = l
|
|
83
|
+
Error.captureStackTrace(e, stackTraceLimitFunction)
|
|
84
|
+
logger.error(e)
|
|
85
|
+
})
|
|
86
|
+
}
|
|
70
87
|
if (cause) withNoop(() => logger.error(cause))
|
|
71
88
|
}
|
|
72
89
|
|
|
@@ -122,4 +139,4 @@ function trace (...args) {
|
|
|
122
139
|
onTrace(Log.parse(...args))
|
|
123
140
|
}
|
|
124
141
|
|
|
125
|
-
module.exports = { use, toggle, reset, error, warn, info, debug, trace }
|
|
142
|
+
module.exports = { use, toggle, reset, error, warn, info, debug, trace, setStackTraceLimitFunction }
|
|
@@ -298,6 +298,7 @@ class TextMapPropagator {
|
|
|
298
298
|
|
|
299
299
|
_extractSpanContext (carrier) {
|
|
300
300
|
let context = null
|
|
301
|
+
let style = ''
|
|
301
302
|
for (const extractor of this._config.tracePropagationStyle.extract) {
|
|
302
303
|
let extractedContext = null
|
|
303
304
|
switch (extractor) {
|
|
@@ -331,9 +332,9 @@ class TextMapPropagator {
|
|
|
331
332
|
|
|
332
333
|
if (context === null) {
|
|
333
334
|
context = extractedContext
|
|
335
|
+
style = extractor
|
|
334
336
|
if (this._config.tracePropagationExtractFirst) {
|
|
335
|
-
|
|
336
|
-
return context
|
|
337
|
+
break
|
|
337
338
|
}
|
|
338
339
|
} else {
|
|
339
340
|
// If extractor is tracecontext, add tracecontext specific information to the context
|
|
@@ -342,7 +343,7 @@ class TextMapPropagator {
|
|
|
342
343
|
this._extractTraceparentContext(carrier), context, carrier)
|
|
343
344
|
}
|
|
344
345
|
if (extractedContext._traceId && extractedContext._spanId &&
|
|
345
|
-
|
|
346
|
+
extractedContext.toTraceId(true) !== context.toTraceId(true)) {
|
|
346
347
|
const link = {
|
|
347
348
|
context: extractedContext,
|
|
348
349
|
attributes: { reason: 'terminated_context', context_headers: extractor }
|
|
@@ -354,6 +355,19 @@ class TextMapPropagator {
|
|
|
354
355
|
|
|
355
356
|
this._extractBaggageItems(carrier, context)
|
|
356
357
|
|
|
358
|
+
if (this._config.tracePropagationBehaviorExtract === 'ignore') {
|
|
359
|
+
context._links = []
|
|
360
|
+
} else if (this._config.tracePropagationBehaviorExtract === 'restart') {
|
|
361
|
+
context._links = []
|
|
362
|
+
context._links.push({
|
|
363
|
+
context,
|
|
364
|
+
attributes:
|
|
365
|
+
{
|
|
366
|
+
reason: 'propagation_behavior_extract', context_headers: style
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
|
|
357
371
|
return context || this._extractSqsdContext(carrier)
|
|
358
372
|
}
|
|
359
373
|
|
|
@@ -319,6 +319,12 @@ class DatadogSpan {
|
|
|
319
319
|
let spanContext
|
|
320
320
|
let startTime
|
|
321
321
|
|
|
322
|
+
let baggage = {}
|
|
323
|
+
if (parent && parent._isRemote && this._parentTracer?._config?.tracePropagationBehaviorExtract !== 'continue') {
|
|
324
|
+
baggage = parent._baggageItems
|
|
325
|
+
parent = null
|
|
326
|
+
}
|
|
327
|
+
|
|
322
328
|
if (fields.context) {
|
|
323
329
|
spanContext = fields.context
|
|
324
330
|
if (!spanContext._trace.startTime) {
|
|
@@ -352,6 +358,10 @@ class DatadogSpan {
|
|
|
352
358
|
.padStart(8, '0')
|
|
353
359
|
.padEnd(16, '0')
|
|
354
360
|
}
|
|
361
|
+
|
|
362
|
+
if (this._parentTracer?._config?.tracePropagationBehaviorExtract === 'restart') {
|
|
363
|
+
spanContext._baggageItems = baggage
|
|
364
|
+
}
|
|
355
365
|
}
|
|
356
366
|
|
|
357
367
|
spanContext._trace.ticks = spanContext._trace.ticks || now()
|
|
@@ -120,6 +120,12 @@ const TEST_LEVEL_EVENT_TYPES = [
|
|
|
120
120
|
'test_module_end',
|
|
121
121
|
'test_session_end'
|
|
122
122
|
]
|
|
123
|
+
const TEST_RETRY_REASON_TYPES = {
|
|
124
|
+
efd: 'early_flake_detection',
|
|
125
|
+
atr: 'auto_test_retry',
|
|
126
|
+
atf: 'attempt_to_fix',
|
|
127
|
+
ext: 'external'
|
|
128
|
+
}
|
|
123
129
|
|
|
124
130
|
const DD_TEST_IS_USER_PROVIDED_SERVICE = '_dd.test.is_user_provided_service'
|
|
125
131
|
|
|
@@ -227,6 +233,7 @@ module.exports = {
|
|
|
227
233
|
DD_CAPABILITIES_TEST_MANAGEMENT_DISABLE,
|
|
228
234
|
DD_CAPABILITIES_TEST_MANAGEMENT_ATTEMPT_TO_FIX,
|
|
229
235
|
TEST_LEVEL_EVENT_TYPES,
|
|
236
|
+
TEST_RETRY_REASON_TYPES,
|
|
230
237
|
getNumFromKnownTests,
|
|
231
238
|
getFileAndLineNumberFromError,
|
|
232
239
|
DI_ERROR_DEBUG_INFO_CAPTURED,
|