dd-trace 5.96.0 → 5.98.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/index.d.ts +60 -2
- package/package.json +9 -7
- package/packages/datadog-esbuild/index.js +20 -9
- package/packages/datadog-instrumentations/src/child_process.js +7 -17
- package/packages/datadog-instrumentations/src/crypto.js +1 -2
- package/packages/datadog-instrumentations/src/cucumber.js +69 -4
- package/packages/datadog-instrumentations/src/cypress-config.js +318 -0
- package/packages/datadog-instrumentations/src/cypress.js +86 -4
- package/packages/datadog-instrumentations/src/dns.js +1 -2
- package/packages/datadog-instrumentations/src/express.js +4 -4
- package/packages/datadog-instrumentations/src/fs.js +27 -29
- package/packages/datadog-instrumentations/src/graphql.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/bundler-register.js +41 -13
- package/packages/datadog-instrumentations/src/helpers/hook.js +31 -6
- package/packages/datadog-instrumentations/src/helpers/hooks.js +12 -19
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -13
- package/packages/datadog-instrumentations/src/helpers/register.js +103 -142
- package/packages/datadog-instrumentations/src/http/client.js +2 -3
- package/packages/datadog-instrumentations/src/http/server.js +2 -5
- package/packages/datadog-instrumentations/src/http2/client.js +1 -3
- package/packages/datadog-instrumentations/src/http2/server.js +1 -3
- package/packages/datadog-instrumentations/src/jest.js +117 -16
- package/packages/datadog-instrumentations/src/limitd-client.js +1 -1
- package/packages/datadog-instrumentations/src/mocha/utils.js +12 -1
- package/packages/datadog-instrumentations/src/net.js +2 -8
- package/packages/datadog-instrumentations/src/pino.js +1 -1
- package/packages/datadog-instrumentations/src/playwright.js +4 -1
- package/packages/datadog-instrumentations/src/prisma.js +1 -2
- package/packages/datadog-instrumentations/src/redis.js +12 -6
- package/packages/datadog-instrumentations/src/selenium.js +4 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/url.js +1 -3
- package/packages/datadog-instrumentations/src/vitest.js +5 -1
- package/packages/datadog-instrumentations/src/vm.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +5 -4
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
- package/packages/datadog-plugin-cucumber/src/index.js +13 -3
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +166 -6
- package/packages/datadog-plugin-cypress/src/index.js +59 -2
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -7
- package/packages/datadog-plugin-graphql/src/resolve.js +1 -1
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +10 -2
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +10 -2
- package/packages/datadog-plugin-jest/src/index.js +4 -2
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +31 -4
- package/packages/datadog-plugin-mocha/src/index.js +5 -2
- package/packages/datadog-plugin-mongodb-core/src/index.js +3 -3
- package/packages/datadog-plugin-mysql/src/index.js +1 -1
- package/packages/datadog-plugin-next/src/index.js +10 -16
- package/packages/datadog-plugin-openai/src/services.js +1 -0
- package/packages/datadog-plugin-pg/src/index.js +1 -1
- package/packages/datadog-plugin-tedious/src/index.js +1 -1
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-plugin-ws/src/receiver.js +1 -1
- package/packages/datadog-webpack/index.js +3 -3
- package/packages/dd-trace/index.js +12 -10
- package/packages/dd-trace/src/agent/url.js +2 -2
- package/packages/dd-trace/src/aiguard/sdk.js +26 -22
- package/packages/dd-trace/src/appsec/blocked_templates.js +4 -3
- package/packages/dd-trace/src/appsec/blocking.js +64 -33
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +1 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/utils.js +1 -1
- package/packages/dd-trace/src/appsec/remote_config.js +1 -0
- package/packages/dd-trace/src/appsec/sdk/index.js +4 -0
- package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
- package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -5
- package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
- package/packages/dd-trace/src/appsec/sdk/utils.js +4 -2
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +6 -1
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +4 -0
- package/packages/dd-trace/src/config/defaults.js +315 -146
- package/packages/dd-trace/src/config/generated-config-types.d.ts +9 -1
- package/packages/dd-trace/src/config/helper.js +59 -10
- package/packages/dd-trace/src/config/index.js +587 -1496
- package/packages/dd-trace/src/config/parsers.js +256 -0
- package/packages/dd-trace/src/config/remote_config.js +59 -2
- package/packages/dd-trace/src/config/supported-configurations.json +406 -432
- package/packages/dd-trace/src/constants.js +1 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +7 -1
- package/packages/dd-trace/src/crashtracking/index.js +1 -7
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +5 -2
- package/packages/dd-trace/src/debugger/index.js +1 -1
- package/packages/dd-trace/src/dogstatsd.js +12 -9
- package/packages/dd-trace/src/encode/0.4.js +8 -7
- package/packages/dd-trace/src/encode/span-stats.js +4 -1
- package/packages/dd-trace/src/exporters/agent/writer.js +7 -1
- package/packages/dd-trace/src/exporters/common/request.js +9 -0
- package/packages/dd-trace/src/exporters/common/writer.js +12 -2
- package/packages/dd-trace/src/heap_snapshots.js +3 -0
- package/packages/dd-trace/src/index.js +5 -2
- package/packages/dd-trace/src/lambda/runtime/ritm.js +6 -6
- package/packages/dd-trace/src/llmobs/index.js +4 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +5 -1
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +60 -12
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +4 -2
- package/packages/dd-trace/src/llmobs/sdk.js +12 -8
- package/packages/dd-trace/src/llmobs/span_processor.js +1 -1
- package/packages/dd-trace/src/llmobs/tagger.js +9 -6
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -0
- package/packages/dd-trace/src/llmobs/writers/util.js +3 -0
- package/packages/dd-trace/src/log/index.js +20 -59
- package/packages/dd-trace/src/log/writer.js +7 -19
- package/packages/dd-trace/src/noop/proxy.js +8 -0
- package/packages/dd-trace/src/openfeature/remote_config.js +6 -1
- package/packages/dd-trace/src/opentelemetry/context_manager.js +6 -4
- package/packages/dd-trace/src/opentelemetry/logs/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +17 -2
- package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +14 -2
- package/packages/dd-trace/src/opentelemetry/otlp/trace.proto +358 -0
- package/packages/dd-trace/src/opentelemetry/otlp/trace_service.proto +78 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +75 -0
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +66 -0
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +332 -0
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +9 -4
- package/packages/dd-trace/src/opentracing/tracer.js +9 -4
- package/packages/dd-trace/src/payload-tagging/config/index.js +6 -5
- package/packages/dd-trace/src/plugin_manager.js +8 -6
- package/packages/dd-trace/src/plugins/ci_plugin.js +4 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +3 -0
- package/packages/dd-trace/src/plugins/plugin.js +11 -13
- package/packages/dd-trace/src/plugins/storage.js +2 -2
- package/packages/dd-trace/src/plugins/tracing.js +22 -5
- package/packages/dd-trace/src/plugins/util/test.js +2 -0
- package/packages/dd-trace/src/plugins/util/web.js +6 -88
- package/packages/dd-trace/src/process-tags/index.js +3 -0
- package/packages/dd-trace/src/profiler.js +27 -2
- package/packages/dd-trace/src/profiling/config.js +73 -241
- package/packages/dd-trace/src/profiling/exporter_cli.js +1 -4
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +6 -2
- package/packages/dd-trace/src/profiling/profiler.js +78 -109
- package/packages/dd-trace/src/profiling/profilers/events.js +2 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +89 -6
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +4 -1
- package/packages/dd-trace/src/propagation-hash/index.js +2 -1
- package/packages/dd-trace/src/proxy.js +40 -6
- package/packages/dd-trace/src/remote_config/index.js +3 -0
- package/packages/dd-trace/src/require-package-json.js +8 -4
- package/packages/dd-trace/src/ritm.js +58 -26
- package/packages/dd-trace/src/runtime_metrics/index.js +3 -0
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +18 -11
- package/packages/dd-trace/src/sampler.js +1 -1
- package/packages/dd-trace/src/service-naming/index.js +1 -1
- package/packages/dd-trace/src/service-naming/schemas/definition.js +4 -1
- package/packages/dd-trace/src/service-naming/schemas/util.js +15 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +24 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +60 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/web.js +17 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/websocket.js +5 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +17 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +11 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/websocket.js +6 -0
- package/packages/dd-trace/src/span_stats.js +5 -1
- package/packages/dd-trace/src/standalone/index.js +3 -0
- package/packages/dd-trace/src/telemetry/index.js +2 -3
- package/packages/dd-trace/src/telemetry/send-data.js +5 -19
- package/packages/dd-trace/src/telemetry/session-propagation.js +19 -44
- package/packages/dd-trace/src/telemetry/telemetry.js +28 -171
- package/packages/dd-trace/src/tracer.js +2 -2
- package/packages/dd-trace/src/util.js +0 -9
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +28 -6
- package/vendor/dist/protobufjs/index.js +1 -1
- package/packages/dd-trace/src/log/utils.js +0 -16
|
@@ -21,6 +21,7 @@ module.exports = {
|
|
|
21
21
|
SPAN_SAMPLING_MECHANISM: '_dd.span_sampling.mechanism',
|
|
22
22
|
SPAN_SAMPLING_RULE_RATE: '_dd.span_sampling.rule_rate',
|
|
23
23
|
SPAN_SAMPLING_MAX_PER_SECOND: '_dd.span_sampling.max_per_second',
|
|
24
|
+
SVC_SRC_KEY: '_dd.svc_src',
|
|
24
25
|
DATADOG_LAMBDA_EXTENSION_PATH: '/opt/extensions/datadog-agent',
|
|
25
26
|
DATADOG_MINI_AGENT_PATH: '/tmp/datadog/mini_agent_ready',
|
|
26
27
|
DECISION_MAKER_KEY: '_dd.p.dm',
|
|
@@ -23,6 +23,9 @@ class Crashtracker {
|
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/**
|
|
27
|
+
* @param {import('../config/config-base')} config - Tracer configuration
|
|
28
|
+
*/
|
|
26
29
|
start (config) {
|
|
27
30
|
if (this.#started) return this.configure(config)
|
|
28
31
|
|
|
@@ -35,7 +38,7 @@ class Crashtracker {
|
|
|
35
38
|
this.#getMetadata(config)
|
|
36
39
|
)
|
|
37
40
|
} catch (e) {
|
|
38
|
-
log.error('Error
|
|
41
|
+
log.error('Error initializing crashtracker', e)
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
44
|
|
|
@@ -49,6 +52,9 @@ class Crashtracker {
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
// TODO: Send only configured values when defaults are fixed.
|
|
55
|
+
/**
|
|
56
|
+
* @param {import('../config/config-base')} config - Tracer configuration
|
|
57
|
+
*/
|
|
52
58
|
#getConfig (config) {
|
|
53
59
|
const url = getAgentUrl(config)
|
|
54
60
|
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { existsSync } = require('node:fs')
|
|
4
3
|
const { isMainThread } = require('worker_threads')
|
|
5
4
|
const log = require('../log')
|
|
6
5
|
|
|
7
|
-
|
|
8
|
-
// The segfault bypasses JS try/catch so we must avoid loading it entirely.
|
|
9
|
-
// See: https://github.com/DataDog/libdatadog-nodejs/issues/114
|
|
10
|
-
const isArm64Musl = process.arch === 'arm64' && existsSync('/etc/alpine-release')
|
|
11
|
-
|
|
12
|
-
if (isMainThread && !isArm64Musl) {
|
|
6
|
+
if (isMainThread) {
|
|
13
7
|
try {
|
|
14
8
|
module.exports = require('./crashtracker')
|
|
15
9
|
} catch (e) {
|
|
@@ -105,10 +105,13 @@ function getObjectValue (obj, maxLength) {
|
|
|
105
105
|
// case 'node': // TODO: What does this subtype represent?
|
|
106
106
|
case 'regexp':
|
|
107
107
|
return { type: obj.className, value: obj.description }
|
|
108
|
-
case 'date':
|
|
108
|
+
case 'date': {
|
|
109
109
|
// TODO: This looses millisecond resolution, as that's not retained in the `.toString()` representation contained
|
|
110
110
|
// in the `description` field. Unfortunately that's all we get from the Chrome DevTools Protocol.
|
|
111
|
-
|
|
111
|
+
const date = new Date(obj.description)
|
|
112
|
+
const value = Number.isNaN(date.getTime()) ? obj.description : `${date.toISOString().slice(0, -5)}Z`
|
|
113
|
+
return { type: obj.className, value }
|
|
114
|
+
}
|
|
112
115
|
case 'map':
|
|
113
116
|
return toMap(obj.className, obj.properties, maxLength, timeBudgetReached)
|
|
114
117
|
case 'set':
|
|
@@ -147,7 +147,7 @@ function start (config, rcInstance) {
|
|
|
147
147
|
* Sends the new configuration to the worker thread via the config channel.
|
|
148
148
|
* Does nothing if the worker is not started.
|
|
149
149
|
*
|
|
150
|
-
* @param {
|
|
150
|
+
* @param {import('../config/config-base')} config - The updated tracer configuration object
|
|
151
151
|
*/
|
|
152
152
|
function configure (config) {
|
|
153
153
|
if (configChannel === null) return
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const lookup = require('dns').lookup // cache to avoid instrumentation
|
|
4
3
|
const dgram = require('dgram')
|
|
5
4
|
const isIP = require('net').isIP
|
|
6
5
|
|
|
7
6
|
const request = require('./exporters/common/request')
|
|
8
7
|
const log = require('./log')
|
|
9
8
|
const Histogram = require('./histogram')
|
|
10
|
-
const defaults = require('./config/defaults')
|
|
11
9
|
const { getAgentUrl } = require('./agent/url')
|
|
12
10
|
const { entityId } = require('./exporters/common/docker')
|
|
13
11
|
|
|
@@ -23,7 +21,9 @@ const TYPE_HISTOGRAM = 'h'
|
|
|
23
21
|
* @implements {DogStatsD}
|
|
24
22
|
*/
|
|
25
23
|
class DogStatsDClient {
|
|
26
|
-
|
|
24
|
+
#lookup
|
|
25
|
+
constructor (options) {
|
|
26
|
+
this.#lookup = options.lookup
|
|
27
27
|
if (options.metricsProxyUrl) {
|
|
28
28
|
this._httpOptions = {
|
|
29
29
|
method: 'POST',
|
|
@@ -32,11 +32,10 @@ class DogStatsDClient {
|
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
this._host = options.host
|
|
35
|
+
this._host = options.host
|
|
36
36
|
this._family = isIP(this._host)
|
|
37
|
-
this._port = options.port
|
|
38
|
-
this.
|
|
39
|
-
this._tags = options.tags || []
|
|
37
|
+
this._port = options.port
|
|
38
|
+
this._tags = options.tags
|
|
40
39
|
this._queue = []
|
|
41
40
|
this._buffer = ''
|
|
42
41
|
this._offset = 0
|
|
@@ -99,7 +98,7 @@ class DogStatsDClient {
|
|
|
99
98
|
|
|
100
99
|
_sendUdp (queue) {
|
|
101
100
|
if (this._family === 0) {
|
|
102
|
-
lookup(this._host, (err, address, family) => {
|
|
101
|
+
this.#lookup(this._host, (err, address, family) => {
|
|
103
102
|
if (err) return log.error('DogStatsDClient: Host not found', err)
|
|
104
103
|
this._sendUdpFromQueue(queue, address, family)
|
|
105
104
|
})
|
|
@@ -118,7 +117,7 @@ class DogStatsDClient {
|
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
_add (stat, value, type, tags) {
|
|
121
|
-
let message = `${
|
|
120
|
+
let message = `${stat}:${value}|${type}`
|
|
122
121
|
|
|
123
122
|
// Don't manipulate this._tags as it is still used
|
|
124
123
|
tags = tags ? [...this._tags, ...tags] : this._tags
|
|
@@ -164,6 +163,9 @@ class DogStatsDClient {
|
|
|
164
163
|
return socket
|
|
165
164
|
}
|
|
166
165
|
|
|
166
|
+
/**
|
|
167
|
+
* @param {import('./config/config-base')} config - Tracer configuration
|
|
168
|
+
*/
|
|
167
169
|
static generateClientConfig (config) {
|
|
168
170
|
const tags = []
|
|
169
171
|
|
|
@@ -183,6 +185,7 @@ class DogStatsDClient {
|
|
|
183
185
|
host: config.dogstatsd.hostname,
|
|
184
186
|
port: config.dogstatsd.port,
|
|
185
187
|
tags,
|
|
188
|
+
lookup: config.lookup,
|
|
186
189
|
}
|
|
187
190
|
|
|
188
191
|
if (config.url || config.port) {
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const { MsgpackChunk, MsgpackEncoder } = require('../msgpack')
|
|
4
4
|
const log = require('../log')
|
|
5
5
|
const { isTrue } = require('../util')
|
|
6
|
-
const { memoize } = require('../log/utils')
|
|
7
6
|
const { getValueFromEnvSources } = require('../config/helper')
|
|
8
7
|
const { truncateSpan, normalizeSpan } = require('./tags-processors')
|
|
9
8
|
|
|
@@ -140,7 +139,7 @@ class AgentEncoder {
|
|
|
140
139
|
this._traceBytes.length = 0
|
|
141
140
|
this._stringCount = 0
|
|
142
141
|
this._stringBytes.length = 0
|
|
143
|
-
this._stringMap =
|
|
142
|
+
this._stringMap = Object.create(null)
|
|
144
143
|
|
|
145
144
|
this._cacheString('')
|
|
146
145
|
}
|
|
@@ -338,11 +337,13 @@ class AgentEncoder {
|
|
|
338
337
|
}
|
|
339
338
|
}
|
|
340
339
|
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
340
|
+
const seenKeys = new Set()
|
|
341
|
+
const memoizedLogDebug = (key, message) => {
|
|
342
|
+
if (!seenKeys.has(key)) {
|
|
343
|
+
seenKeys.add(key)
|
|
344
|
+
log.debug(message)
|
|
345
|
+
}
|
|
346
|
+
}
|
|
346
347
|
|
|
347
348
|
function formatSpanEvents (span) {
|
|
348
349
|
for (const spanEvent of span.span_events) {
|
|
@@ -31,7 +31,7 @@ class SpanStatsEncoder extends AgentEncoder {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
_encodeStat (bytes, stat) {
|
|
34
|
-
this._encodeMapPrefix(bytes,
|
|
34
|
+
this._encodeMapPrefix(bytes, 15)
|
|
35
35
|
|
|
36
36
|
this._encodeString(bytes, 'Service')
|
|
37
37
|
const service = stat.Service || DEFAULT_SERVICE_NAME
|
|
@@ -76,6 +76,9 @@ class SpanStatsEncoder extends AgentEncoder {
|
|
|
76
76
|
|
|
77
77
|
this._encodeString(bytes, 'HTTPEndpoint')
|
|
78
78
|
this._encodeString(bytes, stat.HTTPEndpoint)
|
|
79
|
+
|
|
80
|
+
this._encodeString(bytes, 'srv_src')
|
|
81
|
+
this._encodeString(bytes, stat.srv_src || '')
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
_encodeBucket (bytes, bucket) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { inspect } = require('node:util')
|
|
4
|
+
const { channel } = require('dc-polyfill')
|
|
5
|
+
|
|
4
6
|
const request = require('../common/request')
|
|
5
7
|
const { logIntegrations, logAgentError } = require('../../startup-log')
|
|
6
8
|
const runtimeMetrics = require('../../runtime_metrics')
|
|
@@ -10,10 +12,14 @@ const BaseWriter = require('../common/writer')
|
|
|
10
12
|
const propagationHash = require('../../propagation-hash')
|
|
11
13
|
|
|
12
14
|
const METRIC_PREFIX = 'datadog.tracer.node.exporter.agent'
|
|
15
|
+
const firstFlushChannel = channel('dd-trace:exporter:first-flush')
|
|
13
16
|
|
|
14
17
|
class AgentWriter extends BaseWriter {
|
|
15
18
|
constructor (...args) {
|
|
16
|
-
super(
|
|
19
|
+
super({
|
|
20
|
+
...args[0],
|
|
21
|
+
beforeFirstFlush: () => firstFlushChannel.publish(),
|
|
22
|
+
})
|
|
17
23
|
const { prioritySampler, lookup, protocolVersion, headers, config = {} } = args[0]
|
|
18
24
|
const AgentEncoder = getEncoder(protocolVersion)
|
|
19
25
|
|
|
@@ -18,6 +18,10 @@ const maxActiveBufferSize = 1024 * 1024 * 64
|
|
|
18
18
|
|
|
19
19
|
let activeBufferSize = 0
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @param {string|URL|object} urlObjOrString
|
|
23
|
+
* @returns {object}
|
|
24
|
+
*/
|
|
21
25
|
function parseUrl (urlObjOrString) {
|
|
22
26
|
if (urlObjOrString !== null && typeof urlObjOrString === 'object') return urlToHttpOptions(urlObjOrString)
|
|
23
27
|
|
|
@@ -33,6 +37,11 @@ function parseUrl (urlObjOrString) {
|
|
|
33
37
|
return url
|
|
34
38
|
}
|
|
35
39
|
|
|
40
|
+
/**
|
|
41
|
+
* @param {Buffer|string|Readable|Array<Buffer|string>} data
|
|
42
|
+
* @param {object} options
|
|
43
|
+
* @param {(error: Error|null, result: string, statusCode: number) => void} callback
|
|
44
|
+
*/
|
|
36
45
|
function request (data, options, callback) {
|
|
37
46
|
if (!options.headers) {
|
|
38
47
|
options.headers = {}
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
|
+
|
|
3
5
|
const log = require('../../log')
|
|
4
6
|
const request = require('./request')
|
|
5
7
|
const { safeJSONStringify } = require('./util')
|
|
6
8
|
|
|
9
|
+
const firstFlushChannel = channel('dd-trace:exporter:first-flush')
|
|
10
|
+
|
|
7
11
|
class Writer {
|
|
8
|
-
constructor ({ url }) {
|
|
12
|
+
constructor ({ url, beforeFirstFlush }) {
|
|
9
13
|
this._url = url
|
|
14
|
+
this._beforeFirstFlush = beforeFirstFlush
|
|
10
15
|
}
|
|
11
16
|
|
|
17
|
+
#isFirstFlush = true
|
|
18
|
+
|
|
12
19
|
flush (done = () => {}) {
|
|
13
20
|
const count = this._encoder.count()
|
|
14
21
|
|
|
@@ -16,8 +23,11 @@ class Writer {
|
|
|
16
23
|
this._encoder.reset()
|
|
17
24
|
done()
|
|
18
25
|
} else if (count > 0) {
|
|
26
|
+
if (this.#isFirstFlush && firstFlushChannel.hasSubscribers && this._beforeFirstFlush) {
|
|
27
|
+
this.#isFirstFlush = false
|
|
28
|
+
this._beforeFirstFlush()
|
|
29
|
+
}
|
|
19
30
|
const payload = this._encoder.makePayload()
|
|
20
|
-
|
|
21
31
|
this._sendPayload(payload, count, done)
|
|
22
32
|
} else {
|
|
23
33
|
done()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const { getValueFromEnvSources } = require('./config/helper')
|
|
4
|
-
const { isFalse } = require('./util')
|
|
4
|
+
const { isFalse, isTrue } = require('./util')
|
|
5
5
|
|
|
6
6
|
// Global `jest` is only present in Jest workers.
|
|
7
7
|
const inJestWorker = typeof jest !== 'undefined'
|
|
@@ -9,7 +9,10 @@ const inJestWorker = typeof jest !== 'undefined'
|
|
|
9
9
|
const ddTraceDisabled = getValueFromEnvSources('DD_TRACE_ENABLED')
|
|
10
10
|
? isFalse(getValueFromEnvSources('DD_TRACE_ENABLED'))
|
|
11
11
|
: String(getValueFromEnvSources('OTEL_TRACES_EXPORTER')).toLowerCase() === 'none'
|
|
12
|
+
const shouldUseProxyWhenTracingDisabled =
|
|
13
|
+
isTrue(getValueFromEnvSources('DD_DYNAMIC_INSTRUMENTATION_ENABLED')) ||
|
|
14
|
+
isTrue(getValueFromEnvSources('DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED'))
|
|
12
15
|
|
|
13
|
-
module.exports = ddTraceDisabled || inJestWorker
|
|
16
|
+
module.exports = (ddTraceDisabled && !shouldUseProxyWhenTracingDisabled) || inJestWorker
|
|
14
17
|
? require('./noop/proxy')
|
|
15
18
|
: require('./proxy')
|
|
@@ -89,12 +89,12 @@ const registerLambdaHook = () => {
|
|
|
89
89
|
const lambdaFilePaths = _getLambdaFilePaths(lambdaStylePath)
|
|
90
90
|
|
|
91
91
|
// TODO: Redo this like any other instrumentation.
|
|
92
|
-
Hook(lambdaFilePaths, (moduleExports, name) => {
|
|
92
|
+
Hook(lambdaFilePaths, (moduleExports, name, _, moduleVersion) => {
|
|
93
93
|
require('./patch')
|
|
94
94
|
|
|
95
95
|
for (const { hook } of instrumentations[name]) {
|
|
96
96
|
try {
|
|
97
|
-
moduleExports = hook(moduleExports)
|
|
97
|
+
moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
|
|
98
98
|
} catch (e) {
|
|
99
99
|
log.error('Error executing lambda hook', e)
|
|
100
100
|
}
|
|
@@ -104,16 +104,16 @@ const registerLambdaHook = () => {
|
|
|
104
104
|
})
|
|
105
105
|
} else {
|
|
106
106
|
const moduleToPatch = 'datadog-lambda-js'
|
|
107
|
-
Hook([moduleToPatch], (moduleExports, moduleName, _) => {
|
|
107
|
+
Hook([moduleToPatch], (moduleExports, moduleName, _, moduleVersion) => {
|
|
108
108
|
moduleName = moduleName.replace(pathSepExpr, '/')
|
|
109
109
|
|
|
110
110
|
require('./patch')
|
|
111
111
|
|
|
112
|
-
for (const {
|
|
113
|
-
const fullFilename = filename(
|
|
112
|
+
for (const { file, hook } of instrumentations[moduleToPatch]) {
|
|
113
|
+
const fullFilename = filename(moduleToPatch, file)
|
|
114
114
|
if (moduleName === fullFilename) {
|
|
115
115
|
try {
|
|
116
|
-
moduleExports = hook(moduleExports)
|
|
116
|
+
moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
|
|
117
117
|
} catch (e) {
|
|
118
118
|
log.error('Error executing lambda hook for datadog-lambda-js', e)
|
|
119
119
|
}
|
|
@@ -43,9 +43,12 @@ let spanWriter
|
|
|
43
43
|
/** @type {LLMObsEvalMetricsWriter | null} */
|
|
44
44
|
let evalWriter
|
|
45
45
|
|
|
46
|
-
/** @type {import('../config')} */
|
|
46
|
+
/** @type {import('../config/config-base')} */
|
|
47
47
|
let globalTracerConfig
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* @param {@type import('../config/config-base')} config
|
|
51
|
+
*/
|
|
49
52
|
function enable (config) {
|
|
50
53
|
globalTracerConfig = config
|
|
51
54
|
|
|
@@ -18,6 +18,7 @@ const {
|
|
|
18
18
|
getToolNameFromTags,
|
|
19
19
|
getToolCallResultContent,
|
|
20
20
|
getLlmObsSpanName,
|
|
21
|
+
getTelemetryMetadata,
|
|
21
22
|
} = require('./util')
|
|
22
23
|
|
|
23
24
|
/**
|
|
@@ -216,6 +217,9 @@ class VercelAILLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
216
217
|
|
|
217
218
|
this._tagger.tagEmbeddingIO(span, parsedInputs, output)
|
|
218
219
|
|
|
220
|
+
const metadata = getTelemetryMetadata(tags)
|
|
221
|
+
this._tagger.tagMetadata(span, metadata)
|
|
222
|
+
|
|
219
223
|
const usage = tags['ai.usage.tokens']
|
|
220
224
|
this._tagger.tagMetrics(span, {
|
|
221
225
|
inputTokens: usage,
|
|
@@ -234,7 +238,7 @@ class VercelAILLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
234
238
|
|
|
235
239
|
this._tagger.tagTextIO(span, prompt, output)
|
|
236
240
|
|
|
237
|
-
const metadata = getGenerationMetadata(tags)
|
|
241
|
+
const metadata = getGenerationMetadata(tags)
|
|
238
242
|
metadata.schema = getJsonStringValue(tags['ai.schema'], {})
|
|
239
243
|
this._tagger.tagMetadata(span, metadata)
|
|
240
244
|
}
|
|
@@ -10,6 +10,10 @@ const MODEL_METADATA_KEYS = new Set([
|
|
|
10
10
|
'stop_sequences',
|
|
11
11
|
])
|
|
12
12
|
|
|
13
|
+
const VERCEL_AI_TELEMETRY_METADATA_PREFIX = 'ai.telemetry.metadata.'
|
|
14
|
+
const VERCEL_AI_MODEL_METADATA_PREFIX = 'gen_ai.request.'
|
|
15
|
+
const VERCEL_AI_GENERATION_METADATA_PREFIX = 'ai.settings.'
|
|
16
|
+
|
|
13
17
|
/**
|
|
14
18
|
* @typedef {import('../../../opentracing/span')} Span
|
|
15
19
|
*
|
|
@@ -107,17 +111,29 @@ function getJsonStringValue (str, defaultValue) {
|
|
|
107
111
|
|
|
108
112
|
/**
|
|
109
113
|
* Get the model metadata from the span tags (top_p, top_k, temperature, etc.)
|
|
114
|
+
* Additionally, set telemetry metadata from manual telemetry tags.
|
|
110
115
|
* @param {SpanTags} tags
|
|
111
116
|
* @returns {Record<string, unknown> | null}
|
|
112
117
|
*/
|
|
113
118
|
function getModelMetadata (tags) {
|
|
114
119
|
/** @type {Record<string, unknown>} */
|
|
115
120
|
const modelMetadata = {}
|
|
116
|
-
for (const
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
+
for (const tag of Object.keys(tags)) {
|
|
122
|
+
const isModelMetadata = tag.startsWith(VERCEL_AI_MODEL_METADATA_PREFIX)
|
|
123
|
+
if (isModelMetadata) {
|
|
124
|
+
const lastCommaPosition = tag.lastIndexOf('.')
|
|
125
|
+
const metadataKey = lastCommaPosition === -1 ? tag : tag.slice(lastCommaPosition + 1)
|
|
126
|
+
if (metadataKey && MODEL_METADATA_KEYS.has(metadataKey)) {
|
|
127
|
+
modelMetadata[metadataKey] = tags[tag]
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
const isTelemetryMetadata = tag.startsWith(VERCEL_AI_TELEMETRY_METADATA_PREFIX)
|
|
131
|
+
if (isTelemetryMetadata) {
|
|
132
|
+
const metadataKey = tag.slice(VERCEL_AI_TELEMETRY_METADATA_PREFIX.length)
|
|
133
|
+
if (metadataKey) {
|
|
134
|
+
modelMetadata[metadataKey] = tags[tag]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
121
137
|
}
|
|
122
138
|
}
|
|
123
139
|
|
|
@@ -126,6 +142,7 @@ function getModelMetadata (tags) {
|
|
|
126
142
|
|
|
127
143
|
/**
|
|
128
144
|
* Get the generation metadata from the span tags (maxSteps, maxRetries, etc.)
|
|
145
|
+
* Additionally, set telemetry metadata from manual telemetry tags.
|
|
129
146
|
* @param {SpanTags} tags
|
|
130
147
|
* @returns {Record<string, unknown> | null}
|
|
131
148
|
*/
|
|
@@ -134,14 +151,24 @@ function getGenerationMetadata (tags) {
|
|
|
134
151
|
const metadata = {}
|
|
135
152
|
|
|
136
153
|
for (const tag of Object.keys(tags)) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
154
|
+
const isGenerationMetadata = tag.startsWith(VERCEL_AI_GENERATION_METADATA_PREFIX)
|
|
155
|
+
if (isGenerationMetadata) {
|
|
156
|
+
const lastCommaPosition = tag.lastIndexOf('.')
|
|
157
|
+
const settingKey = lastCommaPosition === -1 ? tag : tag.slice(lastCommaPosition + 1)
|
|
158
|
+
const transformedKey = settingKey.replaceAll(/[A-Z]/g, letter => '_' + letter.toLowerCase())
|
|
159
|
+
if (MODEL_METADATA_KEYS.has(transformedKey)) continue
|
|
142
160
|
|
|
143
|
-
|
|
144
|
-
|
|
161
|
+
const settingValue = tags[tag]
|
|
162
|
+
metadata[settingKey] = settingValue
|
|
163
|
+
} else {
|
|
164
|
+
const isTelemetryMetadata = tag.startsWith(VERCEL_AI_TELEMETRY_METADATA_PREFIX)
|
|
165
|
+
if (isTelemetryMetadata) {
|
|
166
|
+
const metadataKey = tag.slice(VERCEL_AI_TELEMETRY_METADATA_PREFIX.length)
|
|
167
|
+
if (metadataKey) {
|
|
168
|
+
metadata[metadataKey] = tags[tag]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
145
172
|
}
|
|
146
173
|
|
|
147
174
|
return Object.keys(metadata).length ? metadata : null
|
|
@@ -205,6 +232,26 @@ function getLlmObsSpanName (operation, functionId) {
|
|
|
205
232
|
return functionId ? `${functionId}.${operation}` : operation
|
|
206
233
|
}
|
|
207
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Get custom telemetry metadata from ai.telemetry.metadata.* attributes
|
|
237
|
+
* @param {Record<string, unknown>} tags
|
|
238
|
+
* @returns {Record<string, unknown> | null}
|
|
239
|
+
*/
|
|
240
|
+
function getTelemetryMetadata (tags) {
|
|
241
|
+
const metadata = {}
|
|
242
|
+
|
|
243
|
+
for (const tag of Object.keys(tags)) {
|
|
244
|
+
if (!tag.startsWith(VERCEL_AI_TELEMETRY_METADATA_PREFIX)) continue
|
|
245
|
+
|
|
246
|
+
const metadataKey = tag.slice(VERCEL_AI_TELEMETRY_METADATA_PREFIX.length)
|
|
247
|
+
if (metadataKey) {
|
|
248
|
+
metadata[metadataKey] = tags[tag]
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return Object.keys(metadata).length ? metadata : null
|
|
253
|
+
}
|
|
254
|
+
|
|
208
255
|
module.exports = {
|
|
209
256
|
getSpanTags,
|
|
210
257
|
getOperation,
|
|
@@ -215,4 +262,5 @@ module.exports = {
|
|
|
215
262
|
getToolNameFromTags,
|
|
216
263
|
getToolCallResultContent,
|
|
217
264
|
getLlmObsSpanName,
|
|
265
|
+
getTelemetryMetadata,
|
|
218
266
|
}
|
|
@@ -65,10 +65,12 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
65
65
|
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: 'bedrock' })
|
|
66
66
|
|
|
67
67
|
const parent = llmobsStore.getStore()?.span
|
|
68
|
+
// Use full modelId and unified provider for LLMObs (required for backend cost estimation).
|
|
69
|
+
// Split modelProvider/modelName from parseModelId() are still used below for response parsing.
|
|
68
70
|
this._tagger.registerLLMObsSpan(span, {
|
|
69
71
|
parent,
|
|
70
|
-
modelName:
|
|
71
|
-
modelProvider:
|
|
72
|
+
modelName: request.params.modelId.toLowerCase(),
|
|
73
|
+
modelProvider: 'amazon_bedrock',
|
|
72
74
|
kind: 'llm',
|
|
73
75
|
name: 'bedrock-runtime.command',
|
|
74
76
|
integration: 'bedrock',
|
|
@@ -29,16 +29,23 @@ class LLMObs extends NoopLLMObs {
|
|
|
29
29
|
*/
|
|
30
30
|
#hasUserSpanProcessor = false
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @param {import('../tracer')} tracer - Tracer instance
|
|
34
|
+
* @param {import('./index')} llmobsModule - LLMObs module instance
|
|
35
|
+
* @param {import('../config/config-base')} config - Tracer configuration
|
|
36
|
+
*/
|
|
32
37
|
constructor (tracer, llmobsModule, config) {
|
|
33
38
|
super(tracer)
|
|
34
39
|
|
|
40
|
+
/** @type {import('../config/config-base')} */
|
|
35
41
|
this._config = config
|
|
42
|
+
|
|
36
43
|
this._llmobsModule = llmobsModule
|
|
37
44
|
this._tagger = new LLMObsTagger(config)
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
get enabled () {
|
|
41
|
-
return this._config.llmobs.enabled
|
|
48
|
+
return this._config.llmobs.enabled ?? false
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
enable (options = {}) {
|
|
@@ -56,13 +63,10 @@ class LLMObs extends NoopLLMObs {
|
|
|
56
63
|
return
|
|
57
64
|
}
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// TODO: This will update config telemetry with the origin 'code', which is not ideal when `enable()` is called
|
|
64
|
-
// based on `APM_TRACING` RC product updates.
|
|
65
|
-
this._config.updateOptions({ llmobs })
|
|
66
|
+
// TODO: These configs should be passed through directly at construction time instead.
|
|
67
|
+
this._config.llmobs.enabled = true
|
|
68
|
+
this._config.llmobs.mlApp = options.mlApp
|
|
69
|
+
this._config.llmobs.agentlessEnabled = options.agentlessEnabled
|
|
66
70
|
|
|
67
71
|
// configure writers and channel subscribers
|
|
68
72
|
this._llmobsModule.enable(this._config)
|
|
@@ -47,8 +47,11 @@ const { storage } = require('./storage')
|
|
|
47
47
|
const registry = new WeakMap()
|
|
48
48
|
|
|
49
49
|
class LLMObsTagger {
|
|
50
|
+
/** @type {import('../config/config-base')} */
|
|
51
|
+
#config
|
|
52
|
+
|
|
50
53
|
constructor (config, softFail = false) {
|
|
51
|
-
this
|
|
54
|
+
this.#config = config
|
|
52
55
|
|
|
53
56
|
this.softFail = softFail
|
|
54
57
|
}
|
|
@@ -72,15 +75,15 @@ class LLMObsTagger {
|
|
|
72
75
|
integration,
|
|
73
76
|
_decorator,
|
|
74
77
|
} = {}) {
|
|
75
|
-
if (!this.
|
|
78
|
+
if (!this.#config.llmobs.enabled) return
|
|
76
79
|
if (!kind) return // do not register it in the map if it doesn't have an llmobs span kind
|
|
77
80
|
|
|
78
81
|
const spanMlApp =
|
|
79
82
|
mlApp ||
|
|
80
83
|
registry.get(parent)?.[ML_APP] ||
|
|
81
84
|
span.context()._trace.tags[PROPAGATED_ML_APP_KEY] ||
|
|
82
|
-
this.
|
|
83
|
-
this.
|
|
85
|
+
this.#config.llmobs.mlApp ||
|
|
86
|
+
this.#config.service // this should always have a default
|
|
84
87
|
|
|
85
88
|
if (!spanMlApp) {
|
|
86
89
|
throw new Error(
|
|
@@ -624,7 +627,7 @@ class LLMObsTagger {
|
|
|
624
627
|
}
|
|
625
628
|
|
|
626
629
|
_register (span) {
|
|
627
|
-
if (!this.
|
|
630
|
+
if (!this.#config.llmobs.enabled) return
|
|
628
631
|
if (registry.has(span)) {
|
|
629
632
|
this.#handleFailure(`LLMObs Span "${span._name}" already registered.`)
|
|
630
633
|
return
|
|
@@ -634,7 +637,7 @@ class LLMObsTagger {
|
|
|
634
637
|
}
|
|
635
638
|
|
|
636
639
|
_setTag (span, key, value) {
|
|
637
|
-
if (!this.
|
|
640
|
+
if (!this.#config.llmobs.enabled) return
|
|
638
641
|
if (!registry.has(span)) {
|
|
639
642
|
this.#handleFailure(`Span "${span._name}" must be an LLMObs generated span.`)
|
|
640
643
|
return
|
|
@@ -45,7 +45,9 @@ class BaseLLMObsWriter {
|
|
|
45
45
|
/** @type {LLMObsBuffer} */
|
|
46
46
|
this._buffer = new LLMObsBuffer({ events: [], size: 0, isDefault: true })
|
|
47
47
|
|
|
48
|
+
/** @type {import('../../config/config-base')} */
|
|
48
49
|
this._config = config
|
|
50
|
+
|
|
49
51
|
this._endpoint = endpoint
|
|
50
52
|
this._baseEndpoint = endpoint // should not be unset
|
|
51
53
|
this._intake = intake
|
|
@@ -6,6 +6,9 @@ const telemetry = require('../telemetry')
|
|
|
6
6
|
const { fetchAgentInfo } = require('../../agent/info')
|
|
7
7
|
const { getAgentUrl } = require('../../agent/url')
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('../../config/config-base')} config
|
|
11
|
+
*/
|
|
9
12
|
function setAgentStrategy (config, setWritersAgentlessValue) {
|
|
10
13
|
const agentlessEnabled = config.llmobs.agentlessEnabled
|
|
11
14
|
|