dd-trace 5.67.0 → 5.68.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 (104) hide show
  1. package/LICENSE-3rdparty.csv +0 -3
  2. package/README.md +0 -2
  3. package/ci/init.js +52 -54
  4. package/ext/exporters.d.ts +2 -1
  5. package/ext/exporters.js +2 -1
  6. package/index.d.ts +47 -2
  7. package/initialize.mjs +1 -1
  8. package/package.json +8 -11
  9. package/packages/datadog-esbuild/index.js +56 -0
  10. package/packages/datadog-instrumentations/src/aws-sdk.js +42 -4
  11. package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
  12. package/packages/datadog-instrumentations/src/azure-service-bus.js +1 -1
  13. package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
  14. package/packages/datadog-instrumentations/src/connect.js +6 -2
  15. package/packages/datadog-instrumentations/src/cucumber.js +31 -6
  16. package/packages/datadog-instrumentations/src/express.js +5 -6
  17. package/packages/datadog-instrumentations/src/fastify.js +3 -3
  18. package/packages/datadog-instrumentations/src/helpers/hook.js +28 -15
  19. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  20. package/packages/datadog-instrumentations/src/helpers/instrument.js +11 -2
  21. package/packages/datadog-instrumentations/src/helpers/register.js +10 -3
  22. package/packages/datadog-instrumentations/src/http2/client.js +1 -0
  23. package/packages/datadog-instrumentations/src/http2/server.js +0 -1
  24. package/packages/datadog-instrumentations/src/ioredis.js +12 -1
  25. package/packages/datadog-instrumentations/src/jest.js +48 -36
  26. package/packages/datadog-instrumentations/src/limitd-client.js +2 -1
  27. package/packages/datadog-instrumentations/src/mocha/main.js +15 -7
  28. package/packages/datadog-instrumentations/src/mocha/utils.js +3 -0
  29. package/packages/datadog-instrumentations/src/mongoose.js +2 -1
  30. package/packages/datadog-instrumentations/src/oracledb.js +19 -13
  31. package/packages/datadog-instrumentations/src/pg.js +9 -5
  32. package/packages/datadog-instrumentations/src/pino.js +18 -6
  33. package/packages/datadog-instrumentations/src/playwright.js +15 -1
  34. package/packages/datadog-instrumentations/src/sequelize.js +1 -1
  35. package/packages/datadog-instrumentations/src/vitest.js +155 -62
  36. package/packages/datadog-plugin-ai/src/tracing.js +3 -3
  37. package/packages/datadog-plugin-aws-sdk/src/base.js +23 -8
  38. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
  39. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +101 -2
  40. package/packages/datadog-plugin-aws-sdk/src/util.js +1 -1
  41. package/packages/datadog-plugin-cucumber/src/index.js +4 -56
  42. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -2
  43. package/packages/datadog-plugin-cypress/src/support.js +4 -0
  44. package/packages/datadog-plugin-express/src/code_origin.js +2 -2
  45. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -2
  46. package/packages/datadog-plugin-jest/src/index.js +0 -21
  47. package/packages/datadog-plugin-mocha/src/index.js +3 -57
  48. package/packages/datadog-plugin-mongodb-core/src/index.js +20 -7
  49. package/packages/datadog-plugin-playwright/src/index.js +11 -5
  50. package/packages/datadog-plugin-vitest/src/index.js +5 -1
  51. package/packages/datadog-plugin-ws/src/close.js +1 -1
  52. package/packages/datadog-plugin-ws/src/producer.js +6 -1
  53. package/packages/datadog-plugin-ws/src/receiver.js +6 -1
  54. package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +1 -1
  55. package/packages/dd-trace/src/appsec/telemetry/waf.js +2 -2
  56. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -4
  57. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +11 -3
  58. package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +10 -1
  59. package/packages/dd-trace/src/config.js +69 -304
  60. package/packages/dd-trace/src/config_defaults.js +186 -0
  61. package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -1
  62. package/packages/dd-trace/src/datastreams/fnv.js +2 -2
  63. package/packages/dd-trace/src/datastreams/writer.js +3 -2
  64. package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
  65. package/packages/dd-trace/src/dogstatsd.js +4 -3
  66. package/packages/dd-trace/src/encode/0.4.js +1 -5
  67. package/packages/dd-trace/src/exporter.js +1 -0
  68. package/packages/dd-trace/src/exporters/agent/index.js +3 -2
  69. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  70. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +3 -2
  71. package/packages/dd-trace/src/exporters/common/request.js +2 -1
  72. package/packages/dd-trace/src/exporters/span-stats/index.js +3 -2
  73. package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
  74. package/packages/dd-trace/src/llmobs/plugins/ai/index.js +4 -3
  75. package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -1
  76. package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +40 -13
  77. package/packages/dd-trace/src/llmobs/plugins/openai.js +7 -1
  78. package/packages/dd-trace/src/llmobs/tagger.js +8 -0
  79. package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
  80. package/packages/dd-trace/src/log/index.js +28 -17
  81. package/packages/dd-trace/src/log/log.js +29 -5
  82. package/packages/dd-trace/src/log/writer.js +5 -5
  83. package/packages/dd-trace/src/noop/span.js +1 -0
  84. package/packages/dd-trace/src/opentelemetry/span.js +14 -3
  85. package/packages/dd-trace/src/opentracing/span.js +18 -4
  86. package/packages/dd-trace/src/plugin_manager.js +20 -2
  87. package/packages/dd-trace/src/plugins/ci_plugin.js +97 -3
  88. package/packages/dd-trace/src/plugins/index.js +2 -0
  89. package/packages/dd-trace/src/plugins/util/git-cache.js +129 -0
  90. package/packages/dd-trace/src/plugins/util/git.js +40 -26
  91. package/packages/dd-trace/src/plugins/util/test.js +37 -27
  92. package/packages/dd-trace/src/plugins/util/web.js +1 -1
  93. package/packages/dd-trace/src/profiler.js +4 -1
  94. package/packages/dd-trace/src/profiling/config.js +73 -42
  95. package/packages/dd-trace/src/profiling/profiler.js +3 -1
  96. package/packages/dd-trace/src/profiling/profilers/events.js +3 -8
  97. package/packages/dd-trace/src/profiling/profilers/space.js +1 -0
  98. package/packages/dd-trace/src/profiling/profilers/wall.js +196 -117
  99. package/packages/dd-trace/src/remote_config/capabilities.js +5 -0
  100. package/packages/dd-trace/src/remote_config/manager.js +3 -2
  101. package/packages/dd-trace/src/startup-log.js +2 -1
  102. package/packages/dd-trace/src/supported-configurations.json +3 -0
  103. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  104. package/register.js +1 -1
@@ -0,0 +1,186 @@
1
+ 'use strict'
2
+
3
+ const pkg = require('./pkg')
4
+ const { GRPC_CLIENT_ERROR_STATUSES, GRPC_SERVER_ERROR_STATUSES } = require('./constants')
5
+ const { getEnvironmentVariables } = require('./config-helper')
6
+
7
+ // eslint-disable-next-line @stylistic/max-len
8
+ const qsRegex = String.raw`(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\s|%20)*(?:=|%3D)[^&]+|(?:"|%22)(?:\s|%20)*(?::|%3A)(?:\s|%20)*(?:"|%22)(?:%2[^2]|%[^2]|[^"%])+(?:"|%22))|bearer(?:\s|%20)+[a-z0-9\._\-]+|token(?::|%3A)[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L](?:[\w=-]|%3D)+\.ey[I-L](?:[\w=-]|%3D)+(?:\.(?:[\w.+\/=-]|%3D|%2F|%2B)+)?|[\-]{5}BEGIN(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY[\-]{5}[^\-]+[\-]{5}END(?:[a-z\s]|%20)+PRIVATE(?:\s|%20)KEY|ssh-rsa(?:\s|%20)*(?:[a-z0-9\/\.+]|%2F|%5C|%2B){100,}`
9
+ // eslint-disable-next-line @stylistic/max-len
10
+ const defaultWafObfuscatorKeyRegex = String.raw`(?i)pass|pw(?:or)?d|secret|(?:api|private|public|access)[_-]?key|token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)|bearer|authorization|jsessionid|phpsessid|asp\.net[_-]sessionid|sid|jwt`
11
+ // eslint-disable-next-line @stylistic/max-len
12
+ const defaultWafObfuscatorValueRegex = String.raw`(?i)(?:p(?:ass)?w(?:or)?d|pass(?:[_-]?phrase)?|secret(?:[_-]?key)?|(?:(?:api|private|public|access)[_-]?)key(?:[_-]?id)?|(?:(?:auth|access|id|refresh)[_-]?)?token|consumer[_-]?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?|jsessionid|phpsessid|asp\.net(?:[_-]|-)sessionid|sid|jwt)(?:\s*=([^;&]+)|"\s*:\s*("[^"]+"|\d+))|bearer\s+([a-z0-9\._\-]+)|token\s*:\s*([a-z0-9]{13})|gh[opsu]_([0-9a-zA-Z]{36})|ey[I-L][\w=-]+\.(ey[I-L][\w=-]+(?:\.[\w.+\/=-]+)?)|[\-]{5}BEGIN[a-z\s]+PRIVATE\sKEY[\-]{5}([^\-]+)[\-]{5}END[a-z\s]+PRIVATE\sKEY|ssh-rsa\s*([a-z0-9\/\.+]{100,})`
13
+
14
+ const {
15
+ AWS_LAMBDA_FUNCTION_NAME,
16
+ FUNCTION_NAME,
17
+ K_SERVICE,
18
+ WEBSITE_SITE_NAME
19
+ } = getEnvironmentVariables()
20
+
21
+ const service = AWS_LAMBDA_FUNCTION_NAME ||
22
+ FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
23
+ K_SERVICE || // Google Cloud Function Name set by newer runtimes
24
+ WEBSITE_SITE_NAME || // set by Azure Functions
25
+ pkg.name ||
26
+ 'node'
27
+
28
+ module.exports = {
29
+ apmTracingEnabled: true,
30
+ 'appsec.apiSecurity.enabled': true,
31
+ 'appsec.apiSecurity.sampleDelay': 30,
32
+ 'appsec.apiSecurity.endpointCollectionEnabled': true,
33
+ 'appsec.apiSecurity.endpointCollectionMessageLimit': 300,
34
+ 'appsec.blockedTemplateGraphql': undefined,
35
+ 'appsec.blockedTemplateHtml': undefined,
36
+ 'appsec.blockedTemplateJson': undefined,
37
+ 'appsec.enabled': undefined,
38
+ 'appsec.eventTracking.mode': 'identification',
39
+ 'appsec.extendedHeadersCollection.enabled': false,
40
+ 'appsec.extendedHeadersCollection.redaction': true,
41
+ 'appsec.extendedHeadersCollection.maxHeaders': 50,
42
+ 'appsec.obfuscatorKeyRegex': defaultWafObfuscatorKeyRegex,
43
+ 'appsec.obfuscatorValueRegex': defaultWafObfuscatorValueRegex,
44
+ 'appsec.rasp.enabled': true,
45
+ 'appsec.rasp.bodyCollection': false,
46
+ 'appsec.rateLimit': 100,
47
+ 'appsec.rules': undefined,
48
+ 'appsec.sca.enabled': null,
49
+ 'appsec.stackTrace.enabled': true,
50
+ 'appsec.stackTrace.maxDepth': 32,
51
+ 'appsec.stackTrace.maxStackTraces': 2,
52
+ 'appsec.wafTimeout': 5e3, // µs
53
+ baggageMaxBytes: 8192,
54
+ baggageMaxItems: 64,
55
+ baggageTagKeys: 'user.id,session.id,account.id',
56
+ clientIpEnabled: false,
57
+ clientIpHeader: null,
58
+ 'crashtracking.enabled': true,
59
+ 'codeOriginForSpans.enabled': true,
60
+ 'codeOriginForSpans.experimental.exit_spans.enabled': false,
61
+ dbmPropagationMode: 'disabled',
62
+ 'dogstatsd.hostname': '127.0.0.1',
63
+ 'dogstatsd.port': '8125',
64
+ dsmEnabled: false,
65
+ 'dynamicInstrumentation.enabled': false,
66
+ 'dynamicInstrumentation.probeFile': undefined,
67
+ 'dynamicInstrumentation.redactedIdentifiers': [],
68
+ 'dynamicInstrumentation.redactionExcludedIdentifiers': [],
69
+ 'dynamicInstrumentation.uploadIntervalSeconds': 1,
70
+ env: undefined,
71
+ 'experimental.enableGetRumData': false,
72
+ 'experimental.exporter': undefined,
73
+ flushInterval: 2000,
74
+ flushMinSpans: 1000,
75
+ gitMetadataEnabled: true,
76
+ graphqlErrorExtensions: [],
77
+ 'grpc.client.error.statuses': GRPC_CLIENT_ERROR_STATUSES,
78
+ 'grpc.server.error.statuses': GRPC_SERVER_ERROR_STATUSES,
79
+ headerTags: [],
80
+ 'heapSnapshot.count': 0,
81
+ 'heapSnapshot.destination': '',
82
+ 'heapSnapshot.interval': 3600,
83
+ hostname: '127.0.0.1',
84
+ 'iast.dbRowsToTaint': 1,
85
+ 'iast.deduplicationEnabled': true,
86
+ 'iast.enabled': false,
87
+ 'iast.maxConcurrentRequests': 2,
88
+ 'iast.maxContextOperations': 2,
89
+ 'iast.redactionEnabled': true,
90
+ 'iast.redactionNamePattern': null,
91
+ 'iast.redactionValuePattern': null,
92
+ 'iast.requestSampling': 30,
93
+ 'iast.securityControlsConfiguration': null,
94
+ 'iast.telemetryVerbosity': 'INFORMATION',
95
+ 'iast.stackTrace.enabled': true,
96
+ injectionEnabled: [],
97
+ instrumentationSource: 'manual',
98
+ injectForce: null,
99
+ isAzureFunction: false,
100
+ isCiVisibility: false,
101
+ isEarlyFlakeDetectionEnabled: false,
102
+ isFlakyTestRetriesEnabled: false,
103
+ flakyTestRetriesCount: 5,
104
+ isGCPFunction: false,
105
+ isGitUploadEnabled: false,
106
+ isIntelligentTestRunnerEnabled: false,
107
+ isManualApiEnabled: false,
108
+ 'langchain.spanCharLimit': 128,
109
+ 'langchain.spanPromptCompletionSampleRate': 1,
110
+ 'llmobs.agentlessEnabled': undefined,
111
+ 'llmobs.enabled': false,
112
+ 'llmobs.mlApp': undefined,
113
+ ciVisibilityTestSessionName: '',
114
+ ciVisAgentlessLogSubmissionEnabled: false,
115
+ legacyBaggageEnabled: true,
116
+ isTestDynamicInstrumentationEnabled: false,
117
+ isServiceUserProvided: false,
118
+ testManagementAttemptToFixRetries: 20,
119
+ isTestManagementEnabled: false,
120
+ isImpactedTestsEnabled: false,
121
+ logInjection: true,
122
+ lookup: undefined,
123
+ inferredProxyServicesEnabled: false,
124
+ memcachedCommandEnabled: false,
125
+ middlewareTracingEnabled: true,
126
+ openAiLogsEnabled: false,
127
+ 'openai.spanCharLimit': 128,
128
+ peerServiceMapping: {},
129
+ plugins: true,
130
+ port: '8126',
131
+ 'profiling.enabled': undefined,
132
+ 'profiling.exporters': 'agent',
133
+ 'profiling.sourceMap': true,
134
+ 'profiling.longLivedThreshold': undefined,
135
+ protocolVersion: '0.4',
136
+ queryStringObfuscation: qsRegex,
137
+ 'remoteConfig.enabled': true,
138
+ 'remoteConfig.pollInterval': 5, // seconds
139
+ reportHostname: false,
140
+ 'runtimeMetrics.enabled': false,
141
+ 'runtimeMetrics.eventLoop': true,
142
+ 'runtimeMetrics.gc': true,
143
+ runtimeMetricsRuntimeId: false,
144
+ sampleRate: undefined,
145
+ 'sampler.rateLimit': 100,
146
+ 'sampler.rules': [],
147
+ 'sampler.spanSamplingRules': [],
148
+ scope: undefined,
149
+ service,
150
+ serviceMapping: {},
151
+ site: 'datadoghq.com',
152
+ spanAttributeSchema: 'v0',
153
+ spanComputePeerService: false,
154
+ spanLeakDebug: 0,
155
+ spanRemoveIntegrationFromService: false,
156
+ startupLogs: false,
157
+ 'stats.enabled': false,
158
+ tags: {},
159
+ tagsHeaderMaxLength: 512,
160
+ 'telemetry.debug': false,
161
+ 'telemetry.dependencyCollection': true,
162
+ 'telemetry.enabled': true,
163
+ 'telemetry.heartbeatInterval': 60_000,
164
+ 'telemetry.logCollection': true,
165
+ 'telemetry.metrics': true,
166
+ traceEnabled: true,
167
+ traceId128BitGenerationEnabled: true,
168
+ traceId128BitLoggingEnabled: true,
169
+ tracePropagationExtractFirst: false,
170
+ tracePropagationBehaviorExtract: 'continue',
171
+ 'tracePropagationStyle.inject': ['datadog', 'tracecontext', 'baggage'],
172
+ 'tracePropagationStyle.extract': ['datadog', 'tracecontext', 'baggage'],
173
+ 'tracePropagationStyle.otelPropagators': false,
174
+ traceWebsocketMessagesEnabled: false,
175
+ traceWebsocketMessagesInheritSampling: true,
176
+ traceWebsocketMessagesSeparateTraces: true,
177
+ tracing: true,
178
+ url: undefined,
179
+ version: pkg.version,
180
+ instrumentation_config_id: undefined,
181
+ 'vertexai.spanCharLimit': 128,
182
+ 'vertexai.spanPromptCompletionSampleRate': 1,
183
+ 'trace.aws.addSpanPointers': true,
184
+ 'trace.dynamoDb.tablePrimaryKeys': undefined,
185
+ 'trace.nativeSpanEvents': false
186
+ }
@@ -5,6 +5,7 @@ const libdatadog = require('@datadog/libdatadog')
5
5
  const binding = libdatadog.load('crashtracker')
6
6
 
7
7
  const log = require('../log')
8
+ const defaults = require('../config_defaults')
8
9
  const { URL } = require('url')
9
10
  const pkg = require('../../../../package.json')
10
11
 
@@ -49,7 +50,7 @@ class Crashtracker {
49
50
 
50
51
  // TODO: Send only configured values when defaults are fixed.
51
52
  #getConfig (config) {
52
- const { hostname = '127.0.0.1', port = 8126 } = config
53
+ const { hostname = defaults.hostname, port = defaults.port } = config
53
54
  const url = config.url || new URL(`http://${hostname}:${port}`)
54
55
 
55
56
  return {
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const FNV_64_PRIME = BigInt('0x100000001B3')
4
- const FNV1_64_INIT = BigInt('0xCBF29CE484222325')
3
+ const FNV_64_PRIME = 0x1_00_00_00_01_B3n
4
+ const FNV1_64_INIT = 0xCB_F2_9C_E4_84_22_23_25n
5
5
 
6
6
  function fnv (data, hvalInit, fnvPrime, fnvSize) {
7
7
  let hval = hvalInit
@@ -5,6 +5,7 @@ const log = require('../log')
5
5
  const request = require('../exporters/common/request')
6
6
  const { URL, format } = require('url')
7
7
  const { MsgpackEncoder } = require('../msgpack')
8
+ const defaults = require('../config_defaults')
8
9
  const zlib = require('zlib')
9
10
 
10
11
  const msgpack = new MsgpackEncoder()
@@ -31,10 +32,10 @@ function makeRequest (data, url, cb) {
31
32
 
32
33
  class DataStreamsWriter {
33
34
  constructor (config) {
34
- const { hostname = '127.0.0.1', port = 8126, url } = config
35
+ const { hostname = defaults.hostname, port = defaults.port, url } = config
35
36
  this._url = url || new URL(format({
36
37
  protocol: 'http:',
37
- hostname: hostname || 'localhost',
38
+ hostname,
38
39
  port
39
40
  }))
40
41
  }
@@ -3,6 +3,7 @@
3
3
  const { workerData: { config: parentConfig, parentThreadId, configPort } } = require('node:worker_threads')
4
4
  const { format } = require('node:url')
5
5
  const log = require('./log')
6
+ const defaults = require('../../config_defaults')
6
7
 
7
8
  const config = module.exports = {
8
9
  ...parentConfig,
@@ -20,7 +21,7 @@ configPort.on('messageerror', (err) =>
20
21
  function updateUrl (updates) {
21
22
  config.url = updates.url || format({
22
23
  protocol: 'http:',
23
- hostname: updates.hostname || 'localhost',
24
+ hostname: updates.hostname || defaults.hostname,
24
25
  port: updates.port
25
26
  })
26
27
  }
@@ -7,6 +7,7 @@ const isIP = require('net').isIP
7
7
  const log = require('./log')
8
8
  const { URL, format } = require('url')
9
9
  const Histogram = require('./histogram')
10
+ const defaults = require('./config_defaults')
10
11
 
11
12
  const MAX_BUFFER_SIZE = 1024 // limit from the agent
12
13
 
@@ -28,9 +29,9 @@ class DogStatsDClient {
28
29
  }
29
30
  }
30
31
 
31
- this._host = options.host || 'localhost'
32
+ this._host = options.host || defaults['dogstatsd.hostname']
32
33
  this._family = isIP(this._host)
33
- this._port = options.port || 8125
34
+ this._port = options.port || defaults['dogstatsd.port']
34
35
  this._prefix = options.prefix || ''
35
36
  this._tags = options.tags || []
36
37
  this._queue = []
@@ -182,7 +183,7 @@ class DogStatsDClient {
182
183
  } else if (config.port) {
183
184
  clientConfig.metricsProxyUrl = new URL(format({
184
185
  protocol: 'http:',
185
- hostname: config.hostname || 'localhost',
186
+ hostname: config.hostname || defaults.hostname,
186
187
  port: config.port
187
188
  }))
188
189
  }
@@ -4,7 +4,6 @@ const { truncateSpan, normalizeSpan } = require('./tags-processors')
4
4
  const { Chunk, MsgpackEncoder } = require('../msgpack')
5
5
  const log = require('../log')
6
6
  const { isTrue } = require('../util')
7
- const coalesce = require('koalas')
8
7
  const { memoize } = require('../log/utils')
9
8
  const { getEnvironmentVariable } = require('../config-helper')
10
9
 
@@ -32,10 +31,7 @@ class AgentEncoder {
32
31
  this._stringBytes = new Chunk()
33
32
  this._writer = writer
34
33
  this._reset()
35
- this._debugEncoding = isTrue(coalesce(
36
- getEnvironmentVariable('DD_TRACE_ENCODING_DEBUG'),
37
- false
38
- ))
34
+ this._debugEncoding = isTrue(getEnvironmentVariable('DD_TRACE_ENCODING_DEBUG'))
39
35
  this._config = this._writer?._config
40
36
  }
41
37
 
@@ -19,6 +19,7 @@ module.exports = function getExporter (name) {
19
19
  case exporters.CUCUMBER_WORKER:
20
20
  case exporters.MOCHA_WORKER:
21
21
  case exporters.PLAYWRIGHT_WORKER:
22
+ case exporters.VITEST_WORKER:
22
23
  return require('./ci-visibility/exporters/test-worker')
23
24
  default: {
24
25
  const inAWSLambda = getEnvironmentVariable('AWS_LAMBDA_FUNCTION_NAME') !== undefined
@@ -3,16 +3,17 @@
3
3
  const { URL, format } = require('url')
4
4
  const log = require('../../log')
5
5
  const Writer = require('./writer')
6
+ const defaults = require('../../config_defaults')
6
7
 
7
8
  class AgentExporter {
8
9
  #timer
9
10
 
10
11
  constructor (config, prioritySampler) {
11
12
  this._config = config
12
- const { url, hostname, port, lookup, protocolVersion, stats = {}, apmTracingEnabled } = config
13
+ const { url, hostname = defaults.hostname, port, lookup, protocolVersion, stats = {}, apmTracingEnabled } = config
13
14
  this._url = url || new URL(format({
14
15
  protocol: 'http:',
15
- hostname: hostname || 'localhost',
16
+ hostname,
16
17
  port
17
18
  }))
18
19
 
@@ -42,7 +42,7 @@ class Writer extends BaseWriter {
42
42
  startupLog({ agentError: err })
43
43
 
44
44
  if (err) {
45
- log.error('Error sending payload to the agent (status code: %s)', err.status, err)
45
+ log.errorWithoutTelemetry('Error sending payload to the agent (status code: %s)', err.status, err)
46
46
  done()
47
47
  return
48
48
  }
@@ -3,6 +3,7 @@
3
3
  const { URL, format } = require('url')
4
4
 
5
5
  const request = require('./request')
6
+ const defaults = require('../../config_defaults')
6
7
  const { incrementCountMetric, TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION } = require('../../ci-visibility/telemetry')
7
8
 
8
9
  function fetchAgentInfo (url, callback) {
@@ -29,10 +30,10 @@ function fetchAgentInfo (url, callback) {
29
30
  class AgentInfoExporter {
30
31
  constructor (tracerConfig) {
31
32
  this._config = tracerConfig
32
- const { url, hostname, port } = this._config
33
+ const { url, hostname = defaults.hostname, port } = this._config
33
34
  this._url = url || new URL(format({
34
35
  protocol: 'http:',
35
- hostname: hostname || 'localhost',
36
+ hostname,
36
37
  port
37
38
  }))
38
39
  this._traceBuffer = []
@@ -106,11 +106,12 @@ function request (data, options, callback) {
106
106
  } catch {
107
107
  // ignore error
108
108
  }
109
+
109
110
  const responseData = buffer.toString()
110
111
  if (responseData) {
111
112
  errorMessage += ` Response from the endpoint: "${responseData}"`
112
113
  }
113
- const error = new Error(errorMessage)
114
+ const error = new log.NoTransmitError(errorMessage)
114
115
  error.status = res.statusCode
115
116
 
116
117
  callback(error, null, res.statusCode)
@@ -3,13 +3,14 @@
3
3
  const { URL, format } = require('url')
4
4
 
5
5
  const { Writer } = require('./writer')
6
+ const defaults = require('../../config_defaults')
6
7
 
7
8
  class SpanStatsExporter {
8
9
  constructor (config) {
9
- const { hostname = '127.0.0.1', port = 8126, tags, url } = config
10
+ const { hostname = defaults.hostname, port = defaults.port, tags, url } = config
10
11
  this._url = url || new URL(format({
11
12
  protocol: 'http:',
12
- hostname: hostname || 'localhost',
13
+ hostname,
13
14
  port
14
15
  }))
15
16
  this._writer = new Writer({ url: this._url, tags })
@@ -32,6 +32,8 @@ module.exports = {
32
32
  INPUT_TOKENS_METRIC_KEY: 'input_tokens',
33
33
  OUTPUT_TOKENS_METRIC_KEY: 'output_tokens',
34
34
  TOTAL_TOKENS_METRIC_KEY: 'total_tokens',
35
+ CACHE_READ_INPUT_TOKENS_METRIC_KEY: 'cache_read_input_tokens',
36
+ CACHE_WRITE_INPUT_TOKENS_METRIC_KEY: 'cache_write_input_tokens',
35
37
 
36
38
  DROPPED_IO_COLLECTION_ERROR: 'dropped_io'
37
39
  }
@@ -17,7 +17,8 @@ const {
17
17
  getModelMetadata,
18
18
  getGenerationMetadata,
19
19
  getToolNameFromTags,
20
- getToolCallResultContent
20
+ getToolCallResultContent,
21
+ getLlmObsSpanName
21
22
  } = require('./util')
22
23
 
23
24
  const SPAN_NAME_TO_KIND_MAPPING = {
@@ -84,7 +85,7 @@ class VercelAILLMObsPlugin extends BaseLLMObsPlugin {
84
85
  findToolName (toolDescription) {
85
86
  for (const availableTool of this.#availableTools) {
86
87
  const description = availableTool.description
87
- if (description === toolDescription) {
88
+ if (description === toolDescription && availableTool.id) {
88
89
  return availableTool.id
89
90
  }
90
91
  }
@@ -96,7 +97,7 @@ class VercelAILLMObsPlugin extends BaseLLMObsPlugin {
96
97
  const kind = SPAN_NAME_TO_KIND_MAPPING[operation]
97
98
  if (!kind) return
98
99
 
99
- return { kind, name: operation }
100
+ return { kind, name: getLlmObsSpanName(operation, ctx.attributes['ai.telemetry.functionId']) }
100
101
  }
101
102
 
102
103
  setLLMObsTags (ctx) {
@@ -167,6 +167,16 @@ function getToolCallResultContent (content) {
167
167
  }
168
168
  }
169
169
 
170
+ /**
171
+ * Computes the LLM Observability `ai` span name
172
+ * @param {string} operation
173
+ * @param {string} functionId
174
+ * @returns {string}
175
+ */
176
+ function getLlmObsSpanName (operation, functionId) {
177
+ return functionId ? `${functionId}.${operation}` : operation
178
+ }
179
+
170
180
  module.exports = {
171
181
  getSpanTags,
172
182
  getOperation,
@@ -175,5 +185,6 @@ module.exports = {
175
185
  getModelMetadata,
176
186
  getGenerationMetadata,
177
187
  getToolNameFromTags,
178
- getToolCallResultContent
188
+ getToolCallResultContent,
189
+ getLlmObsSpanName
179
190
  }
@@ -8,10 +8,11 @@ const telemetry = require('../telemetry')
8
8
  const {
9
9
  extractRequestParams,
10
10
  extractTextAndResponseReason,
11
- parseModelId
11
+ parseModelId,
12
+ extractTextAndResponseReasonFromStream
12
13
  } = require('../../../../datadog-plugin-aws-sdk/src/services/bedrockruntime/utils')
13
14
 
14
- const ENABLED_OPERATIONS = new Set(['invokeModel'])
15
+ const ENABLED_OPERATIONS = new Set(['invokeModel', 'invokeModelWithResponseStream'])
15
16
 
16
17
  const requestIdsToTokens = {}
17
18
 
@@ -19,7 +20,8 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
19
20
  constructor () {
20
21
  super(...arguments)
21
22
 
22
- this.addSub('apm:aws:request:complete:bedrockruntime', ({ response }) => {
23
+ this.addSub('apm:aws:request:complete:bedrockruntime', (ctx) => {
24
+ const { response } = ctx
23
25
  const request = response.request
24
26
  const operation = request.operation
25
27
  // avoids instrumenting other non supported runtime operations
@@ -32,23 +34,34 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
32
34
  if (modelName.includes('embed')) {
33
35
  return
34
36
  }
35
- const span = storage('legacy').getStore()?.span
36
- this.setLLMObsTags({ request, span, response, modelProvider, modelName })
37
+ const span = ctx.currentStore?.span
38
+ this.setLLMObsTags({ ctx, request, span, response, modelProvider, modelName })
37
39
  })
38
40
 
39
41
  this.addSub('apm:aws:response:deserialize:bedrockruntime', ({ headers }) => {
40
42
  const requestId = headers['x-amzn-requestid']
41
43
  const inputTokenCount = headers['x-amzn-bedrock-input-token-count']
42
44
  const outputTokenCount = headers['x-amzn-bedrock-output-token-count']
45
+ const cacheReadTokenCount = headers['x-amzn-bedrock-cache-read-input-token-count']
46
+ const cacheWriteTokenCount = headers['x-amzn-bedrock-cache-write-input-token-count']
43
47
 
44
48
  requestIdsToTokens[requestId] = {
45
49
  inputTokensFromHeaders: inputTokenCount && Number.parseInt(inputTokenCount),
46
- outputTokensFromHeaders: outputTokenCount && Number.parseInt(outputTokenCount)
50
+ outputTokensFromHeaders: outputTokenCount && Number.parseInt(outputTokenCount),
51
+ cacheReadTokensFromHeaders: cacheReadTokenCount && Number.parseInt(cacheReadTokenCount),
52
+ cacheWriteTokensFromHeaders: cacheWriteTokenCount && Number.parseInt(cacheWriteTokenCount)
47
53
  }
48
54
  })
55
+
56
+ this.addSub('apm:aws:response:streamed-chunk:bedrockruntime', ({ ctx, chunk }) => {
57
+ if (!ctx.chunks) ctx.chunks = []
58
+
59
+ if (chunk) ctx.chunks.push(chunk)
60
+ })
49
61
  }
50
62
 
51
- setLLMObsTags ({ request, span, response, modelProvider, modelName }) {
63
+ setLLMObsTags ({ ctx, request, span, response, modelProvider, modelName }) {
64
+ const isStream = request?.operation?.toLowerCase().includes('stream')
52
65
  telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: 'bedrock' })
53
66
 
54
67
  const parent = llmobsStore.getStore()?.span
@@ -62,7 +75,10 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
62
75
  })
63
76
 
64
77
  const requestParams = extractRequestParams(request.params, modelProvider)
65
- const textAndResponseReason = extractTextAndResponseReason(response, modelProvider, modelName)
78
+ // for streamed responses, we'll use the coerced response object we formed in the stream handler
79
+ const textAndResponseReason = isStream
80
+ ? extractTextAndResponseReasonFromStream(ctx.chunks, modelProvider, modelName)
81
+ : extractTextAndResponseReason(response, modelProvider, modelName)
66
82
 
67
83
  // add metadata tags
68
84
  this._tagger.tagMetadata(span, {
@@ -78,14 +94,16 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
78
94
  )
79
95
 
80
96
  // add token metrics
81
- const { inputTokens, outputTokens, totalTokens } = extractTokens({
97
+ const { inputTokens, outputTokens, totalTokens, cacheReadTokens, cacheWriteTokens } = extractTokens({
82
98
  requestId: response.$metadata.requestId,
83
99
  usage: textAndResponseReason.usage
84
100
  })
85
101
  this._tagger.tagMetrics(span, {
86
102
  inputTokens,
87
103
  outputTokens,
88
- totalTokens
104
+ totalTokens,
105
+ cacheReadTokens,
106
+ cacheWriteTokens
89
107
  })
90
108
  }
91
109
  }
@@ -93,17 +111,26 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
93
111
  function extractTokens ({ requestId, usage }) {
94
112
  const {
95
113
  inputTokensFromHeaders,
96
- outputTokensFromHeaders
114
+ outputTokensFromHeaders,
115
+ cacheReadTokensFromHeaders,
116
+ cacheWriteTokensFromHeaders
97
117
  } = requestIdsToTokens[requestId] || {}
98
118
  delete requestIdsToTokens[requestId]
99
119
 
100
120
  const inputTokens = usage.inputTokens || inputTokensFromHeaders || 0
101
121
  const outputTokens = usage.outputTokens || outputTokensFromHeaders || 0
122
+ const cacheReadTokens = usage.cacheReadTokens || cacheReadTokensFromHeaders || 0
123
+ const cacheWriteTokens = usage.cacheWriteTokens || cacheWriteTokensFromHeaders || 0
124
+
125
+ // adjust for the fact that bedrock input tokens only count non-cached tokens
126
+ const normalizedInputTokens = inputTokens + cacheReadTokens + cacheWriteTokens
102
127
 
103
128
  return {
104
- inputTokens,
129
+ inputTokens: normalizedInputTokens,
105
130
  outputTokens,
106
- totalTokens: inputTokens + outputTokens
131
+ totalTokens: normalizedInputTokens + outputTokens,
132
+ cacheReadTokens,
133
+ cacheWriteTokens
107
134
  }
108
135
  }
109
136
 
@@ -81,8 +81,14 @@ class OpenAiLLMObsPlugin extends LLMObsPlugin {
81
81
  const outputTokens = tokenUsage.completion_tokens
82
82
  if (outputTokens) metrics.outputTokens = outputTokens
83
83
 
84
- const totalTokens = tokenUsage.total_toksn || (inputTokens + outputTokens)
84
+ const totalTokens = tokenUsage.total_tokens || (inputTokens + outputTokens)
85
85
  if (totalTokens) metrics.totalTokens = totalTokens
86
+
87
+ const promptTokensDetails = tokenUsage.prompt_tokens_details
88
+ if (promptTokensDetails) {
89
+ const cacheReadTokens = promptTokensDetails.cached_tokens
90
+ if (cacheReadTokens) metrics.cacheReadTokens = cacheReadTokens
91
+ }
86
92
  }
87
93
 
88
94
  return metrics
@@ -20,6 +20,8 @@ const {
20
20
  NAME,
21
21
  PROPAGATED_PARENT_ID_KEY,
22
22
  ROOT_PARENT_ID,
23
+ CACHE_READ_INPUT_TOKENS_METRIC_KEY,
24
+ CACHE_WRITE_INPUT_TOKENS_METRIC_KEY,
23
25
  INPUT_TOKENS_METRIC_KEY,
24
26
  OUTPUT_TOKENS_METRIC_KEY,
25
27
  TOTAL_TOKENS_METRIC_KEY,
@@ -144,6 +146,12 @@ class LLMObsTagger {
144
146
  case 'totalTokens':
145
147
  processedKey = TOTAL_TOKENS_METRIC_KEY
146
148
  break
149
+ case 'cacheReadTokens':
150
+ processedKey = CACHE_READ_INPUT_TOKENS_METRIC_KEY
151
+ break
152
+ case 'cacheWriteTokens':
153
+ processedKey = CACHE_WRITE_INPUT_TOKENS_METRIC_KEY
154
+ break
147
155
  }
148
156
 
149
157
  if (typeof value === 'number') {
@@ -85,7 +85,8 @@ function recordLLMObsEnabled (startTime, config, value = 1) {
85
85
  error: 0,
86
86
  agentless: Number(config.llmobs.agentlessEnabled),
87
87
  site: config.site,
88
- auto: Number(autoEnabled)
88
+ auto: Number(autoEnabled),
89
+ ml_app: config.llmobs.mlApp
89
90
  }
90
91
  llmobsMetrics.count('product_enabled', tags).inc(value)
91
92
  llmobsMetrics.distribution('init_time', tags).track(initTimeMs)