dd-trace 6.9.0 → 6.11.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/README.md +0 -17
- package/ci/vitest-no-worker-init-setup.mjs +112 -10
- package/index.d.ts +150 -3
- package/initialize.mjs +28 -17
- package/openfeature.js +2 -2
- package/package.json +14 -10
- package/packages/datadog-esbuild/index.js +0 -34
- package/packages/datadog-instrumentations/src/anthropic.js +210 -15
- package/packages/datadog-instrumentations/src/aws-sdk.js +9 -1
- package/packages/datadog-instrumentations/src/browser-bunyan.js +11 -0
- package/packages/datadog-instrumentations/src/bunyan.js +3 -16
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +111 -6
- package/packages/datadog-instrumentations/src/cucumber.js +26 -11
- package/packages/datadog-instrumentations/src/cypress-config.js +182 -16
- package/packages/datadog-instrumentations/src/cypress-legacy-finalizers.js +30 -0
- package/packages/datadog-instrumentations/src/cypress.js +2 -0
- package/packages/datadog-instrumentations/src/fastify.js +2 -0
- package/packages/datadog-instrumentations/src/helpers/bunyan.js +22 -0
- package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/pool-acquire.js +634 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +10 -8
- package/packages/datadog-instrumentations/src/helpers/rewriter/index.js +2 -1
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/webdriverio.js +81 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/targets.json +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +83 -1
- package/packages/datadog-instrumentations/src/jest.js +26 -18
- package/packages/datadog-instrumentations/src/mariadb.js +278 -21
- package/packages/datadog-instrumentations/src/mocha/main.js +540 -56
- package/packages/datadog-instrumentations/src/mocha/utils.js +132 -25
- package/packages/datadog-instrumentations/src/mysql.js +45 -15
- package/packages/datadog-instrumentations/src/mysql2.js +119 -18
- package/packages/datadog-instrumentations/src/path-to-regexp.js +67 -1
- package/packages/datadog-instrumentations/src/pg.js +116 -92
- package/packages/datadog-instrumentations/src/playwright-reporter.js +99 -0
- package/packages/datadog-instrumentations/src/playwright.js +149 -2
- package/packages/datadog-instrumentations/src/router.js +2 -0
- package/packages/datadog-instrumentations/src/vitest-main-no-worker-init.js +43 -4
- package/packages/datadog-instrumentations/src/vitest-main.js +180 -20
- package/packages/datadog-instrumentations/src/vitest-util.js +64 -5
- package/packages/datadog-instrumentations/src/vitest-worker.js +150 -25
- package/packages/datadog-instrumentations/src/webdriverio.js +31 -17
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +12 -6
- package/packages/datadog-plugin-aws-sdk/src/base.js +1 -0
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +163 -44
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +4 -13
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -5
- package/packages/datadog-plugin-azure-functions/src/index.js +1 -1
- package/packages/datadog-plugin-browser-bunyan/src/index.js +9 -0
- package/packages/datadog-plugin-bunyan/src/index.js +5 -8
- package/packages/datadog-plugin-cucumber/src/index.js +11 -0
- package/packages/datadog-plugin-cypress/src/after-run.js +5 -1
- package/packages/datadog-plugin-cypress/src/after-spec.js +5 -1
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +82 -30
- package/packages/datadog-plugin-cypress/src/finalization.js +76 -0
- package/packages/datadog-plugin-cypress/src/index.js +12 -6
- package/packages/datadog-plugin-cypress/src/plugin.js +16 -3
- package/packages/datadog-plugin-dd-trace-api/src/index.js +4 -0
- package/packages/datadog-plugin-electron/src/index.js +2 -0
- package/packages/datadog-plugin-fs/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +31 -17
- package/packages/datadog-plugin-jest/src/index.js +11 -4
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -3
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -2
- package/packages/datadog-plugin-kafkajs/src/utils.js +65 -7
- package/packages/datadog-plugin-mocha/src/index.js +606 -40
- package/packages/datadog-plugin-mysql/src/index.js +37 -0
- package/packages/datadog-plugin-nats/src/index.js +1 -1
- package/packages/datadog-plugin-next/src/index.js +1 -19
- package/packages/datadog-plugin-openai/src/tracing.js +41 -30
- package/packages/datadog-plugin-openai-agents/src/integration.js +279 -69
- package/packages/datadog-plugin-openai-agents/src/processor.js +16 -4
- package/packages/datadog-plugin-pg/src/index.js +1 -0
- package/packages/datadog-plugin-playwright/src/index.js +42 -13
- package/packages/datadog-plugin-vitest/src/index.js +14 -20
- package/packages/datadog-plugin-ws/src/util.js +2 -1
- package/packages/datadog-webpack/index.js +0 -11
- package/packages/dd-trace/index.js +0 -1
- package/packages/dd-trace/src/agent/info.js +6 -5
- package/packages/dd-trace/src/aiguard/client.js +100 -1
- package/packages/dd-trace/src/aiguard/errors.js +41 -0
- package/packages/dd-trace/src/aiguard/evaluation.js +357 -0
- package/packages/dd-trace/src/aiguard/integrations/anthropic.js +70 -0
- package/packages/dd-trace/src/aiguard/integrations/index.js +4 -0
- package/packages/dd-trace/src/aiguard/messages/anthropic.js +423 -0
- package/packages/dd-trace/src/aiguard/messages/openai.js +1 -24
- package/packages/dd-trace/src/aiguard/messages/utils.js +28 -0
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +1 -11
- package/packages/dd-trace/src/aiguard/sdk.js +22 -278
- package/packages/dd-trace/src/appsec/api_security/normalized-route.js +453 -0
- package/packages/dd-trace/src/appsec/handlers/http-request.js +13 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +9 -12
- package/packages/dd-trace/src/carrier.js +356 -0
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/worker/index.js +1 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agent-proxy/index.js +27 -3
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +21 -5
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/request-tracker.js +164 -0
- package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +22 -6
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +365 -32
- package/packages/dd-trace/src/ci-visibility/exporters/request.js +201 -0
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +5 -3
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/writer.js +9 -5
- package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -1
- package/packages/dd-trace/src/ci-visibility/requests/rate-limit.js +39 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +3 -6
- package/packages/dd-trace/src/ci-visibility/requests/upload-test-screenshot.js +6 -2
- package/packages/dd-trace/src/config/generated-config-types.d.ts +7 -0
- package/packages/dd-trace/src/config/index.js +13 -2
- package/packages/dd-trace/src/config/major-overrides.js +7 -0
- package/packages/dd-trace/src/config/supported-configurations.json +24 -0
- package/packages/dd-trace/src/datastreams/context.js +6 -1
- package/packages/dd-trace/src/datastreams/index.js +2 -0
- package/packages/dd-trace/src/datastreams/manager.js +14 -3
- package/packages/dd-trace/src/datastreams/pathway.js +23 -22
- package/packages/dd-trace/src/datastreams/processor.js +16 -13
- package/packages/dd-trace/src/datastreams/size.js +5 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +3 -2
- package/packages/dd-trace/src/exporters/agent/writer.js +49 -9
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +6 -4
- package/packages/dd-trace/src/exporters/common/writer.js +11 -6
- package/packages/dd-trace/src/llmobs/constants/tags.js +5 -0
- package/packages/dd-trace/src/llmobs/experiments/client.js +163 -5
- package/packages/dd-trace/src/llmobs/experiments/dataset.js +241 -87
- package/packages/dd-trace/src/llmobs/experiments/experiment.js +280 -20
- package/packages/dd-trace/src/llmobs/experiments/index.js +58 -59
- package/packages/dd-trace/src/llmobs/experiments/noop.js +71 -3
- package/packages/dd-trace/src/llmobs/experiments/result.js +1 -0
- package/packages/dd-trace/src/llmobs/experiments/util.js +41 -5
- package/packages/dd-trace/src/llmobs/index.js +34 -2
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +12 -3
- package/packages/dd-trace/src/llmobs/plugins/base.js +4 -2
- package/packages/dd-trace/src/llmobs/span_processor.js +16 -0
- package/packages/dd-trace/src/llmobs/tagger.js +96 -0
- package/packages/dd-trace/src/llmobs/util.js +78 -0
- package/packages/dd-trace/src/noop/proxy.js +3 -4
- package/packages/dd-trace/src/openfeature/flagging_provider.js +18 -2
- package/packages/dd-trace/src/openfeature/remote_config.js +1 -1
- package/packages/dd-trace/src/opentelemetry/context_manager.js +7 -7
- package/packages/dd-trace/src/opentelemetry/logs/batch_log_processor.js +2 -1
- package/packages/dd-trace/src/opentelemetry/logs/logger.js +67 -11
- package/packages/dd-trace/src/opentelemetry/logs/otlp_transformer.js +14 -3
- package/packages/dd-trace/src/opentelemetry/metrics/index.js +25 -12
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_exporter.js +2 -5
- package/packages/dd-trace/src/opentelemetry/metrics/otlp_span_stats_transformer.js +96 -43
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +126 -120
- package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +4 -8
- package/packages/dd-trace/src/opentracing/tracer.js +5 -2
- package/packages/dd-trace/src/otel-thread-ctx.js +387 -0
- package/packages/dd-trace/src/plugin_manager.js +5 -3
- package/packages/dd-trace/src/plugins/ci_plugin.js +6 -1
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/{datadog-plugin-jest/src/util.js → dd-trace/src/plugins/util/jest.js} +5 -65
- package/packages/dd-trace/src/plugins/util/test.js +93 -14
- package/packages/dd-trace/src/plugins/util/web.js +56 -2
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/space.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +37 -90
- package/packages/dd-trace/src/profiling/webspan-utils.js +45 -0
- package/packages/dd-trace/src/proxy.js +38 -29
- package/packages/dd-trace/src/ritm.js +9 -2
- package/packages/dd-trace/src/serverless.js +37 -0
- package/packages/dd-trace/src/span_format.js +1 -0
- package/packages/dd-trace/src/span_stats.js +30 -3
- package/packages/dd-trace/src/storage-channels.js +86 -0
- package/packages/dd-trace/src/tracer.js +9 -2
- package/packages/dd-trace/src/tracer_metadata.js +14 -1
- package/packages/dd-trace/src/web-tags-cache.js +132 -0
- package/vendor/dist/@datadog/openfeature-node-server/LICENSE +201 -0
- package/vendor/dist/@datadog/openfeature-node-server/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +0 -65
- package/packages/datadog-webpack/src/optional-peer-loader.js +0 -17
- package/packages/dd-trace/src/feature-registry.js +0 -29
- package/packages/dd-trace/src/openfeature/register.js +0 -35
- package/packages/dd-trace/src/openfeature/require-provider.js +0 -18
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const NoopProxy = require('./noop/proxy')
|
|
4
|
-
const { features } = require('./feature-registry')
|
|
5
4
|
const DatadogTracer = require('./tracer')
|
|
6
5
|
const getConfig = require('./config')
|
|
7
6
|
const { getEnvironmentVariable } = require('./config/helper')
|
|
@@ -38,9 +37,9 @@ const OFFLINE_VALIDATION_EXPORTERS = new Set([
|
|
|
38
37
|
'playwright_worker',
|
|
39
38
|
'vitest_worker',
|
|
40
39
|
])
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
40
|
+
const OPENFEATURE_STATE_NOOP = 0
|
|
41
|
+
const OPENFEATURE_STATE_LAZY = 1
|
|
42
|
+
const OPENFEATURE_STATE_ACTIVE = 2
|
|
44
43
|
|
|
45
44
|
class LazyModule {
|
|
46
45
|
constructor (provider) {
|
|
@@ -91,8 +90,7 @@ function defineLazily (obj, property, getClass, ...args) {
|
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
class Tracer extends NoopProxy {
|
|
94
|
-
|
|
95
|
-
#featureStates
|
|
93
|
+
#openfeatureState = OPENFEATURE_STATE_NOOP
|
|
96
94
|
|
|
97
95
|
constructor () {
|
|
98
96
|
super()
|
|
@@ -115,12 +113,9 @@ class Tracer extends NoopProxy {
|
|
|
115
113
|
aiguard: new LazyModule(() => require('./aiguard')),
|
|
116
114
|
iast: new LazyModule(() => require('./appsec/iast')),
|
|
117
115
|
llmobs: new LazyModule(() => require('./llmobs')),
|
|
116
|
+
openfeature: new LazyModule(() => require('./openfeature')),
|
|
118
117
|
rewriter: new LazyModule(() => require('./appsec/iast/taint-tracking/rewriter')),
|
|
119
118
|
}
|
|
120
|
-
|
|
121
|
-
for (const feature of Object.values(features)) {
|
|
122
|
-
this._modules[feature.name] = new LazyModule(feature.factory)
|
|
123
|
-
}
|
|
124
119
|
}
|
|
125
120
|
|
|
126
121
|
/**
|
|
@@ -213,9 +208,10 @@ class Tracer extends NoopProxy {
|
|
|
213
208
|
DynamicInstrumentation.start(config, rc)
|
|
214
209
|
}
|
|
215
210
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
211
|
+
const openfeatureRemoteConfig = require('./openfeature/remote_config')
|
|
212
|
+
const subscribeOpenfeatureToRemoteConfig = config.featureFlags.DD_FEATURE_FLAGS_ENABLED &&
|
|
213
|
+
config.featureFlags.DD_FEATURE_FLAGS_CONFIGURATION_SOURCE === 'remote_config'
|
|
214
|
+
openfeatureRemoteConfig.enable(rc, () => this.openfeature, subscribeOpenfeatureToRemoteConfig)
|
|
219
215
|
}
|
|
220
216
|
|
|
221
217
|
if (config.profiling.DD_PROFILING_ENABLED === 'true') {
|
|
@@ -233,6 +229,17 @@ class Tracer extends NoopProxy {
|
|
|
233
229
|
}
|
|
234
230
|
}
|
|
235
231
|
|
|
232
|
+
// Experimental: mirror the active trace ID, span ID and endpoint into
|
|
233
|
+
// an OTEP-4947 thread-local context record an out-of-process eBPF
|
|
234
|
+
// reader can consume.
|
|
235
|
+
if (config.DD_TRACE_OTEL_CTX_ENABLED) {
|
|
236
|
+
try {
|
|
237
|
+
require('./otel-thread-ctx').start()
|
|
238
|
+
} catch (e) {
|
|
239
|
+
log.error('Error starting OTEP-4947 thread context writer', e)
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
236
243
|
// OTel logs/metrics pipelines must be initialized BEFORE runtimeMetrics.start so that
|
|
237
244
|
// when the OTLP runtime metrics module calls metrics.getMeterProvider(), it gets the
|
|
238
245
|
// real provider, otherwise instruments register on the noop provider and never export.
|
|
@@ -305,28 +312,32 @@ class Tracer extends NoopProxy {
|
|
|
305
312
|
}
|
|
306
313
|
|
|
307
314
|
/**
|
|
308
|
-
*
|
|
315
|
+
* `tracer.openfeature` is only reachable through this proxy. SSI itself (auto-injecting
|
|
316
|
+
* the tracer, resolving the vendored provider regardless of the customer's own
|
|
317
|
+
* `node_modules` layout) is unaffected -- that is what this PR fixes. The remaining gap is
|
|
318
|
+
* narrower: there is no `dd-trace-api` handoff for `openfeature` yet (see
|
|
319
|
+
* `packages/datadog-plugin-dd-trace-api`), so an application that calls into the tracer
|
|
320
|
+
* exclusively through the `dd-trace-api` shim -- instead of `require('dd-trace')` -- cannot
|
|
321
|
+
* reach the flagging provider through that shim.
|
|
322
|
+
*
|
|
309
323
|
* @param {import('./config/config-base')} config
|
|
310
324
|
*/
|
|
311
|
-
#
|
|
312
|
-
|
|
313
|
-
|
|
325
|
+
#enableOpenfeature (config) {
|
|
326
|
+
if (this.#openfeatureState !== OPENFEATURE_STATE_NOOP) return
|
|
327
|
+
this.#openfeatureState = OPENFEATURE_STATE_LAZY
|
|
314
328
|
|
|
315
|
-
|
|
316
|
-
states[feature.name] = FEATURE_STATE_LAZY
|
|
317
|
-
|
|
318
|
-
Reflect.defineProperty(this, feature.name, {
|
|
329
|
+
Reflect.defineProperty(this, 'openfeature', {
|
|
319
330
|
get: () => {
|
|
320
|
-
const
|
|
321
|
-
const provider = new
|
|
331
|
+
const FlaggingProvider = require('./openfeature/flagging_provider')
|
|
332
|
+
const provider = new FlaggingProvider(this._tracer, config)
|
|
322
333
|
|
|
323
|
-
this._modules
|
|
324
|
-
Reflect.defineProperty(this,
|
|
334
|
+
this._modules.openfeature.enable(config)
|
|
335
|
+
Reflect.defineProperty(this, 'openfeature', {
|
|
325
336
|
value: provider,
|
|
326
337
|
configurable: true,
|
|
327
338
|
enumerable: true,
|
|
328
339
|
})
|
|
329
|
-
|
|
340
|
+
this.#openfeatureState = OPENFEATURE_STATE_ACTIVE
|
|
330
341
|
return provider
|
|
331
342
|
},
|
|
332
343
|
configurable: true,
|
|
@@ -373,9 +384,7 @@ class Tracer extends NoopProxy {
|
|
|
373
384
|
this._modules.llmobs.disable()
|
|
374
385
|
}
|
|
375
386
|
|
|
376
|
-
|
|
377
|
-
if (feature.isEnabled(config)) this.#enableFeature(feature, config)
|
|
378
|
-
}
|
|
387
|
+
if (config.featureFlags.DD_FEATURE_FLAGS_ENABLED) this.#enableOpenfeature(config)
|
|
379
388
|
|
|
380
389
|
if (this._tracingInitialized) {
|
|
381
390
|
this._tracer.configure(config)
|
|
@@ -20,6 +20,7 @@ const origRequire = Module.prototype.require
|
|
|
20
20
|
module.exports = Hook
|
|
21
21
|
|
|
22
22
|
let moduleHooks = Object.create(null)
|
|
23
|
+
let hookedModuleCount = 0
|
|
23
24
|
let cache = Object.create(null)
|
|
24
25
|
let patching = Object.create(null)
|
|
25
26
|
let patchedRequire = null
|
|
@@ -64,6 +65,7 @@ function Hook (modules, options, onrequire) {
|
|
|
64
65
|
hooks.push(onrequire)
|
|
65
66
|
} else {
|
|
66
67
|
moduleHooks[mod] = [onrequire]
|
|
68
|
+
hookedModuleCount++
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
71
|
}
|
|
@@ -205,6 +207,7 @@ Hook.reset = function () {
|
|
|
205
207
|
patching = Object.create(null)
|
|
206
208
|
cache = Object.create(null)
|
|
207
209
|
moduleHooks = Object.create(null)
|
|
210
|
+
hookedModuleCount = 0
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
function findProjectRoot (startDir) {
|
|
@@ -221,16 +224,20 @@ function findProjectRoot (startDir) {
|
|
|
221
224
|
|
|
222
225
|
Hook.prototype.unhook = function () {
|
|
223
226
|
for (const mod of this.modules) {
|
|
224
|
-
const
|
|
227
|
+
const registeredHooks = moduleHooks[mod]
|
|
228
|
+
if (registeredHooks === undefined) continue
|
|
229
|
+
|
|
230
|
+
const hooks = registeredHooks.filter(hook => hook !== this.onrequire)
|
|
225
231
|
|
|
226
232
|
if (hooks.length > 0) {
|
|
227
233
|
moduleHooks[mod] = hooks
|
|
228
234
|
} else {
|
|
229
235
|
delete moduleHooks[mod]
|
|
236
|
+
hookedModuleCount--
|
|
230
237
|
}
|
|
231
238
|
}
|
|
232
239
|
|
|
233
|
-
if (
|
|
240
|
+
if (hookedModuleCount === 0) {
|
|
234
241
|
Hook.reset()
|
|
235
242
|
}
|
|
236
243
|
}
|
|
@@ -42,7 +42,44 @@ function isInServerlessEnvironment () {
|
|
|
42
42
|
return inAWSLambda || isGCPFunction || isAzureFunction
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Gets tags describing the serverless platform where the tracer is running.
|
|
47
|
+
*
|
|
48
|
+
* @returns {string[]|undefined}
|
|
49
|
+
*/
|
|
50
|
+
function getServerlessPlatformTags () {
|
|
51
|
+
if (getEnvironmentVariable('VERCEL') === '1') {
|
|
52
|
+
return getVercelPlatformTags()
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @returns {string[]|undefined}
|
|
58
|
+
*/
|
|
59
|
+
function getVercelPlatformTags () {
|
|
60
|
+
let tags
|
|
61
|
+
const projectId = getEnvironmentVariable('VERCEL_PROJECT_ID')
|
|
62
|
+
if (projectId) {
|
|
63
|
+
tags = ['vercel.project_id', projectId]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const environment = getEnvironmentVariable('VERCEL_ENV')
|
|
67
|
+
if (environment) {
|
|
68
|
+
tags ??= []
|
|
69
|
+
tags.push('vercel.environment', environment)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const region = getEnvironmentVariable('VERCEL_REGION')
|
|
73
|
+
if (region) {
|
|
74
|
+
tags ??= []
|
|
75
|
+
tags.push('vercel.region', region)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return tags
|
|
79
|
+
}
|
|
80
|
+
|
|
45
81
|
module.exports = {
|
|
82
|
+
getServerlessPlatformTags,
|
|
46
83
|
getIsGCPFunction,
|
|
47
84
|
getIsAzureFunction,
|
|
48
85
|
enableGCPPubSubPushSubscription,
|
|
@@ -14,8 +14,10 @@ const {
|
|
|
14
14
|
GRPC_STATUS_CODE,
|
|
15
15
|
} = require('../../../ext/tags')
|
|
16
16
|
const { ORIGIN_KEY, TOP_LEVEL_KEY, SVC_SRC_KEY, GRPC_STATUS_NAMES } = require('./constants')
|
|
17
|
+
const id = require('./id')
|
|
17
18
|
|
|
18
19
|
const GRPC_STATUS_CODE_MAP = Object.fromEntries(GRPC_STATUS_NAMES.map((name, i) => [name, String(i)]))
|
|
20
|
+
const ZERO_ID = id('0')
|
|
19
21
|
const { version } = require('./pkg')
|
|
20
22
|
const processTags = require('./process-tags')
|
|
21
23
|
|
|
@@ -150,9 +152,24 @@ class SpanAggKey {
|
|
|
150
152
|
}
|
|
151
153
|
|
|
152
154
|
class SpanBuckets extends Map {
|
|
155
|
+
#includeTraceRoot
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @param {boolean} [includeTraceRoot]
|
|
159
|
+
*/
|
|
160
|
+
constructor (includeTraceRoot = false) {
|
|
161
|
+
super()
|
|
162
|
+
this.#includeTraceRoot = includeTraceRoot
|
|
163
|
+
}
|
|
164
|
+
|
|
153
165
|
forSpan (span) {
|
|
154
166
|
const aggKey = new SpanAggKey(span)
|
|
155
|
-
const
|
|
167
|
+
const baseKey = aggKey.toString()
|
|
168
|
+
const parentId = span.parent_id
|
|
169
|
+
if (this.#includeTraceRoot && parentId !== undefined && parentId !== null) {
|
|
170
|
+
aggKey.isTraceRoot = parentId.equals(ZERO_ID)
|
|
171
|
+
}
|
|
172
|
+
const key = this.#includeTraceRoot ? `${baseKey},${aggKey.isTraceRoot}` : baseKey
|
|
156
173
|
|
|
157
174
|
if (!this.has(key)) {
|
|
158
175
|
this.set(key, new SpanAggStats(aggKey))
|
|
@@ -163,9 +180,19 @@ class SpanBuckets extends Map {
|
|
|
163
180
|
}
|
|
164
181
|
|
|
165
182
|
class TimeBuckets extends Map {
|
|
183
|
+
#includeTraceRoot
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* @param {boolean} [includeTraceRoot]
|
|
187
|
+
*/
|
|
188
|
+
constructor (includeTraceRoot = false) {
|
|
189
|
+
super()
|
|
190
|
+
this.#includeTraceRoot = includeTraceRoot
|
|
191
|
+
}
|
|
192
|
+
|
|
166
193
|
forTime (time) {
|
|
167
194
|
if (!this.has(time)) {
|
|
168
|
-
this.set(time, new SpanBuckets())
|
|
195
|
+
this.set(time, new SpanBuckets(this.#includeTraceRoot))
|
|
169
196
|
}
|
|
170
197
|
|
|
171
198
|
return this.get(time)
|
|
@@ -192,7 +219,7 @@ class SpanStatsProcessor {
|
|
|
192
219
|
const intervalMs = otlpExporter ? (flushIntervalMs ?? 10_000) : interval * 1e3
|
|
193
220
|
this.interval = intervalMs / 1e3
|
|
194
221
|
this.bucketSizeNs = intervalMs * 1e6
|
|
195
|
-
this.buckets = new TimeBuckets()
|
|
222
|
+
this.buckets = new TimeBuckets(Boolean(otlpExporter))
|
|
196
223
|
this.hostname = os.hostname()
|
|
197
224
|
this.enabled = enabled
|
|
198
225
|
this.otlpExporter = otlpExporter || null
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const dc = require('dc-polyfill')
|
|
4
|
+
const { storage } = require('../../datadog-core')
|
|
5
|
+
|
|
6
|
+
// Channels that surface tracer-storage events to interested consumers
|
|
7
|
+
// (currently the wall profiler and the OTEP-4947 thread context writer).
|
|
8
|
+
//
|
|
9
|
+
// dd-trace:storage:enter — fires when the active legacy-storage store
|
|
10
|
+
// changes. Published by the shimmer installed in ensureChannelsActivated().
|
|
11
|
+
// dd-trace:storage:before — fires from an async_hooks "before" callback in
|
|
12
|
+
// non-AsyncContextFrame mode. Used by the wall profiler to refresh the
|
|
13
|
+
// sample context at the start of each async resource callback. Has no
|
|
14
|
+
// publisher in ACF mode.
|
|
15
|
+
// dd-trace:span:finish, dd-trace:span:tags:update — published by the
|
|
16
|
+
// tracer core (opentracing/span.js). Re-exported here as a convenience
|
|
17
|
+
// so consumers have a single import path for storage-related channels.
|
|
18
|
+
const enterCh = dc.channel('dd-trace:storage:enter')
|
|
19
|
+
const beforeCh = dc.channel('dd-trace:storage:before')
|
|
20
|
+
const spanFinishCh = dc.channel('dd-trace:span:finish')
|
|
21
|
+
const tagsUpdateCh = dc.channel('dd-trace:span:tags:update')
|
|
22
|
+
|
|
23
|
+
function getActiveSpan () {
|
|
24
|
+
const store = storage('legacy').getStore()
|
|
25
|
+
return store && store.span
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let channelsActivated = false
|
|
29
|
+
// Idempotent. The asyncContextFrameEnabled argument from the first caller
|
|
30
|
+
// wins; subsequent calls are no-ops regardless of their argument. In
|
|
31
|
+
// practice all callers observe the same global ACF state.
|
|
32
|
+
function ensureChannelsActivated (asyncContextFrameEnabled) {
|
|
33
|
+
if (channelsActivated) return
|
|
34
|
+
|
|
35
|
+
const shimmer = require('../../datadog-shimmer')
|
|
36
|
+
|
|
37
|
+
// We need to instrument enterWith() on the legacy storage — that's the storage
|
|
38
|
+
// carrying span data and the only one consumers of these channels care about.
|
|
39
|
+
const legacyStorage = storage('legacy')
|
|
40
|
+
let inRun = false
|
|
41
|
+
shimmer.wrap(legacyStorage, 'enterWith', function (original) {
|
|
42
|
+
return function (store) {
|
|
43
|
+
const retVal = original.call(this, store)
|
|
44
|
+
if (!inRun) enterCh.publish()
|
|
45
|
+
return retVal
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
// When not using AsyncContextFrame, we need additional instrumentation.
|
|
50
|
+
if (!asyncContextFrameEnabled) {
|
|
51
|
+
// We need async_hooks.createHook to create a "before" callback.
|
|
52
|
+
const { createHook } = require('async_hooks')
|
|
53
|
+
createHook({ before: () => beforeCh.publish() }).enable()
|
|
54
|
+
|
|
55
|
+
// In ACF-based implementation run() delegates to enterWith() so it doesn't
|
|
56
|
+
// need to be separately instrumented. in non-ACF implementation run()
|
|
57
|
+
// doesn't delegate to enterWith(), so separate instrumentation is necessary.
|
|
58
|
+
shimmer.wrap(legacyStorage, 'run', function (original) {
|
|
59
|
+
return function (store, callback, ...args) {
|
|
60
|
+
const wrappedCb = shimmer.wrapFunction(callback, cb => function (...args) {
|
|
61
|
+
inRun = false
|
|
62
|
+
enterCh.publish()
|
|
63
|
+
const retVal = cb.apply(this, args)
|
|
64
|
+
inRun = true
|
|
65
|
+
return retVal
|
|
66
|
+
})
|
|
67
|
+
inRun = true
|
|
68
|
+
const retVal = original.call(this, store, wrappedCb, ...args)
|
|
69
|
+
enterCh.publish()
|
|
70
|
+
inRun = false
|
|
71
|
+
return retVal
|
|
72
|
+
}
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
channelsActivated = true
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = {
|
|
80
|
+
enterCh,
|
|
81
|
+
beforeCh,
|
|
82
|
+
spanFinishCh,
|
|
83
|
+
tagsUpdateCh,
|
|
84
|
+
getActiveSpan,
|
|
85
|
+
ensureChannelsActivated,
|
|
86
|
+
}
|
|
@@ -59,8 +59,15 @@ class DatadogTracer extends Tracer {
|
|
|
59
59
|
|
|
60
60
|
// todo[piochelepiotr] These two methods are not related to the tracer, but to data streams monitoring.
|
|
61
61
|
// They should be moved outside of the tracer in the future.
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
/**
|
|
63
|
+
* @param {string[]} edgeTags
|
|
64
|
+
* @param {import('./opentracing/span')|null} span
|
|
65
|
+
* @param {number} [payloadSize]
|
|
66
|
+
* @param {number} [pathwayContextSize] See `DataStreamsProcessor#setCheckpoint`.
|
|
67
|
+
* @returns {object|undefined}
|
|
68
|
+
*/
|
|
69
|
+
setCheckpoint (edgeTags, span, payloadSize = 0, pathwayContextSize) {
|
|
70
|
+
return this._dataStreamsManager.setCheckpoint(edgeTags, span, payloadSize, pathwayContextSize)
|
|
64
71
|
}
|
|
65
72
|
|
|
66
73
|
decodeDataStreamsContext (carrier) {
|
|
@@ -18,6 +18,18 @@ function storeConfig (config) {
|
|
|
18
18
|
? (processTags.serialized || null)
|
|
19
19
|
: null
|
|
20
20
|
|
|
21
|
+
// OTEP-4947 thread-context writer metadata, published as part of the
|
|
22
|
+
// OTel process context so an out-of-process reader can decode the
|
|
23
|
+
// on-wire record: the attribute key map (libdatadog prepends the
|
|
24
|
+
// implicit `datadog.local_root_span_id` at wire index 0, so we only
|
|
25
|
+
// supply our own additional keys), the schema-version string, and
|
|
26
|
+
// the V8 layout constants the reader needs. Gated on the same config
|
|
27
|
+
// flag that activates the writer; undefined when off or when
|
|
28
|
+
// @datadog/pprof isn't installed to provide the values.
|
|
29
|
+
const threadlocalMetadata = config.DD_TRACE_OTEL_CTX_ENABLED
|
|
30
|
+
? require('./otel-thread-ctx').getThreadLocalMetadata()
|
|
31
|
+
: undefined
|
|
32
|
+
|
|
21
33
|
const metadata = new processDiscovery.TracerMetadata(
|
|
22
34
|
config.tags['runtime-id'],
|
|
23
35
|
tracerVersion,
|
|
@@ -26,7 +38,8 @@ function storeConfig (config) {
|
|
|
26
38
|
config.env || null,
|
|
27
39
|
config.version || null,
|
|
28
40
|
processTagsSerialized,
|
|
29
|
-
containerId || null
|
|
41
|
+
containerId || null,
|
|
42
|
+
threadlocalMetadata
|
|
30
43
|
)
|
|
31
44
|
|
|
32
45
|
return processDiscovery.storeMetadata(metadata)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Per-span cache of "which tag bag from the started-spans chain identifies
|
|
4
|
+
// this span (or its nearest web-server ancestor) as a web-server span?"
|
|
5
|
+
// Populated lazily on first `getCachedWebTags(span)`, refreshed
|
|
6
|
+
// automatically when a `dd-trace:span:tags:update` event promotes a
|
|
7
|
+
// previously-empty answer for that span into a real value.
|
|
8
|
+
//
|
|
9
|
+
// Used by the wall profiler (endpoint-collection label on samples) and by
|
|
10
|
+
// the OTEP-4947 thread-context writer (endpoint attribute in the record);
|
|
11
|
+
// having a single cache means the parent-chain walk happens once per span
|
|
12
|
+
// no matter how many consumers ask.
|
|
13
|
+
//
|
|
14
|
+
// Consumers that want to react to late web-server-span discovery
|
|
15
|
+
// subscribe to `resolvedCh` — a diagnostics channel we publish on once
|
|
16
|
+
// per span at the moment its cached webTags transitions from undefined
|
|
17
|
+
// to a real value. Doing it via a channel (rather than exposing a
|
|
18
|
+
// stateful "did the transition happen?" query) means each consumer sees
|
|
19
|
+
// every transition exactly once, regardless of subscription order or
|
|
20
|
+
// how many other consumers are attached.
|
|
21
|
+
//
|
|
22
|
+
// `endpointResolvedCh` is the same idea one field over: published once per
|
|
23
|
+
// web-server span at the moment its endpoint name settles (see finalEndpoint in
|
|
24
|
+
// profiling/webspan-utils.js), i.e. when routing tags stop being interim
|
|
25
|
+
// placeholders. Consumers that must materialize the endpoint eagerly rather
|
|
26
|
+
// than read the tag bag at leisure need that moment; owning it here means the
|
|
27
|
+
// one `dd-trace:span:tags:update` subscription this module already holds serves
|
|
28
|
+
// them too, instead of each consumer adding its own subscriber to that hot
|
|
29
|
+
// channel and re-deriving finality itself.
|
|
30
|
+
//
|
|
31
|
+
// The module-level `dd-trace:span:tags:update` subscription that drives
|
|
32
|
+
// the transition promotion is installed lazily via `activate()` /
|
|
33
|
+
// `deactivate()`, ref-counted across consumers. When no consumer has
|
|
34
|
+
// activated the cache, `dd-trace:span:tags:update` stays subscriber-free
|
|
35
|
+
// so `DatadogSpan#setTag` / `addTags` skip the publish path entirely.
|
|
36
|
+
// Consumers MUST balance every activate() call with a matching
|
|
37
|
+
// deactivate() when they stop caring.
|
|
38
|
+
|
|
39
|
+
const dc = require('dc-polyfill')
|
|
40
|
+
const { finalEndpoint, isWebServerSpan, getStartedSpans } = require('./profiling/webspan-utils')
|
|
41
|
+
|
|
42
|
+
// Fields on the cache entry:
|
|
43
|
+
// resolved: true once the parent-chain walk has run.
|
|
44
|
+
// webTags: the resolved tag bag, or undefined when the walk came up
|
|
45
|
+
// empty (no web-server span found in the started-spans chain).
|
|
46
|
+
// endpointFinal: true once this span is a web-server span whose endpoint name
|
|
47
|
+
// has settled and endpointResolvedCh has been published for it.
|
|
48
|
+
const CachedSym = Symbol('WebTagsCache')
|
|
49
|
+
|
|
50
|
+
const tagsUpdateCh = dc.channel('dd-trace:span:tags:update')
|
|
51
|
+
const resolvedCh = dc.channel('dd-trace:web-tags:resolved')
|
|
52
|
+
const endpointResolvedCh = dc.channel('dd-trace:web-tags:endpoint-resolved')
|
|
53
|
+
|
|
54
|
+
function getCache (span) {
|
|
55
|
+
let cached = span[CachedSym]
|
|
56
|
+
if (cached === undefined) {
|
|
57
|
+
cached = {}
|
|
58
|
+
span[CachedSym] = cached
|
|
59
|
+
}
|
|
60
|
+
return cached
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Returns the web-server tag bag for this span or its nearest web-server
|
|
64
|
+
// ancestor in the started-spans chain, or undefined if none is a
|
|
65
|
+
// web-server span. Lazy: walks the parent chain on the first call, caches
|
|
66
|
+
// the result on the span.
|
|
67
|
+
function getCachedWebTags (span) {
|
|
68
|
+
const cached = getCache(span)
|
|
69
|
+
if (cached.resolved) return cached.webTags
|
|
70
|
+
const spanContext = span.context()
|
|
71
|
+
const tags = spanContext.getTags()
|
|
72
|
+
let webTags
|
|
73
|
+
if (isWebServerSpan(tags)) {
|
|
74
|
+
webTags = tags
|
|
75
|
+
} else {
|
|
76
|
+
const parentId = spanContext._parentId
|
|
77
|
+
const startedSpans = getStartedSpans(spanContext)
|
|
78
|
+
for (let i = startedSpans.length; --i >= 0;) {
|
|
79
|
+
const ispan = startedSpans[i]
|
|
80
|
+
if (ispan.context()._spanId === parentId) {
|
|
81
|
+
webTags = getCachedWebTags(ispan)
|
|
82
|
+
break
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
cached.webTags = webTags
|
|
87
|
+
cached.resolved = true
|
|
88
|
+
return webTags
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Own the tagsUpdate → transition promotion here. The dc subscribe
|
|
92
|
+
// happens lazily via activate(); each active consumer bumps a refcount,
|
|
93
|
+
// the last deactivate() removes the subscription. When idle, this module
|
|
94
|
+
// contributes no subscribers to `dd-trace:span:tags:update`, so
|
|
95
|
+
// `DatadogSpan#setTag` / `addTags` never enter the publish path on our
|
|
96
|
+
// behalf.
|
|
97
|
+
function onTagsUpdate (span) {
|
|
98
|
+
const cached = span[CachedSym]
|
|
99
|
+
if (cached === undefined || !cached.resolved) return
|
|
100
|
+
const tags = span.context().getTags()
|
|
101
|
+
if (cached.webTags === undefined) {
|
|
102
|
+
if (!isWebServerSpan(tags)) return
|
|
103
|
+
cached.webTags = tags
|
|
104
|
+
resolvedCh.publish(span)
|
|
105
|
+
}
|
|
106
|
+
// Endpoint finality is a property of the web-server span itself: for a
|
|
107
|
+
// descendant, cached.webTags is an ancestor's bag rather than these tags, and
|
|
108
|
+
// the ancestor's own update is what settles the endpoint. Skipped entirely
|
|
109
|
+
// when nobody is listening, keeping this the same early return it used to be
|
|
110
|
+
// for consumers that only care about web-tag discovery.
|
|
111
|
+
if (!endpointResolvedCh.hasSubscribers || cached.endpointFinal || cached.webTags !== tags) return
|
|
112
|
+
if (finalEndpoint(tags) === undefined) return
|
|
113
|
+
cached.endpointFinal = true
|
|
114
|
+
endpointResolvedCh.publish(span)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
let activeCount = 0
|
|
118
|
+
|
|
119
|
+
function activate () {
|
|
120
|
+
if (activeCount++ === 0) {
|
|
121
|
+
tagsUpdateCh.subscribe(onTagsUpdate)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function deactivate () {
|
|
126
|
+
if (activeCount === 0) return
|
|
127
|
+
if (--activeCount === 0) {
|
|
128
|
+
tagsUpdateCh.unsubscribe(onTagsUpdate)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
module.exports = { getCachedWebTags, resolvedCh, endpointResolvedCh, activate, deactivate }
|