dd-trace 5.67.0 → 5.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +6 -4
- package/README.md +0 -2
- package/ci/init.js +52 -54
- package/ext/exporters.d.ts +2 -1
- package/ext/exporters.js +2 -1
- package/index.d.ts +240 -3
- package/initialize.mjs +1 -1
- package/package.json +17 -11
- package/packages/datadog-core/src/storage.js +14 -13
- package/packages/datadog-esbuild/index.js +118 -26
- package/packages/datadog-instrumentations/src/aws-sdk.js +42 -4
- package/packages/datadog-instrumentations/src/azure-functions.js +1 -1
- package/packages/datadog-instrumentations/src/azure-service-bus.js +1 -1
- package/packages/datadog-instrumentations/src/cassandra-driver.js +2 -2
- package/packages/datadog-instrumentations/src/connect.js +6 -2
- package/packages/datadog-instrumentations/src/cucumber.js +31 -6
- package/packages/datadog-instrumentations/src/express.js +5 -6
- package/packages/datadog-instrumentations/src/fastify.js +3 -3
- package/packages/datadog-instrumentations/src/helpers/hook.js +28 -15
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +15 -5
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -3
- package/packages/datadog-instrumentations/src/http2/client.js +1 -0
- package/packages/datadog-instrumentations/src/http2/server.js +0 -1
- package/packages/datadog-instrumentations/src/ioredis.js +12 -1
- package/packages/datadog-instrumentations/src/jest.js +48 -36
- package/packages/datadog-instrumentations/src/limitd-client.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/main.js +15 -7
- package/packages/datadog-instrumentations/src/mocha/utils.js +3 -0
- package/packages/datadog-instrumentations/src/mongoose.js +2 -1
- package/packages/datadog-instrumentations/src/oracledb.js +19 -13
- package/packages/datadog-instrumentations/src/pg.js +9 -5
- package/packages/datadog-instrumentations/src/pino.js +18 -6
- package/packages/datadog-instrumentations/src/playwright.js +15 -1
- package/packages/datadog-instrumentations/src/sequelize.js +1 -1
- package/packages/datadog-instrumentations/src/vitest.js +155 -62
- package/packages/datadog-plugin-ai/src/tracing.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/base.js +23 -8
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/utils.js +101 -2
- package/packages/datadog-plugin-aws-sdk/src/util.js +1 -1
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +6 -0
- package/packages/datadog-plugin-cucumber/src/index.js +4 -56
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +6 -3
- package/packages/datadog-plugin-cypress/src/support.js +4 -0
- package/packages/datadog-plugin-express/src/code_origin.js +2 -2
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -2
- package/packages/datadog-plugin-jest/src/index.js +0 -21
- package/packages/datadog-plugin-mocha/src/index.js +3 -57
- package/packages/datadog-plugin-mongodb-core/src/index.js +38 -12
- package/packages/datadog-plugin-playwright/src/index.js +11 -5
- package/packages/datadog-plugin-vitest/src/index.js +5 -1
- package/packages/datadog-plugin-ws/src/close.js +1 -1
- package/packages/datadog-plugin-ws/src/producer.js +6 -1
- package/packages/datadog-plugin-ws/src/receiver.js +6 -1
- package/packages/dd-trace/src/aiguard/client.js +25 -0
- package/packages/dd-trace/src/aiguard/noop.js +9 -0
- package/packages/dd-trace/src/aiguard/sdk.js +173 -0
- package/packages/dd-trace/src/aiguard/tags.js +11 -0
- package/packages/dd-trace/src/appsec/iast/path-line.js +21 -4
- package/packages/dd-trace/src/appsec/iast/security-controls/parser.js +1 -1
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +6 -3
- package/packages/dd-trace/src/appsec/stack_trace.js +20 -1
- package/packages/dd-trace/src/appsec/telemetry/waf.js +2 -2
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -4
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +11 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +10 -1
- package/packages/dd-trace/src/config-helper.js +8 -1
- package/packages/dd-trace/src/config.js +92 -304
- package/packages/dd-trace/src/config_defaults.js +191 -0
- package/packages/dd-trace/src/crashtracking/crashtracker.js +2 -1
- package/packages/dd-trace/src/datastreams/fnv.js +2 -2
- package/packages/dd-trace/src/datastreams/index.js +23 -1
- package/packages/dd-trace/src/datastreams/writer.js +3 -2
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -1
- package/packages/dd-trace/src/dogstatsd.js +4 -3
- package/packages/dd-trace/src/encode/0.4.js +1 -5
- package/packages/dd-trace/src/exporter.js +1 -0
- package/packages/dd-trace/src/exporters/agent/index.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
- package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +3 -2
- package/packages/dd-trace/src/exporters/common/request.js +2 -1
- package/packages/dd-trace/src/exporters/span-stats/index.js +3 -2
- package/packages/dd-trace/src/llmobs/constants/tags.js +2 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +15 -4
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +20 -7
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +40 -13
- package/packages/dd-trace/src/llmobs/plugins/openai.js +7 -1
- package/packages/dd-trace/src/llmobs/tagger.js +8 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +2 -1
- package/packages/dd-trace/src/log/index.js +27 -16
- package/packages/dd-trace/src/log/log.js +29 -5
- package/packages/dd-trace/src/log/writer.js +5 -5
- package/packages/dd-trace/src/noop/proxy.js +4 -0
- package/packages/dd-trace/src/noop/span.js +1 -0
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentracing/span.js +19 -5
- package/packages/dd-trace/src/payload-tagging/config/index.js +16 -0
- package/packages/dd-trace/src/payload-tagging/index.js +26 -15
- package/packages/dd-trace/src/payload-tagging/tagging.js +17 -8
- package/packages/dd-trace/src/pkg.js +3 -1
- package/packages/dd-trace/src/plugin_manager.js +20 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +97 -3
- package/packages/dd-trace/src/plugins/composite.js +3 -0
- package/packages/dd-trace/src/plugins/index.js +2 -0
- package/packages/dd-trace/src/plugins/plugin.js +67 -0
- package/packages/dd-trace/src/plugins/util/git-cache.js +129 -0
- package/packages/dd-trace/src/plugins/util/git.js +41 -27
- package/packages/dd-trace/src/plugins/util/test.js +56 -27
- package/packages/dd-trace/src/plugins/util/web.js +1 -1
- package/packages/dd-trace/src/priority_sampler.js +70 -46
- package/packages/dd-trace/src/profiler.js +4 -1
- package/packages/dd-trace/src/profiling/config.js +73 -42
- package/packages/dd-trace/src/profiling/profiler.js +3 -1
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -8
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -0
- package/packages/dd-trace/src/profiling/profilers/wall.js +196 -117
- package/packages/dd-trace/src/proxy.js +15 -0
- package/packages/dd-trace/src/rate_limiter.js +26 -1
- package/packages/dd-trace/src/remote_config/capabilities.js +5 -0
- package/packages/dd-trace/src/remote_config/manager.js +3 -2
- package/packages/dd-trace/src/sampling_rule.js +124 -2
- package/packages/dd-trace/src/span_sampler.js +19 -0
- package/packages/dd-trace/src/standalone/product.js +9 -0
- package/packages/dd-trace/src/standalone/tracesource.js +16 -1
- package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +13 -0
- package/packages/dd-trace/src/startup-log.js +21 -2
- package/packages/dd-trace/src/supported-configurations.json +9 -0
- package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
- package/packages/dd-trace/src/util.js +1 -1
- package/register.js +1 -1
- package/version.js +4 -2
|
@@ -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', (
|
|
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 =
|
|
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
|
-
|
|
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:
|
|
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.
|
|
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)
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
-
|
|
3
|
-
const coalesce = require('koalas')
|
|
4
2
|
const { inspect } = require('util')
|
|
5
3
|
const { isTrue } = require('../util')
|
|
6
4
|
const { traceChannel, debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
|
|
7
5
|
const logWriter = require('./writer')
|
|
8
|
-
const { Log } = require('./log')
|
|
6
|
+
const { Log, LogConfig, NoTransmitError } = require('./log')
|
|
9
7
|
const { memoize } = require('./utils')
|
|
10
8
|
const { getEnvironmentVariable } = require('../config-helper')
|
|
11
9
|
|
|
@@ -15,7 +13,14 @@ const config = {
|
|
|
15
13
|
logLevel: 'debug'
|
|
16
14
|
}
|
|
17
15
|
|
|
16
|
+
// in most places where we know we want to mute a log we use log.error() directly
|
|
17
|
+
const NO_TRANSMIT = new LogConfig(false)
|
|
18
|
+
|
|
18
19
|
const log = {
|
|
20
|
+
LogConfig,
|
|
21
|
+
NO_TRANSMIT,
|
|
22
|
+
NoTransmitError,
|
|
23
|
+
|
|
19
24
|
/**
|
|
20
25
|
* @returns Read-only version of logging config. To modify config, call `log.use` and `log.toggle`
|
|
21
26
|
*/
|
|
@@ -92,18 +97,26 @@ const log = {
|
|
|
92
97
|
return this
|
|
93
98
|
},
|
|
94
99
|
|
|
100
|
+
errorWithoutTelemetry (...args) {
|
|
101
|
+
args.push(NO_TRANSMIT)
|
|
102
|
+
if (errorChannel.hasSubscribers) {
|
|
103
|
+
errorChannel.publish(Log.parse(...args))
|
|
104
|
+
}
|
|
105
|
+
return this
|
|
106
|
+
},
|
|
107
|
+
|
|
95
108
|
deprecate (code, message) {
|
|
96
109
|
return this._deprecate(code, message)
|
|
97
110
|
},
|
|
98
111
|
|
|
99
112
|
isEnabled (fleetStableConfigValue, localStableConfigValue) {
|
|
100
|
-
return isTrue(
|
|
101
|
-
fleetStableConfigValue
|
|
102
|
-
getEnvironmentVariable('DD_TRACE_DEBUG')
|
|
103
|
-
getEnvironmentVariable('OTEL_LOG_LEVEL') === 'debug' || undefined
|
|
104
|
-
localStableConfigValue
|
|
113
|
+
return isTrue(
|
|
114
|
+
fleetStableConfigValue ??
|
|
115
|
+
getEnvironmentVariable('DD_TRACE_DEBUG') ??
|
|
116
|
+
(getEnvironmentVariable('OTEL_LOG_LEVEL') === 'debug' || undefined) ??
|
|
117
|
+
localStableConfigValue ??
|
|
105
118
|
config.enabled
|
|
106
|
-
)
|
|
119
|
+
)
|
|
107
120
|
},
|
|
108
121
|
|
|
109
122
|
getLogLevel (
|
|
@@ -111,14 +124,12 @@ const log = {
|
|
|
111
124
|
fleetStableConfigValue,
|
|
112
125
|
localStableConfigValue
|
|
113
126
|
) {
|
|
114
|
-
return
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
getEnvironmentVariable('
|
|
118
|
-
|
|
119
|
-
localStableConfigValue,
|
|
127
|
+
return optionsValue ??
|
|
128
|
+
fleetStableConfigValue ??
|
|
129
|
+
getEnvironmentVariable('DD_TRACE_LOG_LEVEL') ??
|
|
130
|
+
getEnvironmentVariable('OTEL_LOG_LEVEL') ??
|
|
131
|
+
localStableConfigValue ??
|
|
120
132
|
config.logLevel
|
|
121
|
-
)
|
|
122
133
|
}
|
|
123
134
|
}
|
|
124
135
|
|
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
const { format } = require('util')
|
|
4
4
|
|
|
5
|
+
// other times we produce an Error in a central location and log it several other places
|
|
6
|
+
class NoTransmitError extends Error {}
|
|
7
|
+
|
|
5
8
|
class Log {
|
|
6
|
-
constructor (message, args, cause, delegate) {
|
|
9
|
+
constructor (message, args, cause, delegate, sendViaTelemetry = true) {
|
|
7
10
|
this.message = message
|
|
8
11
|
this.args = args
|
|
9
12
|
this.cause = cause
|
|
10
13
|
this.delegate = delegate
|
|
14
|
+
this.sendViaTelemetry = sendViaTelemetry
|
|
11
15
|
}
|
|
12
16
|
|
|
13
17
|
get formatted () {
|
|
@@ -22,10 +26,18 @@ class Log {
|
|
|
22
26
|
|
|
23
27
|
static parse (...args) {
|
|
24
28
|
let message, cause, delegate
|
|
29
|
+
let sendViaTelemetry = true
|
|
30
|
+
|
|
31
|
+
const maybeLogConfig = args.at(-1)
|
|
32
|
+
if (maybeLogConfig instanceof LogConfig) {
|
|
33
|
+
args.pop()
|
|
34
|
+
sendViaTelemetry = maybeLogConfig.transmit
|
|
35
|
+
}
|
|
25
36
|
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
37
|
+
const maybeError = args.at(-1)
|
|
38
|
+
if (maybeError && typeof maybeError === 'object' && maybeError.stack) { // maybeError instanceof Error?
|
|
28
39
|
cause = args.pop()
|
|
40
|
+
if (cause instanceof NoTransmitError) sendViaTelemetry = false
|
|
29
41
|
}
|
|
30
42
|
|
|
31
43
|
const firstArg = args.shift()
|
|
@@ -43,10 +55,22 @@ class Log {
|
|
|
43
55
|
message = String(firstArg)
|
|
44
56
|
}
|
|
45
57
|
|
|
46
|
-
return new Log(message, args, cause, delegate)
|
|
58
|
+
return new Log(message, args, cause, delegate, sendViaTelemetry)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Pass instances of this class to logger methods when fine-grain control is needed
|
|
64
|
+
* @property {boolean} transmit - Whether to send the log via telemetry.
|
|
65
|
+
*/
|
|
66
|
+
class LogConfig {
|
|
67
|
+
constructor (transmit = true) {
|
|
68
|
+
this.transmit = transmit
|
|
47
69
|
}
|
|
48
70
|
}
|
|
49
71
|
|
|
50
72
|
module.exports = {
|
|
51
|
-
Log
|
|
73
|
+
Log,
|
|
74
|
+
LogConfig,
|
|
75
|
+
NoTransmitError,
|
|
52
76
|
}
|
|
@@ -75,12 +75,12 @@ function onError (err) {
|
|
|
75
75
|
// TODO: replace it with Error(message, { cause }) when cause has broad support
|
|
76
76
|
if (formatted) {
|
|
77
77
|
withNoop(() => {
|
|
78
|
-
const
|
|
78
|
+
const stackTraceLimitBackup = Error.stackTraceLimit
|
|
79
79
|
Error.stackTraceLimit = 0
|
|
80
|
-
const
|
|
81
|
-
Error.stackTraceLimit =
|
|
82
|
-
Error.captureStackTrace(
|
|
83
|
-
logger.error(
|
|
80
|
+
const newError = new Error(formatted)
|
|
81
|
+
Error.stackTraceLimit = stackTraceLimitBackup
|
|
82
|
+
Error.captureStackTrace(newError, stackTraceLimitFunction)
|
|
83
|
+
logger.error(newError)
|
|
84
84
|
})
|
|
85
85
|
}
|
|
86
86
|
if (cause) withNoop(() => logger.error(cause))
|
|
@@ -4,18 +4,22 @@ const NoopTracer = require('./tracer')
|
|
|
4
4
|
const NoopAppsecSdk = require('../appsec/sdk/noop')
|
|
5
5
|
const NoopDogStatsDClient = require('./dogstatsd')
|
|
6
6
|
const NoopLLMObsSDK = require('../llmobs/noop')
|
|
7
|
+
const NoopAIGuardSDK = require('../aiguard/noop')
|
|
7
8
|
|
|
8
9
|
const noop = new NoopTracer()
|
|
9
10
|
const noopAppsec = new NoopAppsecSdk()
|
|
10
11
|
const noopDogStatsDClient = new NoopDogStatsDClient()
|
|
11
12
|
const noopLLMObs = new NoopLLMObsSDK(noop)
|
|
13
|
+
const noopAIGuard = new NoopAIGuardSDK()
|
|
12
14
|
|
|
15
|
+
/** @type {import('../../src/index')} Proxy */
|
|
13
16
|
class NoopProxy {
|
|
14
17
|
constructor () {
|
|
15
18
|
this._tracer = noop
|
|
16
19
|
this.appsec = noopAppsec
|
|
17
20
|
this.dogstatsd = noopDogStatsDClient
|
|
18
21
|
this.llmobs = noopLLMObs
|
|
22
|
+
this.aiguard = noopAIGuard
|
|
19
23
|
this.setBaggageItem = () => {}
|
|
20
24
|
this.getBaggageItem = () => {}
|
|
21
25
|
this.getAllBaggageItems = () => {}
|
|
@@ -22,6 +22,7 @@ class NoopSpan {
|
|
|
22
22
|
setTag (key, value) { return this }
|
|
23
23
|
addTags (keyValueMap) { return this }
|
|
24
24
|
addLink (link) { return this }
|
|
25
|
+
addLinks (links) { return this }
|
|
25
26
|
addSpanPointer (ptrKind, ptrDir, ptrHash) { return this }
|
|
26
27
|
log () { return this }
|
|
27
28
|
logEvent () {}
|
|
@@ -211,10 +211,21 @@ class Span {
|
|
|
211
211
|
return this
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
-
addLink (
|
|
215
|
-
//
|
|
214
|
+
addLink (link, attrs) {
|
|
215
|
+
// TODO: Remove this once we remove addLink(context, attrs) in v6.0.0
|
|
216
|
+
if (link instanceof SpanContext) {
|
|
217
|
+
link = { context: link, attributes: attrs ?? {} }
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const { context, attributes } = link
|
|
221
|
+
// Extract dd context
|
|
216
222
|
const ddSpanContext = context._ddContext
|
|
217
|
-
this._ddSpan.addLink(ddSpanContext, attributes)
|
|
223
|
+
this._ddSpan.addLink({ context: ddSpanContext, attributes })
|
|
224
|
+
return this
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
addLinks (links) {
|
|
228
|
+
links.forEach(link => this.addLink(link))
|
|
218
229
|
return this
|
|
219
230
|
}
|
|
220
231
|
|
|
@@ -86,8 +86,10 @@ class DatadogSpan {
|
|
|
86
86
|
|
|
87
87
|
this._startTime = fields.startTime || this._getTime()
|
|
88
88
|
|
|
89
|
-
this._links =
|
|
90
|
-
|
|
89
|
+
this._links = fields.links?.map(link => ({
|
|
90
|
+
context: link.context._ddContext ?? link.context,
|
|
91
|
+
attributes: this._sanitizeAttributes(link.attributes)
|
|
92
|
+
})) ?? []
|
|
91
93
|
|
|
92
94
|
if (DD_TRACE_EXPERIMENTAL_SPAN_COUNTS && finishedRegistry) {
|
|
93
95
|
runtimeMetrics.increment('runtime.node.spans.unfinished')
|
|
@@ -144,7 +146,7 @@ class DatadogSpan {
|
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
/**
|
|
147
|
-
* @returns {DatadogSpanContext}
|
|
149
|
+
* @returns {import('../priority_sampler').DatadogSpanContext}
|
|
148
150
|
*/
|
|
149
151
|
context () {
|
|
150
152
|
return this._spanContext
|
|
@@ -196,13 +198,25 @@ class DatadogSpan {
|
|
|
196
198
|
|
|
197
199
|
logEvent () {}
|
|
198
200
|
|
|
199
|
-
addLink (
|
|
201
|
+
addLink (link, attrs) {
|
|
202
|
+
// TODO: Remove this once we remove addLink(context, attrs) in v6.0.0
|
|
203
|
+
if (link instanceof SpanContext) {
|
|
204
|
+
link = { context: link, attributes: attrs ?? {} }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const { context, attributes } = link
|
|
208
|
+
|
|
200
209
|
this._links.push({
|
|
201
210
|
context: context._ddContext ?? context,
|
|
202
211
|
attributes: this._sanitizeAttributes(attributes)
|
|
203
212
|
})
|
|
204
213
|
}
|
|
205
214
|
|
|
215
|
+
addLinks (links) {
|
|
216
|
+
links.forEach(link => this.addLink(link))
|
|
217
|
+
return this
|
|
218
|
+
}
|
|
219
|
+
|
|
206
220
|
addSpanPointer (ptrKind, ptrDir, ptrHash) {
|
|
207
221
|
const zeroContext = new SpanContext({
|
|
208
222
|
traceId: id('0'),
|
|
@@ -214,7 +228,7 @@ class DatadogSpan {
|
|
|
214
228
|
'ptr.hash': ptrHash,
|
|
215
229
|
'link.kind': 'span-pointer'
|
|
216
230
|
}
|
|
217
|
-
this.addLink(zeroContext, attributes)
|
|
231
|
+
this.addLink({ context: zeroContext, attributes })
|
|
218
232
|
}
|
|
219
233
|
|
|
220
234
|
addEvent (name, attributesOrStartTime, startTime) {
|
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
const aws = require('./aws.json')
|
|
4
4
|
const sdks = { aws }
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Builds rules per service for a given SDK, appending user-provided rules.
|
|
8
|
+
*
|
|
9
|
+
* @param {Record<string, { request: string[], response: string[], expand: string[] }>} sdk
|
|
10
|
+
* @param {string[]} requestInput
|
|
11
|
+
* @param {string[]} responseInput
|
|
12
|
+
* @returns {Record<string, { request: string[], response: string[], expand: string[] }>}
|
|
13
|
+
*/
|
|
6
14
|
function getSDKRules (sdk, requestInput, responseInput) {
|
|
7
15
|
const sdkServiceRules = {}
|
|
8
16
|
for (const [service, serviceRules] of Object.entries(sdk)) {
|
|
@@ -17,6 +25,14 @@ function getSDKRules (sdk, requestInput, responseInput) {
|
|
|
17
25
|
return sdkServiceRules
|
|
18
26
|
}
|
|
19
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Appends input rules to all supported SDKs and returns a structure mapping SDK
|
|
30
|
+
* names to per-service rules.
|
|
31
|
+
*
|
|
32
|
+
* @param {string[]} [requestInput=[]]
|
|
33
|
+
* @param {string[]} [responseInput=[]]
|
|
34
|
+
* @returns {Record<string, Record<string, { request: string[], response: string[], expand: string[] }>>}
|
|
35
|
+
*/
|
|
20
36
|
function appendRules (requestInput = [], responseInput = []) {
|
|
21
37
|
const sdkRules = {}
|
|
22
38
|
for (const [name, sdk] of Object.entries(sdks)) {
|
|
@@ -14,8 +14,8 @@ const { tagsFromObject } = require('./tagging')
|
|
|
14
14
|
/**
|
|
15
15
|
* Given an identified value, attempt to parse it as JSON if relevant
|
|
16
16
|
*
|
|
17
|
-
* @param {
|
|
18
|
-
* @returns {
|
|
17
|
+
* @param {unknown} value
|
|
18
|
+
* @returns {unknown} the parsed object if parsing was successful, the input if not
|
|
19
19
|
*/
|
|
20
20
|
function maybeJSONParseValue (value) {
|
|
21
21
|
if (typeof value !== 'string' || value[0] !== '{') {
|
|
@@ -32,8 +32,8 @@ function maybeJSONParseValue (value) {
|
|
|
32
32
|
/**
|
|
33
33
|
* Apply expansion to all expansion JSONPath queries
|
|
34
34
|
*
|
|
35
|
-
* @param {
|
|
36
|
-
* @param {[
|
|
35
|
+
* @param {Record<string, unknown>} object
|
|
36
|
+
* @param {string[]} expansionRules list of JSONPath queries
|
|
37
37
|
*/
|
|
38
38
|
function expand (object, expansionRules) {
|
|
39
39
|
for (const rule of expansionRules) {
|
|
@@ -46,8 +46,8 @@ function expand (object, expansionRules) {
|
|
|
46
46
|
/**
|
|
47
47
|
* Apply redaction to all redaction JSONPath queries
|
|
48
48
|
*
|
|
49
|
-
* @param {
|
|
50
|
-
* @param {[
|
|
49
|
+
* @param {Record<string, unknown>} object
|
|
50
|
+
* @param {string[]} redactionRules
|
|
51
51
|
*/
|
|
52
52
|
function redact (object, redactionRules) {
|
|
53
53
|
for (const rule of redactionRules) {
|
|
@@ -65,15 +65,10 @@ function redact (object, redactionRules) {
|
|
|
65
65
|
* as there are leaf values in the object
|
|
66
66
|
* This function performs side-effects on a _copy_ of the input object.
|
|
67
67
|
*
|
|
68
|
-
* @param {
|
|
69
|
-
* @param {
|
|
70
|
-
* @param {
|
|
71
|
-
* @
|
|
72
|
-
* @param {Object} object the input object to generate tags from
|
|
73
|
-
* @param {Object} opts tag generation options
|
|
74
|
-
* @param {String} opts.prefix prefix for all generated tags
|
|
75
|
-
* @param {number} opts.maxDepth maximum depth to traverse the object
|
|
76
|
-
* @returns
|
|
68
|
+
* @param {{ expand: string[], request: string[], response: string[] }} config sdk configuration for the service
|
|
69
|
+
* @param {Record<string, unknown>} object the input object to generate tags from
|
|
70
|
+
* @param {{ prefix: string, maxDepth: number }} opts tag generation options
|
|
71
|
+
* @returns {Record<string, string|boolean>} Tags map
|
|
77
72
|
*/
|
|
78
73
|
function computeTags (config, object, opts) {
|
|
79
74
|
const payload = rfdc(object)
|
|
@@ -84,10 +79,26 @@ function computeTags (config, object, opts) {
|
|
|
84
79
|
return tagsFromObject(payload, opts)
|
|
85
80
|
}
|
|
86
81
|
|
|
82
|
+
/**
|
|
83
|
+
* Compute request tags with the request prefix.
|
|
84
|
+
*
|
|
85
|
+
* @param {{ expand: string[], request: string[], response: string[] }} config
|
|
86
|
+
* @param {Record<string, unknown>} object
|
|
87
|
+
* @param {{ maxDepth: number }} opts
|
|
88
|
+
* @returns {Record<string, string|boolean>}
|
|
89
|
+
*/
|
|
87
90
|
function tagsFromRequest (config, object, opts) {
|
|
88
91
|
return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_REQUEST_PREFIX })
|
|
89
92
|
}
|
|
90
93
|
|
|
94
|
+
/**
|
|
95
|
+
* Compute response tags with the response prefix.
|
|
96
|
+
*
|
|
97
|
+
* @param {{ expand: string[], request: string[], response: string[] }} config
|
|
98
|
+
* @param {Record<string, unknown>} object
|
|
99
|
+
* @param {{ maxDepth: number }} opts
|
|
100
|
+
* @returns {Record<string, string|boolean>}
|
|
101
|
+
*/
|
|
91
102
|
function tagsFromResponse (config, object, opts) {
|
|
92
103
|
return computeTags(config, object, { ...opts, prefix: PAYLOAD_TAG_RESPONSE_PREFIX })
|
|
93
104
|
}
|
|
@@ -8,24 +8,33 @@ const redactedKeys = new Set([
|
|
|
8
8
|
const truncated = 'truncated'
|
|
9
9
|
const redacted = 'redacted'
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Escapes dots in keys to preserve hierarchy in flattened tag names.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} key
|
|
15
|
+
* @returns {string}
|
|
16
|
+
*/
|
|
11
17
|
function escapeKey (key) {
|
|
12
18
|
return key.replaceAll('.', String.raw`\.`)
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
* Compute normalized payload tags from any given object.
|
|
23
|
+
*
|
|
24
|
+
* - Limits total tag count to `PAYLOAD_TAGGING_MAX_TAGS - 1` plus the `_dd.payload_tags_incomplete` flag
|
|
25
|
+
* - Truncates values at max depth and for large scalars
|
|
26
|
+
* - Redacts known sensitive keys
|
|
27
|
+
*
|
|
28
|
+
* @param {unknown} object - Input to flatten into tags
|
|
29
|
+
* @param {{ maxDepth: number, prefix: string }} opts - Traversal options
|
|
30
|
+
* @returns {Record<string, string|boolean>} Map of tag names to values
|
|
31
|
+
*/
|
|
24
32
|
function tagsFromObject (object, opts) {
|
|
25
33
|
const { maxDepth, prefix } = opts
|
|
26
34
|
|
|
27
35
|
let tagCount = 0
|
|
28
36
|
let abort = false
|
|
37
|
+
/** @type {Record<string, string|boolean>} */
|
|
29
38
|
const result = {}
|
|
30
39
|
|
|
31
40
|
function tagRec (prefix, object, depth = 0) {
|
|
@@ -20,8 +20,10 @@ function findPkg () {
|
|
|
20
20
|
|
|
21
21
|
const filePath = findUp('package.json', root, directory)
|
|
22
22
|
|
|
23
|
+
if (filePath === undefined) return {}
|
|
24
|
+
|
|
23
25
|
try {
|
|
24
|
-
return
|
|
26
|
+
return require(filePath)
|
|
25
27
|
} catch {
|
|
26
28
|
return {}
|
|
27
29
|
}
|
|
@@ -6,6 +6,15 @@ const plugins = require('./plugins')
|
|
|
6
6
|
const log = require('./log')
|
|
7
7
|
const { getEnvironmentVariable } = require('../../dd-trace/src/config-helper')
|
|
8
8
|
|
|
9
|
+
// Test optimization plugins that should only be enabled when isCiVisibility is true
|
|
10
|
+
const TEST_OPTIMIZATION_PLUGINS = new Set([
|
|
11
|
+
'jest',
|
|
12
|
+
'vitest',
|
|
13
|
+
'cucumber',
|
|
14
|
+
'mocha',
|
|
15
|
+
'playwright'
|
|
16
|
+
])
|
|
17
|
+
|
|
9
18
|
const loadChannel = channel('dd-trace:instrumentation:load')
|
|
10
19
|
|
|
11
20
|
// instrument everything that needs Plugin System V2 instrumentation
|
|
@@ -74,6 +83,13 @@ module.exports = class PluginManager {
|
|
|
74
83
|
|
|
75
84
|
if (!Plugin) return
|
|
76
85
|
if (!this._tracerConfig) return // TODO: don't wait for tracer to be initialized
|
|
86
|
+
|
|
87
|
+
// Check if this is a Test Optimization plugin and Test Optimization is not enabled
|
|
88
|
+
if (TEST_OPTIMIZATION_PLUGINS.has(name) && !this._tracerConfig.isCiVisibility) {
|
|
89
|
+
log.debug('Plugin "%s" is not initialized because Test Optimization mode is not enabled.', name)
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
77
93
|
if (!this._pluginsByName[name]) {
|
|
78
94
|
this._pluginsByName[name] = new Plugin(this._tracer, this._tracerConfig)
|
|
79
95
|
}
|
|
@@ -148,7 +164,8 @@ module.exports = class PluginManager {
|
|
|
148
164
|
middlewareTracingEnabled,
|
|
149
165
|
traceWebsocketMessagesEnabled,
|
|
150
166
|
traceWebsocketMessagesInheritSampling,
|
|
151
|
-
traceWebsocketMessagesSeparateTraces
|
|
167
|
+
traceWebsocketMessagesSeparateTraces,
|
|
168
|
+
experimental
|
|
152
169
|
} = this._tracerConfig
|
|
153
170
|
|
|
154
171
|
const sharedConfig = {
|
|
@@ -166,7 +183,8 @@ module.exports = class PluginManager {
|
|
|
166
183
|
isServiceUserProvided,
|
|
167
184
|
traceWebsocketMessagesEnabled,
|
|
168
185
|
traceWebsocketMessagesInheritSampling,
|
|
169
|
-
traceWebsocketMessagesSeparateTraces
|
|
186
|
+
traceWebsocketMessagesSeparateTraces,
|
|
187
|
+
experimental
|
|
170
188
|
}
|
|
171
189
|
|
|
172
190
|
if (logInjection !== undefined) {
|