dd-trace 5.32.0 → 5.33.1

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 (43) hide show
  1. package/README.md +12 -11
  2. package/index.d.ts +11 -1
  3. package/package.json +2 -2
  4. package/packages/datadog-instrumentations/src/aws-sdk.js +3 -1
  5. package/packages/datadog-instrumentations/src/cucumber.js +17 -9
  6. package/packages/datadog-instrumentations/src/jest.js +36 -21
  7. package/packages/datadog-instrumentations/src/mocha/main.js +9 -4
  8. package/packages/datadog-instrumentations/src/mocha/utils.js +4 -2
  9. package/packages/datadog-instrumentations/src/mocha/worker.js +4 -2
  10. package/packages/datadog-instrumentations/src/playwright.js +8 -3
  11. package/packages/datadog-instrumentations/src/vitest.js +35 -11
  12. package/packages/datadog-plugin-amqplib/src/producer.js +9 -1
  13. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +16 -0
  14. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +63 -0
  15. package/packages/datadog-plugin-aws-sdk/src/services/{bedrockruntime.js → bedrockruntime/utils.js} +67 -75
  16. package/packages/datadog-plugin-cucumber/src/index.js +3 -1
  17. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +19 -8
  18. package/packages/datadog-plugin-cypress/src/support.js +6 -2
  19. package/packages/datadog-plugin-fetch/src/index.js +3 -3
  20. package/packages/datadog-plugin-http/src/client.js +5 -33
  21. package/packages/datadog-plugin-jest/src/index.js +4 -1
  22. package/packages/datadog-plugin-langchain/src/handlers/default.js +6 -30
  23. package/packages/datadog-plugin-langchain/src/tracing.js +5 -6
  24. package/packages/datadog-plugin-mocha/src/index.js +3 -1
  25. package/packages/datadog-plugin-openai/src/tracing.js +14 -33
  26. package/packages/datadog-plugin-playwright/src/index.js +3 -1
  27. package/packages/datadog-plugin-vitest/src/index.js +16 -4
  28. package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +3 -3
  29. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +41 -24
  30. package/packages/dd-trace/src/appsec/iast/iast-context.js +12 -0
  31. package/packages/dd-trace/src/appsec/iast/path-line.js +19 -23
  32. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -0
  33. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +75 -24
  34. package/packages/dd-trace/src/appsec/rasp/utils.js +10 -5
  35. package/packages/dd-trace/src/appsec/stack_trace.js +38 -28
  36. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +5 -4
  37. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +5 -3
  38. package/packages/dd-trace/src/config.js +6 -2
  39. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +59 -0
  40. package/packages/dd-trace/src/plugins/ci_plugin.js +1 -0
  41. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +0 -2
  42. package/packages/dd-trace/src/plugins/util/llm.js +35 -0
  43. package/packages/dd-trace/src/plugins/util/test.js +2 -0
@@ -6,6 +6,8 @@ const { IAST_ENABLED_TAG_KEY, IAST_JSON_TAG_KEY } = require('./tags')
6
6
  const standalone = require('../standalone')
7
7
  const { SAMPLING_MECHANISM_APPSEC } = require('../../constants')
8
8
  const { keepTrace } = require('../../priority_sampler')
9
+ const { reportStackTrace, getCallsiteFrames, canReportStackTrace, STACK_TRACE_NAMESPACES } = require('../stack_trace')
10
+ const { getOriginalPathAndLineFromSourceMap } = require('./taint-tracking/rewriter')
9
11
 
10
12
  const VULNERABILITIES_KEY = 'vulnerabilities'
11
13
  const VULNERABILITY_HASHES_MAX_SIZE = 1000
@@ -15,39 +17,60 @@ const RESET_VULNERABILITY_CACHE_INTERVAL = 60 * 60 * 1000 // 1 hour
15
17
  let tracer
16
18
  let resetVulnerabilityCacheTimer
17
19
  let deduplicationEnabled = true
20
+ let stackTraceEnabled = true
21
+ let stackTraceMaxDepth
22
+ let maxStackTraces
18
23
 
19
- function addVulnerability (iastContext, vulnerability) {
20
- if (vulnerability?.evidence && vulnerability?.type && vulnerability?.location) {
21
- if (deduplicationEnabled && isDuplicatedVulnerability(vulnerability)) return
24
+ function canAddVulnerability (vulnerability) {
25
+ const hasRequiredFields = vulnerability?.evidence && vulnerability?.type && vulnerability?.location
26
+ if (!hasRequiredFields) return false
22
27
 
23
- VULNERABILITY_HASHES.set(`${vulnerability.type}${vulnerability.hash}`, true)
28
+ const isDuplicated = deduplicationEnabled && isDuplicatedVulnerability(vulnerability)
24
29
 
25
- let span = iastContext?.rootSpan
30
+ return !isDuplicated
31
+ }
26
32
 
27
- if (!span && tracer) {
28
- span = tracer.startSpan('vulnerability', {
29
- type: 'vulnerability'
30
- })
33
+ function addVulnerability (iastContext, vulnerability, callSiteFrames) {
34
+ if (!canAddVulnerability(vulnerability)) return
31
35
 
32
- vulnerability.location.spanId = span.context().toSpanId()
36
+ VULNERABILITY_HASHES.set(`${vulnerability.type}${vulnerability.hash}`, true)
33
37
 
34
- span.addTags({
35
- [IAST_ENABLED_TAG_KEY]: 1
36
- })
37
- }
38
+ let span = iastContext?.rootSpan
38
39
 
39
- if (!span) return
40
+ if (!span && tracer) {
41
+ span = tracer.startSpan('vulnerability', {
42
+ type: 'vulnerability'
43
+ })
40
44
 
41
- keepTrace(span, SAMPLING_MECHANISM_APPSEC)
42
- standalone.sample(span)
45
+ vulnerability.location.spanId = span.context().toSpanId()
43
46
 
44
- if (iastContext?.rootSpan) {
45
- iastContext[VULNERABILITIES_KEY] = iastContext[VULNERABILITIES_KEY] || []
46
- iastContext[VULNERABILITIES_KEY].push(vulnerability)
47
- } else {
48
- sendVulnerabilities([vulnerability], span)
49
- span.finish()
50
- }
47
+ span.addTags({
48
+ [IAST_ENABLED_TAG_KEY]: 1
49
+ })
50
+ }
51
+
52
+ if (!span) return
53
+
54
+ keepTrace(span, SAMPLING_MECHANISM_APPSEC)
55
+ standalone.sample(span)
56
+
57
+ if (stackTraceEnabled && canReportStackTrace(span, maxStackTraces, STACK_TRACE_NAMESPACES.IAST)) {
58
+ const originalCallSiteList = callSiteFrames.map(callsite => replaceCallSiteFromSourceMap(callsite))
59
+
60
+ reportStackTrace(
61
+ span,
62
+ vulnerability.stackId,
63
+ originalCallSiteList,
64
+ STACK_TRACE_NAMESPACES.IAST
65
+ )
66
+ }
67
+
68
+ if (iastContext?.rootSpan) {
69
+ iastContext[VULNERABILITIES_KEY] = iastContext[VULNERABILITIES_KEY] || []
70
+ iastContext[VULNERABILITIES_KEY].push(vulnerability)
71
+ } else {
72
+ sendVulnerabilities([vulnerability], span)
73
+ span.finish()
51
74
  }
52
75
  }
53
76
 
@@ -94,8 +117,34 @@ function isDuplicatedVulnerability (vulnerability) {
94
117
  return VULNERABILITY_HASHES.get(`${vulnerability.type}${vulnerability.hash}`)
95
118
  }
96
119
 
120
+ function getVulnerabilityCallSiteFrames () {
121
+ return getCallsiteFrames(stackTraceMaxDepth)
122
+ }
123
+
124
+ function replaceCallSiteFromSourceMap (callsite) {
125
+ if (callsite) {
126
+ const { path, line, column } = getOriginalPathAndLineFromSourceMap(callsite)
127
+ if (path) {
128
+ callsite.file = path
129
+ callsite.path = path
130
+ }
131
+ if (line) {
132
+ callsite.line = line
133
+ }
134
+ if (column) {
135
+ callsite.column = column
136
+ }
137
+ }
138
+
139
+ return callsite
140
+ }
141
+
97
142
  function start (config, _tracer) {
98
143
  deduplicationEnabled = config.iast.deduplicationEnabled
144
+ stackTraceEnabled = config.iast.stackTrace.enabled
145
+ stackTraceMaxDepth = config.appsec.stackTrace.maxDepth
146
+ maxStackTraces = config.appsec.stackTrace.maxStackTraces
147
+
99
148
  vulnerabilitiesFormatter.setRedactVulnerabilities(
100
149
  config.iast.redactionEnabled,
101
150
  config.iast.redactionNamePattern,
@@ -114,6 +163,8 @@ function stop () {
114
163
  module.exports = {
115
164
  addVulnerability,
116
165
  sendVulnerabilities,
166
+ getVulnerabilityCallSiteFrames,
167
+ replaceCallSiteFromSourceMap,
117
168
  clearCache,
118
169
  start,
119
170
  stop
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const web = require('../../plugins/util/web')
4
- const { reportStackTrace } = require('../stack_trace')
4
+ const { getCallsiteFrames, reportStackTrace, canReportStackTrace } = require('../stack_trace')
5
5
  const { getBlockingAction } = require('../blocking')
6
6
  const log = require('../../log')
7
7
 
@@ -30,13 +30,18 @@ class DatadogRaspAbortError extends Error {
30
30
 
31
31
  function handleResult (actions, req, res, abortController, config) {
32
32
  const generateStackTraceAction = actions?.generate_stack
33
- if (generateStackTraceAction && config.appsec.stackTrace.enabled) {
34
- const rootSpan = web.root(req)
33
+
34
+ const { enabled, maxDepth, maxStackTraces } = config.appsec.stackTrace
35
+
36
+ const rootSpan = web.root(req)
37
+
38
+ if (generateStackTraceAction && enabled && canReportStackTrace(rootSpan, maxStackTraces)) {
39
+ const frames = getCallsiteFrames(maxDepth)
40
+
35
41
  reportStackTrace(
36
42
  rootSpan,
37
43
  generateStackTraceAction.stack_id,
38
- config.appsec.stackTrace.maxDepth,
39
- config.appsec.stackTrace.maxStackTraces
44
+ frames
40
45
  )
41
46
  }
42
47
 
@@ -6,11 +6,18 @@ const ddBasePath = calculateDDBasePath(__dirname)
6
6
 
7
7
  const LIBRARY_FRAMES_BUFFER = 20
8
8
 
9
+ const STACK_TRACE_NAMESPACES = {
10
+ RASP: 'exploit',
11
+ IAST: 'vulnerability'
12
+ }
13
+
9
14
  function getCallSiteList (maxDepth = 100) {
10
15
  const previousPrepareStackTrace = Error.prepareStackTrace
11
16
  const previousStackTraceLimit = Error.stackTraceLimit
12
17
  let callsiteList
13
- Error.stackTraceLimit = maxDepth
18
+ // Since some frames will be discarded because they come from tracer codebase, a buffer is added
19
+ // to the limit in order to get as close as `maxDepth` number of frames.
20
+ Error.stackTraceLimit = maxDepth + LIBRARY_FRAMES_BUFFER
14
21
 
15
22
  try {
16
23
  Error.prepareStackTrace = function (_, callsites) {
@@ -30,7 +37,10 @@ function filterOutFramesFromLibrary (callSiteList) {
30
37
  return callSiteList.filter(callSite => !callSite.getFileName()?.startsWith(ddBasePath))
31
38
  }
32
39
 
33
- function getFramesForMetaStruct (callSiteList, maxDepth = 32) {
40
+ function getCallsiteFrames (maxDepth = 32, callSiteListGetter = getCallSiteList) {
41
+ if (maxDepth < 1) maxDepth = Infinity
42
+
43
+ const callSiteList = callSiteListGetter(maxDepth)
34
44
  const filteredFrames = filterOutFramesFromLibrary(callSiteList)
35
45
 
36
46
  const half = filteredFrames.length > maxDepth ? Math.round(maxDepth / 2) : Infinity
@@ -45,46 +55,46 @@ function getFramesForMetaStruct (callSiteList, maxDepth = 32) {
45
55
  line: callSite.getLineNumber(),
46
56
  column: callSite.getColumnNumber(),
47
57
  function: callSite.getFunctionName(),
48
- class_name: callSite.getTypeName()
58
+ class_name: callSite.getTypeName(),
59
+ isNative: callSite.isNative()
49
60
  })
50
61
  }
51
62
 
52
63
  return indexedFrames
53
64
  }
54
65
 
55
- function reportStackTrace (rootSpan, stackId, maxDepth, maxStackTraces, callSiteListGetter = getCallSiteList) {
66
+ function reportStackTrace (rootSpan, stackId, frames, namespace = STACK_TRACE_NAMESPACES.RASP) {
56
67
  if (!rootSpan) return
68
+ if (!Array.isArray(frames)) return
57
69
 
58
- if (maxStackTraces < 1 || (rootSpan.meta_struct?.['_dd.stack']?.exploit?.length ?? 0) < maxStackTraces) {
59
- // Since some frames will be discarded because they come from tracer codebase, a buffer is added
60
- // to the limit in order to get as close as `maxDepth` number of frames.
61
- if (maxDepth < 1) maxDepth = Infinity
62
- const callSiteList = callSiteListGetter(maxDepth + LIBRARY_FRAMES_BUFFER)
63
- if (!Array.isArray(callSiteList)) return
70
+ if (!rootSpan.meta_struct) {
71
+ rootSpan.meta_struct = {}
72
+ }
64
73
 
65
- if (!rootSpan.meta_struct) {
66
- rootSpan.meta_struct = {}
67
- }
74
+ if (!rootSpan.meta_struct['_dd.stack']) {
75
+ rootSpan.meta_struct['_dd.stack'] = {}
76
+ }
68
77
 
69
- if (!rootSpan.meta_struct['_dd.stack']) {
70
- rootSpan.meta_struct['_dd.stack'] = {}
71
- }
78
+ if (!rootSpan.meta_struct['_dd.stack'][namespace]) {
79
+ rootSpan.meta_struct['_dd.stack'][namespace] = []
80
+ }
72
81
 
73
- if (!rootSpan.meta_struct['_dd.stack'].exploit) {
74
- rootSpan.meta_struct['_dd.stack'].exploit = []
75
- }
82
+ rootSpan.meta_struct['_dd.stack'][namespace].push({
83
+ id: stackId,
84
+ language: 'nodejs',
85
+ frames
86
+ })
87
+ }
76
88
 
77
- const frames = getFramesForMetaStruct(callSiteList, maxDepth)
89
+ function canReportStackTrace (rootSpan, maxStackTraces, namespace = STACK_TRACE_NAMESPACES.RASP) {
90
+ if (!rootSpan) return false
78
91
 
79
- rootSpan.meta_struct['_dd.stack'].exploit.push({
80
- id: stackId,
81
- language: 'nodejs',
82
- frames
83
- })
84
- }
92
+ return maxStackTraces < 1 || (rootSpan.meta_struct?.['_dd.stack']?.[namespace]?.length ?? 0) < maxStackTraces
85
93
  }
86
94
 
87
95
  module.exports = {
88
- getCallSiteList,
89
- reportStackTrace
96
+ getCallsiteFrames,
97
+ reportStackTrace,
98
+ canReportStackTrace,
99
+ STACK_TRACE_NAMESPACES
90
100
  }
@@ -87,9 +87,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
87
87
 
88
88
  shouldRequestKnownTests () {
89
89
  return !!(
90
- this._config.isEarlyFlakeDetectionEnabled &&
91
90
  this._canUseCiVisProtocol &&
92
- this._libraryConfig?.isEarlyFlakeDetectionEnabled
91
+ this._libraryConfig?.isKnownTestsEnabled
93
92
  )
94
93
  }
95
94
 
@@ -197,7 +196,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
197
196
  earlyFlakeDetectionNumRetries,
198
197
  earlyFlakeDetectionFaultyThreshold,
199
198
  isFlakyTestRetriesEnabled,
200
- isDiEnabled
199
+ isDiEnabled,
200
+ isKnownTestsEnabled
201
201
  } = remoteConfiguration
202
202
  return {
203
203
  isCodeCoverageEnabled,
@@ -209,7 +209,8 @@ class CiVisibilityExporter extends AgentInfoExporter {
209
209
  earlyFlakeDetectionFaultyThreshold,
210
210
  isFlakyTestRetriesEnabled: isFlakyTestRetriesEnabled && this._config.isFlakyTestRetriesEnabled,
211
211
  flakyTestRetriesCount: this._config.flakyTestRetriesCount,
212
- isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled
212
+ isDiEnabled: isDiEnabled && this._config.isTestDynamicInstrumentationEnabled,
213
+ isKnownTestsEnabled
213
214
  }
214
215
  }
215
216
 
@@ -93,7 +93,8 @@ function getLibraryConfiguration ({
93
93
  require_git: requireGit,
94
94
  early_flake_detection: earlyFlakeDetectionConfig,
95
95
  flaky_test_retries_enabled: isFlakyTestRetriesEnabled,
96
- di_enabled: isDiEnabled
96
+ di_enabled: isDiEnabled,
97
+ known_tests_enabled: isKnownTestsEnabled
97
98
  }
98
99
  }
99
100
  } = JSON.parse(res)
@@ -103,13 +104,14 @@ function getLibraryConfiguration ({
103
104
  isSuitesSkippingEnabled,
104
105
  isItrEnabled,
105
106
  requireGit,
106
- isEarlyFlakeDetectionEnabled: earlyFlakeDetectionConfig?.enabled ?? false,
107
+ isEarlyFlakeDetectionEnabled: isKnownTestsEnabled && (earlyFlakeDetectionConfig?.enabled ?? false),
107
108
  earlyFlakeDetectionNumRetries:
108
109
  earlyFlakeDetectionConfig?.slow_test_retries?.['5s'] || DEFAULT_EARLY_FLAKE_DETECTION_NUM_RETRIES,
109
110
  earlyFlakeDetectionFaultyThreshold:
110
111
  earlyFlakeDetectionConfig?.faulty_session_threshold ?? DEFAULT_EARLY_FLAKE_DETECTION_ERROR_THRESHOLD,
111
112
  isFlakyTestRetriesEnabled,
112
- isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled
113
+ isDiEnabled: isDiEnabled && isFlakyTestRetriesEnabled,
114
+ isKnownTestsEnabled
113
115
  }
114
116
 
115
117
  log.debug(() => `Remote settings: ${JSON.stringify(settings)}`)
@@ -497,6 +497,7 @@ class Config {
497
497
  this._setValue(defaults, 'iast.redactionValuePattern', null)
498
498
  this._setValue(defaults, 'iast.requestSampling', 30)
499
499
  this._setValue(defaults, 'iast.telemetryVerbosity', 'INFORMATION')
500
+ this._setValue(defaults, 'iast.stackTrace.enabled', true)
500
501
  this._setValue(defaults, 'injectionEnabled', [])
501
502
  this._setValue(defaults, 'isAzureFunction', false)
502
503
  this._setValue(defaults, 'isCiVisibility', false)
@@ -521,7 +522,7 @@ class Config {
521
522
  this._setValue(defaults, 'inferredProxyServicesEnabled', false)
522
523
  this._setValue(defaults, 'memcachedCommandEnabled', false)
523
524
  this._setValue(defaults, 'openAiLogsEnabled', false)
524
- this._setValue(defaults, 'openaiSpanCharLimit', 128)
525
+ this._setValue(defaults, 'openai.spanCharLimit', 128)
525
526
  this._setValue(defaults, 'peerServiceMapping', {})
526
527
  this._setValue(defaults, 'plugins', true)
527
528
  this._setValue(defaults, 'port', '8126')
@@ -622,6 +623,7 @@ class Config {
622
623
  DD_IAST_REDACTION_VALUE_PATTERN,
623
624
  DD_IAST_REQUEST_SAMPLING,
624
625
  DD_IAST_TELEMETRY_VERBOSITY,
626
+ DD_IAST_STACK_TRACE_ENABLED,
625
627
  DD_INJECTION_ENABLED,
626
628
  DD_INSTRUMENTATION_TELEMETRY_ENABLED,
627
629
  DD_INSTRUMENTATION_CONFIG_ID,
@@ -787,6 +789,7 @@ class Config {
787
789
  }
788
790
  this._envUnprocessed['iast.requestSampling'] = DD_IAST_REQUEST_SAMPLING
789
791
  this._setString(env, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY)
792
+ this._setBoolean(env, 'iast.stackTrace.enabled', DD_IAST_STACK_TRACE_ENABLED)
790
793
  this._setArray(env, 'injectionEnabled', DD_INJECTION_ENABLED)
791
794
  this._setBoolean(env, 'isAzureFunction', getIsAzureFunction())
792
795
  this._setBoolean(env, 'isGCPFunction', getIsGCPFunction())
@@ -802,7 +805,7 @@ class Config {
802
805
  // Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
803
806
  this._setBoolean(env, 'memcachedCommandEnabled', DD_TRACE_MEMCACHED_COMMAND_ENABLED)
804
807
  this._setBoolean(env, 'openAiLogsEnabled', DD_OPENAI_LOGS_ENABLED)
805
- this._setValue(env, 'openaiSpanCharLimit', maybeInt(DD_OPENAI_SPAN_CHAR_LIMIT))
808
+ this._setValue(env, 'openai.spanCharLimit', maybeInt(DD_OPENAI_SPAN_CHAR_LIMIT))
806
809
  this._envUnprocessed.openaiSpanCharLimit = DD_OPENAI_SPAN_CHAR_LIMIT
807
810
  if (DD_TRACE_PEER_SERVICE_MAPPING) {
808
811
  this._setValue(env, 'peerServiceMapping', fromEntries(
@@ -976,6 +979,7 @@ class Config {
976
979
  this._optsUnprocessed['iast.requestSampling'] = options.iast?.requestSampling
977
980
  }
978
981
  this._setString(opts, 'iast.telemetryVerbosity', options.iast && options.iast.telemetryVerbosity)
982
+ this._setBoolean(opts, 'iast.stackTrace.enabled', options.iast?.stackTrace?.enabled)
979
983
  this._setBoolean(opts, 'isCiVisibility', options.isCiVisibility)
980
984
  this._setBoolean(opts, 'legacyBaggageEnabled', options.legacyBaggageEnabled)
981
985
  this._setBoolean(opts, 'llmobs.agentlessEnabled', options.llmobs?.agentlessEnabled)
@@ -0,0 +1,59 @@
1
+ const BaseLLMObsPlugin = require('./base')
2
+ const { storage } = require('../../../../datadog-core')
3
+ const llmobsStore = storage('llmobs')
4
+
5
+ const {
6
+ extractRequestParams,
7
+ extractTextAndResponseReason,
8
+ parseModelId
9
+ } = require('../../../../datadog-plugin-aws-sdk/src/services/bedrockruntime/utils')
10
+
11
+ const enabledOperations = ['invokeModel']
12
+
13
+ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
14
+ constructor () {
15
+ super(...arguments)
16
+
17
+ this.addSub('apm:aws:request:complete:bedrockruntime', ({ response }) => {
18
+ const request = response.request
19
+ const operation = request.operation
20
+ // avoids instrumenting other non supported runtime operations
21
+ if (!enabledOperations.includes(operation)) {
22
+ return
23
+ }
24
+ const { modelProvider, modelName } = parseModelId(request.params.modelId)
25
+
26
+ // avoids instrumenting non llm type
27
+ if (modelName.includes('embed')) {
28
+ return
29
+ }
30
+ const span = storage.getStore()?.span
31
+ this.setLLMObsTags({ request, span, response, modelProvider, modelName })
32
+ })
33
+ }
34
+
35
+ setLLMObsTags ({ request, span, response, modelProvider, modelName }) {
36
+ const parent = llmobsStore.getStore()?.span
37
+ this._tagger.registerLLMObsSpan(span, {
38
+ parent,
39
+ modelName: modelName.toLowerCase(),
40
+ modelProvider: modelProvider.toLowerCase(),
41
+ kind: 'llm',
42
+ name: 'bedrock-runtime.command'
43
+ })
44
+
45
+ const requestParams = extractRequestParams(request.params, modelProvider)
46
+ const textAndResponseReason = extractTextAndResponseReason(response, modelProvider, modelName)
47
+
48
+ // add metadata tags
49
+ this._tagger.tagMetadata(span, {
50
+ temperature: parseFloat(requestParams.temperature) || 0.0,
51
+ max_tokens: parseInt(requestParams.maxTokens) || 0
52
+ })
53
+
54
+ // add I/O tags
55
+ this._tagger.tagLLMIO(span, requestParams.prompt, textAndResponseReason.message)
56
+ }
57
+ }
58
+
59
+ module.exports = BedrockRuntimeLLMObsPlugin
@@ -158,6 +158,7 @@ module.exports = class CiPlugin extends Plugin {
158
158
  if (err) {
159
159
  log.error('Known tests could not be fetched. %s', err.message)
160
160
  this.libraryConfig.isEarlyFlakeDetectionEnabled = false
161
+ this.libraryConfig.isKnownTestsEnabled = false
161
162
  }
162
163
  onDone({ err, knownTests })
163
164
  })
@@ -2,7 +2,6 @@ const log = require('../../log')
2
2
  const tags = require('../../../../../ext/tags')
3
3
 
4
4
  const RESOURCE_NAME = tags.RESOURCE_NAME
5
- const HTTP_ROUTE = tags.HTTP_ROUTE
6
5
  const SPAN_KIND = tags.SPAN_KIND
7
6
  const SPAN_TYPE = tags.SPAN_TYPE
8
7
  const HTTP_URL = tags.HTTP_URL
@@ -54,7 +53,6 @@ function createInferredProxySpan (headers, childOf, tracer, context) {
54
53
  [SPAN_TYPE]: 'web',
55
54
  [HTTP_METHOD]: proxyContext.method,
56
55
  [HTTP_URL]: proxyContext.domainName + proxyContext.path,
57
- [HTTP_ROUTE]: proxyContext.path,
58
56
  stage: proxyContext.stage
59
57
  }
60
58
  }
@@ -0,0 +1,35 @@
1
+ const Sampler = require('../../sampler')
2
+
3
+ const RE_NEWLINE = /\n/g
4
+ const RE_TAB = /\t/g
5
+
6
+ function normalize (text, limit = 128) {
7
+ if (!text) return
8
+ if (typeof text !== 'string' || !text || (typeof text === 'string' && text.length === 0)) return
9
+
10
+ text = text
11
+ .replace(RE_NEWLINE, '\\n')
12
+ .replace(RE_TAB, '\\t')
13
+
14
+ if (text.length > limit) {
15
+ return text.substring(0, limit) + '...'
16
+ }
17
+
18
+ return text
19
+ }
20
+
21
+ function isPromptCompletionSampled (sampler) {
22
+ return sampler.isSampled()
23
+ }
24
+
25
+ module.exports = function (integrationName, tracerConfig) {
26
+ const integrationConfig = tracerConfig[integrationName] || {}
27
+ const { spanCharLimit, spanPromptCompletionSampleRate } = integrationConfig
28
+
29
+ const sampler = new Sampler(spanPromptCompletionSampleRate ?? 1.0)
30
+
31
+ return {
32
+ normalize: str => normalize(str, spanCharLimit),
33
+ isPromptCompletionSampled: () => isPromptCompletionSampled(sampler)
34
+ }
35
+ }
@@ -59,6 +59,7 @@ const TEST_IS_NEW = 'test.is_new'
59
59
  const TEST_IS_RETRY = 'test.is_retry'
60
60
  const TEST_EARLY_FLAKE_ENABLED = 'test.early_flake.enabled'
61
61
  const TEST_EARLY_FLAKE_ABORT_REASON = 'test.early_flake.abort_reason'
62
+ const TEST_RETRY_REASON = 'test.retry_reason'
62
63
 
63
64
  const CI_APP_ORIGIN = 'ciapp-test'
64
65
 
@@ -145,6 +146,7 @@ module.exports = {
145
146
  TEST_IS_RETRY,
146
147
  TEST_EARLY_FLAKE_ENABLED,
147
148
  TEST_EARLY_FLAKE_ABORT_REASON,
149
+ TEST_RETRY_REASON,
148
150
  getTestEnvironmentMetadata,
149
151
  getTestParametersString,
150
152
  finishAllTraceSpans,