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.
Files changed (41) hide show
  1. package/LICENSE-3rdparty.csv +1 -2
  2. package/package.json +8 -9
  3. package/packages/datadog-instrumentations/orchestrion.yml +52 -0
  4. package/packages/datadog-instrumentations/src/cucumber.js +2 -1
  5. package/packages/datadog-instrumentations/src/jest.js +11 -2
  6. package/packages/datadog-instrumentations/src/langchain.js +49 -53
  7. package/packages/datadog-instrumentations/src/mocha/main.js +1 -1
  8. package/packages/datadog-instrumentations/src/mocha/utils.js +11 -3
  9. package/packages/datadog-instrumentations/src/orchestrion-config/index.js +5 -0
  10. package/packages/datadog-instrumentations/src/playwright.js +14 -2
  11. package/packages/datadog-instrumentations/src/vitest.js +11 -3
  12. package/packages/datadog-plugin-cucumber/src/index.js +11 -4
  13. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +17 -5
  14. package/packages/datadog-plugin-jest/src/index.js +11 -4
  15. package/packages/datadog-plugin-langchain/src/index.js +18 -12
  16. package/packages/datadog-plugin-langchain/src/tracing.js +66 -6
  17. package/packages/datadog-plugin-mocha/src/index.js +17 -5
  18. package/packages/datadog-plugin-mongodb-core/src/index.js +5 -1
  19. package/packages/datadog-plugin-playwright/src/index.js +10 -3
  20. package/packages/datadog-plugin-vitest/src/index.js +13 -8
  21. package/packages/datadog-shimmer/src/shimmer.js +3 -42
  22. package/packages/dd-trace/src/appsec/iast/taint-tracking/filter.js +3 -3
  23. package/packages/dd-trace/src/appsec/iast/taint-tracking/index.js +0 -3
  24. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-esm.mjs +24 -11
  25. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter-telemetry.js +3 -32
  26. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +98 -56
  27. package/packages/dd-trace/src/config.js +9 -0
  28. package/packages/dd-trace/src/exporters/common/docker.js +37 -7
  29. package/packages/dd-trace/src/exporters/common/request.js +1 -4
  30. package/packages/dd-trace/src/llmobs/plugins/base.js +2 -2
  31. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +62 -3
  32. package/packages/dd-trace/src/llmobs/plugins/openai.js +1 -0
  33. package/packages/dd-trace/src/llmobs/plugins/vertexai.js +2 -1
  34. package/packages/dd-trace/src/log/index.js +2 -0
  35. package/packages/dd-trace/src/log/writer.js +19 -2
  36. package/packages/dd-trace/src/opentracing/propagation/text_map.js +17 -3
  37. package/packages/dd-trace/src/opentracing/span.js +10 -0
  38. package/packages/dd-trace/src/plugins/util/test.js +7 -0
  39. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -5
  40. package/packages/dd-trace/src/profiling/profilers/wall.js +3 -1
  41. 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, isNotLibraryFile } = require('./filter')
7
+ const { isPrivateModule, isDdTrace } = require('./filter')
8
8
  const { csiMethods } = require('./csi-methods')
9
9
  const { getName } = require('../telemetry/verbosity')
10
- const { getRewriteFunction, incrementTelemetryIfNeeded } = require('./rewriter-telemetry')
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 getGetOriginalPathAndLineFromSourceMapFunction (chainSourceMap, getOriginalPathAndLineFromSourceMap) {
32
- if (chainSourceMap) {
33
- return function (path, line, column) {
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
- if (isPrivateModule(path) && isNotLibraryFile(path)) {
37
- return { path, line, column }
38
- } else {
39
- return getOriginalPathAndLineFromSourceMap(path, line, column)
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
- const getOriginalPathAndLineFromSourceMap = iastRewriter.getOriginalPathAndLineFromSourceMap
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('[ASM] Unable to initialize TaintTracking Rewriter', e)
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
- const rewriteFn = getRewriteFunction(rewriter)
93
- return function (content, filename) {
96
+ let delegate = function (content, filename) {
94
97
  try {
95
- if (isPrivateModule(filename) && isNotLibraryFile(filename)) {
96
- const rewritten = rewriteFn(content, filename)
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
- if (rewritten?.literalsResult && hardcodedSecretCh.hasSubscribers) {
99
- hardcodedSecretCh.publish(rewritten.literalsResult)
100
- }
108
+ incrementTelemetryIfNeeded(rewritten.metrics)
101
109
 
102
- if (rewritten?.content) {
103
- return compileMethod.apply(this, [rewritten.content, filename])
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('[ASM] Error rewriting file %s', filename, e)
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
- const rewriter = getRewriter(telemetryVerbosity)
134
- if (rewriter) {
135
- const pstDescriptor = Object.getOwnPropertyDescriptor(global.Error, 'prepareStackTrace')
136
- if (!pstDescriptor || pstDescriptor.configurable) {
137
- Object.defineProperty(global.Error, 'prepareStackTrace', getPrepareStackTraceAccessor())
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('[ASM] Error enabling TaintTracking Rewriter', e)
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('[ASM] Error enabling ESM Rewriter', e)
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 disableRewriter () {
201
- shimmer.unwrap(Module.prototype, '_compile')
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('[ASM] Error disabling TaintTracking rewriter', e)
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
- enableRewriter, disableRewriter, getOriginalPathAndLineFromSourceMap
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 cgroup = readControlGroup() || ''
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
- // ignore
48
+ return 0
27
49
  }
28
50
  }
29
51
 
30
52
  module.exports = {
31
- // can be the container ID but not always depending on the orchestrator
32
- id () {
33
- return entityId
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
- if (containerId) {
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.id })
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.id, ...registerOptions })
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 LangChainLLMObsPlugin extends LLMObsPlugin {
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
- module.exports = LangChainLLMObsPlugin
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
+ ]
@@ -11,6 +11,7 @@ function isIterable (obj) {
11
11
 
12
12
  class OpenAiLLMObsPlugin extends LLMObsPlugin {
13
13
  static get id () { return 'openai' }
14
+ static get integration () { return 'openai' }
14
15
  static get prefix () {
15
16
  return 'tracing:apm:openai:request'
16
17
  }
@@ -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 id () { return 'vertexai' } // used for llmobs telemetry
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
  }
@@ -121,6 +121,8 @@ const log = {
121
121
  }
122
122
  }
123
123
 
124
+ logWriter.setStackTraceLimitFunction(log.error)
125
+
124
126
  log.reset()
125
127
 
126
128
  log.toggle(log.isEnabled(), log.getLogLevel())
@@ -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) withNoop(() => logger.error(new Error(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
- this._extractBaggageItems(carrier, context)
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
- extractedContext.toTraceId(true) !== context.toTraceId(true)) {
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,