dd-trace 5.108.0 → 5.110.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/ci/init.js +4 -3
- package/index.d.ts +88 -25
- package/loader-hook.mjs +88 -2
- package/package.json +19 -14
- package/packages/datadog-esbuild/index.js +26 -0
- package/packages/datadog-esbuild/src/utils.js +46 -3
- package/packages/datadog-instrumentations/src/ai.js +43 -48
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js-context-methods.js +18 -0
- package/packages/datadog-instrumentations/src/aws-durable-execution-sdk-js.js +111 -0
- package/packages/datadog-instrumentations/src/aws-sdk.js +3 -1
- package/packages/datadog-instrumentations/src/connect.js +4 -3
- package/packages/datadog-instrumentations/src/electron.js +1 -1
- package/packages/datadog-instrumentations/src/fastify.js +4 -12
- package/packages/datadog-instrumentations/src/graphql.js +17 -6
- package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +81 -8
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +27 -2
- package/packages/datadog-instrumentations/src/helpers/optional-peer-bundler.js +65 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +6 -4
- package/packages/datadog-instrumentations/src/helpers/require-optional-peer.js +17 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/aws-durable-execution-sdk-js.js +31 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/rewriter/loader.mjs +18 -2
- package/packages/datadog-instrumentations/src/http/client.js +12 -2
- package/packages/datadog-instrumentations/src/ioredis.js +0 -1
- package/packages/datadog-instrumentations/src/iovalkey.js +1 -2
- package/packages/datadog-instrumentations/src/koa.js +3 -2
- package/packages/datadog-instrumentations/src/mariadb.js +4 -2
- package/packages/datadog-instrumentations/src/mocha/main.js +3 -3
- package/packages/datadog-instrumentations/src/next.js +44 -10
- package/packages/datadog-instrumentations/src/openai.js +77 -18
- package/packages/datadog-instrumentations/src/otel-sdk-trace.js +7 -6
- package/packages/datadog-instrumentations/src/playwright.js +1 -1
- package/packages/datadog-instrumentations/src/redis.js +0 -1
- package/packages/datadog-instrumentations/src/restify.js +4 -3
- package/packages/datadog-instrumentations/src/router.js +18 -5
- package/packages/datadog-instrumentations/src/selenium.js +1 -2
- package/packages/datadog-instrumentations/src/tedious.js +28 -0
- package/packages/datadog-instrumentations/src/vitest.js +323 -7
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/checkpoint.js +31 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/client.js +55 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/context.js +114 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/handler.js +128 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/index.js +19 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/trace-checkpoint.js +224 -0
- package/packages/datadog-plugin-aws-durable-execution-sdk-js/src/util.js +43 -0
- package/packages/datadog-plugin-aws-sdk/src/base.js +14 -16
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +43 -6
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +100 -37
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +108 -99
- package/packages/datadog-plugin-bullmq/src/filter.js +35 -0
- package/packages/datadog-plugin-bullmq/src/producer.js +84 -4
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +9 -1
- package/packages/datadog-plugin-fs/src/index.js +1 -0
- package/packages/datadog-plugin-http/src/client.js +8 -3
- package/packages/datadog-plugin-http2/src/client.js +5 -2
- package/packages/datadog-plugin-mysql/src/index.js +7 -2
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +2 -2
- package/packages/datadog-plugin-redis/src/index.js +1 -2
- package/packages/datadog-plugin-undici/src/index.js +5 -2
- package/packages/datadog-plugin-vitest/src/index.js +11 -2
- package/packages/datadog-webpack/index.js +17 -1
- package/packages/datadog-webpack/src/optional-peer-loader.js +17 -0
- package/packages/dd-trace/src/aiguard/channels.js +0 -1
- package/packages/dd-trace/src/aiguard/index.js +11 -49
- package/packages/dd-trace/src/aiguard/integrations/evaluate.js +46 -0
- package/packages/dd-trace/src/aiguard/integrations/openai.js +66 -0
- package/packages/dd-trace/src/aiguard/integrations/vercel-ai.js +78 -0
- package/packages/{datadog-instrumentations/src/helpers/ai-messages.js → dd-trace/src/aiguard/messages/openai.js} +85 -193
- package/packages/dd-trace/src/aiguard/messages/vercel-ai.js +185 -0
- package/packages/dd-trace/src/aiguard/sdk.js +13 -1
- package/packages/dd-trace/src/appsec/api_security/index.js +55 -0
- package/packages/dd-trace/src/appsec/api_security/sampler.js +147 -0
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/downstream_requests.js +111 -58
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +54 -12
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +5 -1
- package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +29 -4
- package/packages/dd-trace/src/appsec/index.js +10 -6
- package/packages/dd-trace/src/appsec/rasp/ssrf.js +19 -11
- package/packages/dd-trace/src/appsec/reporter.js +1 -0
- package/packages/dd-trace/src/appsec/telemetry/api_security.js +34 -0
- package/packages/dd-trace/src/appsec/telemetry/index.js +26 -0
- package/packages/dd-trace/src/ci-visibility/requests/request.js +1 -17
- package/packages/dd-trace/src/config/defaults.js +22 -3
- package/packages/dd-trace/src/config/generated-config-types.d.ts +538 -1
- package/packages/dd-trace/src/config/helper.js +133 -33
- package/packages/dd-trace/src/config/index.js +4 -1
- package/packages/dd-trace/src/config/parsers.js +19 -1
- package/packages/dd-trace/src/config/supported-configurations.json +45 -5
- package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +49 -35
- package/packages/dd-trace/src/debugger/devtools_client/index.js +31 -66
- package/packages/dd-trace/src/debugger/devtools_client/probe_sampler.js +83 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +1 -0
- package/packages/dd-trace/src/debugger/index.js +5 -0
- package/packages/dd-trace/src/debugger/probe_sampler.js +112 -0
- package/packages/dd-trace/src/debugger/probe_sampler_constants.js +19 -0
- package/packages/dd-trace/src/dogstatsd.js +15 -8
- package/packages/dd-trace/src/encode/agentless-ci-visibility.js +77 -26
- package/packages/dd-trace/src/exporters/agentless/index.js +7 -5
- package/packages/dd-trace/src/exporters/agentless/intake.js +43 -0
- package/packages/dd-trace/src/exporters/agentless/writer.js +5 -4
- package/packages/dd-trace/src/exporters/common/request.js +1 -20
- package/packages/dd-trace/src/exporters/common/url.js +34 -0
- package/packages/dd-trace/src/exporters/span-stats/writer.js +1 -3
- package/packages/dd-trace/src/guardrails/index.js +8 -5
- package/packages/dd-trace/src/index.js +6 -4
- package/packages/dd-trace/src/llmobs/constants/tags.js +6 -0
- package/packages/dd-trace/src/llmobs/index.js +16 -5
- package/packages/dd-trace/src/llmobs/plugins/genai/util.js +3 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +5 -1
- package/packages/dd-trace/src/llmobs/sdk.js +5 -3
- package/packages/dd-trace/src/llmobs/span_processor.js +4 -0
- package/packages/dd-trace/src/llmobs/tagger.js +55 -0
- package/packages/dd-trace/src/llmobs/telemetry.js +1 -0
- package/packages/dd-trace/src/log/index.js +18 -20
- package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -1
- package/packages/dd-trace/src/opentelemetry/bridge-span-base.js +5 -4
- package/packages/dd-trace/src/opentelemetry/metrics/instruments.js +2 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +4 -3
- package/packages/dd-trace/src/opentelemetry/metrics/time.js +19 -0
- package/packages/dd-trace/src/opentelemetry/otlp/common.proto +2 -2
- package/packages/dd-trace/src/opentelemetry/otlp/logs.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/logs_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/metrics_service.proto +1 -1
- package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +11 -4
- package/packages/dd-trace/src/opentelemetry/span-helpers.js +29 -13
- package/packages/dd-trace/src/opentelemetry/span.js +14 -3
- package/packages/dd-trace/src/opentelemetry/span_context.js +1 -0
- package/packages/dd-trace/src/opentelemetry/trace/index.js +2 -1
- package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +3 -2
- package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +26 -13
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +3 -3
- package/packages/dd-trace/src/opentracing/span_context.js +17 -0
- package/packages/dd-trace/src/plugin_manager.js +7 -1
- package/packages/dd-trace/src/plugins/ci_plugin.js +36 -3
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/util/http-otel-semantics.js +276 -0
- package/packages/dd-trace/src/plugins/util/test.js +80 -0
- package/packages/dd-trace/src/plugins/util/url.js +68 -1
- package/packages/dd-trace/src/plugins/util/web.js +19 -36
- package/packages/dd-trace/src/priority_sampler.js +1 -13
- package/packages/dd-trace/src/profiling/config.js +129 -198
- package/packages/dd-trace/src/profiling/constants.js +4 -7
- package/packages/dd-trace/src/profiling/exporter_cli.js +10 -10
- package/packages/dd-trace/src/profiling/exporters/agent.js +23 -16
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +45 -14
- package/packages/dd-trace/src/profiling/exporters/file.js +16 -5
- package/packages/dd-trace/src/profiling/oom.js +71 -0
- package/packages/dd-trace/src/profiling/profiler.js +35 -23
- package/packages/dd-trace/src/profiling/profilers/events.js +14 -7
- package/packages/dd-trace/src/profiling/profilers/space.js +27 -18
- package/packages/dd-trace/src/profiling/profilers/wall.js +35 -25
- package/packages/dd-trace/src/ritm.js +4 -2
- package/packages/dd-trace/src/serverless.js +1 -2
- package/packages/dd-trace/src/service-naming/schemas/util.js +36 -5
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +5 -3
- package/packages/dd-trace/src/span_format.js +2 -1
- package/packages/dd-trace/src/span_processor.js +6 -0
- package/packages/dd-trace/src/telemetry/send-data.js +12 -10
- package/packages/dd-trace/src/tracer.js +15 -1
- package/packages/dd-trace/src/util.js +14 -0
- package/register.js +58 -1
- package/vendor/dist/@apm-js-collab/code-transformer/index.js +1 -1
- package/vendor/dist/@datadog/sketches-js/index.js +1 -1
- package/vendor/dist/pprof-format/index.js +1 -1
- package/vendor/dist/protobufjs/index.js +1 -1
- package/vendor/dist/protobufjs/minimal/index.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/openai-ai-guard.js +0 -284
- package/packages/dd-trace/src/appsec/api_security_sampler.js +0 -117
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const path = require('node:path')
|
|
4
|
+
|
|
5
|
+
// Build-time half of the optional-peer mechanism shared by the webpack and esbuild plugins.
|
|
6
|
+
//
|
|
7
|
+
// Runtime files load an optional peer through `requireOptionalPeer('name')` (see
|
|
8
|
+
// `require-optional-peer.js`), which bundlers cannot follow, so a build that does not opt into
|
|
9
|
+
// the feature never pulls in the peer's (possibly optional) dependency chain (#8635). When the
|
|
10
|
+
// peer is installed at build time the user has opted in, so the plugins rewrite the call into a
|
|
11
|
+
// literal `require('name')` and let the bundler inline the peer, which keeps it working after
|
|
12
|
+
// the bundle is relocated to a tree without the peer on disk (#8980). Peers that are absent at
|
|
13
|
+
// build time stay opaque, so the rewrite is a no-op and the #8635 guarantee holds.
|
|
14
|
+
|
|
15
|
+
// Files that load an optional peer this way, as suffixes of the resolved module path. The same
|
|
16
|
+
// suffix matches the repo layout and `node_modules/dd-trace`. Add a file here to extend the
|
|
17
|
+
// mechanism to a new optional peer; no plugin change is needed.
|
|
18
|
+
const OPTIONAL_PEER_FILES = [
|
|
19
|
+
'packages/dd-trace/src/openfeature/flagging_provider.js',
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
// Captures the peer name from `requireOptionalPeer('name')` / `requireOptionalPeer("name")`.
|
|
23
|
+
const OPTIONAL_PEER_LOAD = /requireOptionalPeer\((['"])(.+?)\1\)/g
|
|
24
|
+
|
|
25
|
+
// esbuild's `onLoad` needs a path filter; match the basenames so the callback only fires for
|
|
26
|
+
// the candidate files, then `matchesOptionalPeerFile` confirms the full suffix on a normalized
|
|
27
|
+
// path (basenames carry no separators, so the filter is OS-agnostic).
|
|
28
|
+
const OPTIONAL_PEER_FILTER = new RegExp(
|
|
29
|
+
`(?:${OPTIONAL_PEER_FILES.map((file) => path.basename(file).replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`)).join('|')})$`
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} normalizedResource - Resolved module path with forward slashes
|
|
34
|
+
* @returns {boolean} Whether the module is one of the optional-peer loader files
|
|
35
|
+
*/
|
|
36
|
+
function matchesOptionalPeerFile (normalizedResource) {
|
|
37
|
+
return OPTIONAL_PEER_FILES.some((suffix) => normalizedResource.endsWith(suffix))
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Rewrites each `requireOptionalPeer('name')` whose peer resolves from `fromDir` into a literal
|
|
42
|
+
* `require('name')` so the bundler inlines it. Peers that do not resolve stay opaque, so a build
|
|
43
|
+
* without the peer keeps the #8635 guarantee.
|
|
44
|
+
*
|
|
45
|
+
* @param {string} source - Source of an optional-peer loader file
|
|
46
|
+
* @param {string} fromDir - Directory to resolve the optional peers from
|
|
47
|
+
* @returns {string} Source with installed optional peers turned into literal requires
|
|
48
|
+
*/
|
|
49
|
+
function rewriteOptionalPeerLoads (source, fromDir) {
|
|
50
|
+
return source.replaceAll(OPTIONAL_PEER_LOAD, (match, _quote, request) => {
|
|
51
|
+
try {
|
|
52
|
+
require.resolve(request, { paths: [fromDir] })
|
|
53
|
+
} catch {
|
|
54
|
+
return match
|
|
55
|
+
}
|
|
56
|
+
return `require('${request}')`
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
OPTIONAL_PEER_FILES,
|
|
62
|
+
OPTIONAL_PEER_FILTER,
|
|
63
|
+
matchesOptionalPeerFile,
|
|
64
|
+
rewriteOptionalPeerLoads,
|
|
65
|
+
}
|
|
@@ -13,8 +13,9 @@ const Hook = require('./hook')
|
|
|
13
13
|
const { isRelativeRequire } = require('./shared-utils')
|
|
14
14
|
const rewriter = require('./rewriter')
|
|
15
15
|
|
|
16
|
-
const DD_TRACE_DISABLED_INSTRUMENTATIONS =
|
|
17
|
-
|
|
16
|
+
const DD_TRACE_DISABLED_INSTRUMENTATIONS =
|
|
17
|
+
getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS')
|
|
18
|
+
const DD_TRACE_DEBUG = getValueFromEnvSources('DD_TRACE_DEBUG')
|
|
18
19
|
|
|
19
20
|
const hooks = require('./hooks')
|
|
20
21
|
const instrumentations = require('./instrumentations')
|
|
@@ -36,8 +37,9 @@ if (!disabledInstrumentations.has('process')) {
|
|
|
36
37
|
require('../process')
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
const debugEnabled = DD_TRACE_DEBUG
|
|
41
|
+
checkRequireCache.checkForRequiredModules()
|
|
42
|
+
if (debugEnabled) {
|
|
41
43
|
setImmediate(checkRequireCache.checkForPotentialConflicts)
|
|
42
44
|
}
|
|
43
45
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
// Loads an optional peer through a require bundlers cannot follow: the package name is an
|
|
4
|
+
// argument, not a `require('literal')`, so a build that does not install the peer never pulls
|
|
5
|
+
// in its (possibly optional) dependency chain (#8635). When the peer is installed at build
|
|
6
|
+
// time, the webpack and esbuild plugins rewrite `requireOptionalPeer('name')` into a literal
|
|
7
|
+
// `require('name')` so the peer is bundled and survives the bundle being relocated without it
|
|
8
|
+
// on disk (#8980). See `optional-peer-bundler.js` for the build-time half.
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} request - Module specifier of the optional peer
|
|
12
|
+
*/
|
|
13
|
+
module.exports = function requireOptionalPeer (request) {
|
|
14
|
+
// eslint-disable-next-line camelcase, no-undef
|
|
15
|
+
const runtimeRequire = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : require
|
|
16
|
+
return runtimeRequire(request)
|
|
17
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const contextMethods = require('../../../aws-durable-execution-sdk-js-context-methods')
|
|
4
|
+
|
|
5
|
+
const baseModule = { name: '@aws/durable-execution-sdk-js', versionRange: '>=1.1.0' }
|
|
6
|
+
|
|
7
|
+
const buildEntries = filePath => {
|
|
8
|
+
const module = { ...baseModule, filePath }
|
|
9
|
+
return [
|
|
10
|
+
{
|
|
11
|
+
module,
|
|
12
|
+
functionQuery: { functionName: 'runHandler', kind: 'Async' },
|
|
13
|
+
channelName: 'withDurableExecution',
|
|
14
|
+
},
|
|
15
|
+
...contextMethods.map(methodName => ({
|
|
16
|
+
module,
|
|
17
|
+
functionQuery: { className: 'DurableContextImpl', methodName, kind: 'Sync' },
|
|
18
|
+
channelName: `DurableContextImpl_${methodName}`,
|
|
19
|
+
})),
|
|
20
|
+
{
|
|
21
|
+
module,
|
|
22
|
+
functionQuery: { className: 'CheckpointManager', methodName: 'checkpoint', kind: 'Async' },
|
|
23
|
+
channelName: 'CheckpointManager_checkpoint',
|
|
24
|
+
},
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
module.exports = [
|
|
29
|
+
...buildEntries('dist/index.mjs'),
|
|
30
|
+
...buildEntries('dist-cjs/index.js'),
|
|
31
|
+
]
|
|
@@ -3,9 +3,25 @@ import { rewrite } from './index.js'
|
|
|
3
3
|
async function load (url, context, nextLoad) {
|
|
4
4
|
const result = await nextLoad(url, context)
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
return rewriteResult(result, url, context)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function loadSync (url, context, nextLoad) {
|
|
10
|
+
const result = nextLoad(url, context)
|
|
11
|
+
|
|
12
|
+
return rewriteResult(result, url, context)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function rewriteResult (result, url, context) {
|
|
16
|
+
const format = result.format || context.format
|
|
17
|
+
|
|
18
|
+
// CommonJS source is rewritten by Module._compile. Rewriting it here too
|
|
19
|
+
// double-instruments CommonJS entrypoints loaded through sync hooks.
|
|
20
|
+
if (format === 'commonjs') return result
|
|
21
|
+
|
|
22
|
+
result.source = rewrite(result.source, url, format)
|
|
7
23
|
|
|
8
24
|
return result
|
|
9
25
|
}
|
|
10
26
|
|
|
11
|
-
export { load }
|
|
27
|
+
export { load, loadSync }
|
|
@@ -14,6 +14,7 @@ const finishChannel = channel('apm:http:client:request:finish')
|
|
|
14
14
|
const endChannel = channel('apm:http:client:request:end')
|
|
15
15
|
const asyncStartChannel = channel('apm:http:client:request:asyncStart')
|
|
16
16
|
const errorChannel = channel('apm:http:client:request:error')
|
|
17
|
+
const responseStartChannel = channel('apm:http:client:response:start')
|
|
17
18
|
const responseFinishChannel = channel('apm:http:client:response:finish')
|
|
18
19
|
|
|
19
20
|
addHook({ name: 'http' }, hookFn)
|
|
@@ -78,10 +79,15 @@ function setupResponseInstrumentation (ctx, res) {
|
|
|
78
79
|
let dataReadStarted = false
|
|
79
80
|
|
|
80
81
|
const { shouldCollectBody } = ctx
|
|
81
|
-
|
|
82
|
+
|
|
83
|
+
let bodyChunks = null
|
|
84
|
+
|
|
85
|
+
if (shouldCollectBody) {
|
|
86
|
+
bodyChunks = []
|
|
87
|
+
}
|
|
82
88
|
|
|
83
89
|
const collectChunk = chunk => {
|
|
84
|
-
if (!
|
|
90
|
+
if (!bodyChunks || !chunk) return
|
|
85
91
|
|
|
86
92
|
if (typeof chunk === 'string') {
|
|
87
93
|
bodyChunks.push(chunk)
|
|
@@ -229,6 +235,10 @@ function patch (http, methodName) {
|
|
|
229
235
|
res.once('end', finish)
|
|
230
236
|
res.once(errorMonitor, finish)
|
|
231
237
|
|
|
238
|
+
if (responseStartChannel.hasSubscribers) {
|
|
239
|
+
responseStartChannel.publish({ ctx, res })
|
|
240
|
+
}
|
|
241
|
+
|
|
232
242
|
const instrumentation = setupResponseInstrumentation(ctx, res)
|
|
233
243
|
|
|
234
244
|
if (!instrumentation) {
|
|
@@ -18,10 +18,9 @@ addHook({ name: 'iovalkey', versions: ['>=0.0.1'] }, Valkey => {
|
|
|
18
18
|
|
|
19
19
|
const options = this.options || {}
|
|
20
20
|
const connectionName = options.connectionName
|
|
21
|
-
const db = options.db
|
|
22
21
|
const connectionOptions = { host: options.host, port: options.port }
|
|
23
22
|
|
|
24
|
-
const ctx = {
|
|
23
|
+
const ctx = { command: command.name, args: command.args, connectionOptions, connectionName }
|
|
25
24
|
return startCh.runStores(ctx, () => {
|
|
26
25
|
command.promise.then(() => finish(finishCh, errorCh, ctx), err => finish(finishCh, errorCh, ctx, err))
|
|
27
26
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const { addHook, channel, createErrorPublisher } = require('./helpers/instrument')
|
|
5
5
|
|
|
6
6
|
const enterChannel = channel('apm:koa:middleware:enter')
|
|
7
7
|
const exitChannel = channel('apm:koa:middleware:exit')
|
|
@@ -10,6 +10,7 @@ const nextChannel = channel('apm:koa:middleware:next')
|
|
|
10
10
|
const finishChannel = channel('apm:koa:middleware:finish')
|
|
11
11
|
const handleChannel = channel('apm:koa:request:handle')
|
|
12
12
|
const routeChannel = channel('apm:koa:request:route')
|
|
13
|
+
const publishError = createErrorPublisher(errorChannel)
|
|
13
14
|
|
|
14
15
|
const originals = new WeakMap()
|
|
15
16
|
|
|
@@ -132,7 +133,7 @@ function fulfill (ctx, error) {
|
|
|
132
133
|
const route = ctx.routePath
|
|
133
134
|
|
|
134
135
|
if (error) {
|
|
135
|
-
|
|
136
|
+
publishError({ req, error })
|
|
136
137
|
}
|
|
137
138
|
|
|
138
139
|
// TODO: make sure that the parent class cannot override this in `enter`
|
|
@@ -160,14 +160,16 @@ addHook({ name, file: 'lib/cmd/execute.js', versions: ['>=3'] }, (Execute) => {
|
|
|
160
160
|
return wrapCommand(Execute)
|
|
161
161
|
})
|
|
162
162
|
|
|
163
|
-
//
|
|
163
|
+
// mariadb 3.4.1 refactored the pool: getConnection switched from promises to
|
|
164
|
+
// callbacks and _createConnection was renamed to _createPoolConnection.
|
|
164
165
|
addHook({ name, file: 'lib/pool.js', versions: ['>=3.4.1'] }, (Pool) => {
|
|
165
166
|
shimmer.wrap(Pool.prototype, 'getConnection', wrapPoolGetConnectionMethod)
|
|
167
|
+
shimmer.wrap(Pool.prototype, '_createPoolConnection', wrapPoolMethod)
|
|
166
168
|
|
|
167
169
|
return Pool
|
|
168
170
|
})
|
|
169
171
|
|
|
170
|
-
addHook({ name, file: 'lib/pool.js', versions: ['>=3'] }, (Pool) => {
|
|
172
|
+
addHook({ name, file: 'lib/pool.js', versions: ['>=3 <3.4.1'] }, (Pool) => {
|
|
171
173
|
shimmer.wrap(Pool.prototype, '_createConnection', wrapPoolMethod)
|
|
172
174
|
|
|
173
175
|
return Pool
|
|
@@ -1093,9 +1093,9 @@ addHook({
|
|
|
1093
1093
|
shimmer.wrap(BufferedWorkerPool.prototype, 'run', run => async function (testSuiteAbsolutePath, workerArgs) {
|
|
1094
1094
|
if (!testFinishCh.hasSubscribers ||
|
|
1095
1095
|
(!config.isKnownTestsEnabled &&
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1096
|
+
!config.isTestManagementTestsEnabled &&
|
|
1097
|
+
!config.isImpactedTestsEnabled &&
|
|
1098
|
+
!config.isFlakyTestRetriesEnabled)) {
|
|
1099
1099
|
return run.apply(this, arguments)
|
|
1100
1100
|
}
|
|
1101
1101
|
|
|
@@ -141,19 +141,19 @@ function instrument (req, res, handler, error) {
|
|
|
141
141
|
requests.add(req)
|
|
142
142
|
|
|
143
143
|
const ctx = { req, res }
|
|
144
|
-
// Parse query parameters from request URL
|
|
145
144
|
if (queryParsedChannel.hasSubscribers && req.url) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
const queryIndex = req.url.indexOf('?')
|
|
146
|
+
if (queryIndex !== -1) {
|
|
147
|
+
const searchParams = new URLSearchParams(req.url.slice(queryIndex + 1))
|
|
148
|
+
const query = {}
|
|
149
|
+
for (const key of searchParams.keys()) {
|
|
150
|
+
if (!query[key]) {
|
|
151
|
+
query[key] = searchParams.getAll(key)
|
|
152
|
+
}
|
|
153
153
|
}
|
|
154
|
-
}
|
|
155
154
|
|
|
156
|
-
|
|
155
|
+
queryParsedChannel.publish({ query })
|
|
156
|
+
}
|
|
157
157
|
}
|
|
158
158
|
|
|
159
159
|
return startChannel.runStores(ctx, () => {
|
|
@@ -220,6 +220,40 @@ addHook({
|
|
|
220
220
|
return NextRequestAdapter
|
|
221
221
|
})
|
|
222
222
|
|
|
223
|
+
// From next 15.4.1 each app-route build inlines its own copy of `fromNodeNextRequest`, so the hook
|
|
224
|
+
// above no longer maps the node request to the app-route NextRequest and a thrown handler error
|
|
225
|
+
// cannot reach `finish`. The app-route runtime reports real errors (redirect/notFound and other
|
|
226
|
+
// control-flow signals excluded by next) through `RouteModule.onRequestError`, which next loads from
|
|
227
|
+
// a precompiled `app-route*.runtime.{dev,prod}.js` bundle regardless of how the route chunk is
|
|
228
|
+
// bundled. The bundler/experimental part of the name is matched with a pattern rather than
|
|
229
|
+
// enumerated, so a variant next adds later is picked up without a code change.
|
|
230
|
+
const patchedAppRouteModules = new WeakSet()
|
|
231
|
+
|
|
232
|
+
function wrapOnRequestError (onRequestError) {
|
|
233
|
+
return function (req, error) {
|
|
234
|
+
if (error) {
|
|
235
|
+
errorChannel.publish({ error })
|
|
236
|
+
}
|
|
237
|
+
return onRequestError.apply(this, arguments)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
function instrumentAppRouteRuntime (runtime) {
|
|
242
|
+
const AppRouteRouteModule = runtime.AppRouteRouteModule
|
|
243
|
+
const proto = AppRouteRouteModule?.prototype
|
|
244
|
+
if (proto && typeof proto.onRequestError === 'function' && !patchedAppRouteModules.has(AppRouteRouteModule)) {
|
|
245
|
+
patchedAppRouteModules.add(AppRouteRouteModule)
|
|
246
|
+
shimmer.wrap(proto, 'onRequestError', wrapOnRequestError)
|
|
247
|
+
}
|
|
248
|
+
return runtime
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
addHook({
|
|
252
|
+
name: 'next',
|
|
253
|
+
versions: ['>=15.4.1'],
|
|
254
|
+
filePattern: String.raw`dist/compiled/next-server/app-route[\w-]*\.runtime\.(?:dev|prod)\.js$`,
|
|
255
|
+
}, instrumentAppRouteRuntime)
|
|
256
|
+
|
|
223
257
|
addHook({
|
|
224
258
|
name: 'next',
|
|
225
259
|
versions: ['>=11.1'],
|
|
@@ -3,11 +3,52 @@
|
|
|
3
3
|
const dc = require('dc-polyfill')
|
|
4
4
|
const shimmer = require('../../datadog-shimmer')
|
|
5
5
|
const { addHook } = require('./helpers/instrument')
|
|
6
|
-
const aiGuard = require('./helpers/openai-ai-guard')
|
|
7
6
|
|
|
8
7
|
const ch = dc.tracingChannel('apm:openai:request')
|
|
9
8
|
const onStreamedChunkCh = dc.channel('apm:openai:request:chunk')
|
|
10
9
|
|
|
10
|
+
// Provider lifecycle channels. Payloads stay OpenAI-native:
|
|
11
|
+
// before { args, parentSpan, abortController, pending }
|
|
12
|
+
// after { args, body, parentSpan, abortController, pending }
|
|
13
|
+
const chatCompletionsBeforeChannel = dc.channel('dd-trace:openai:chat.completions:before')
|
|
14
|
+
const chatCompletionsAfterChannel = dc.channel('dd-trace:openai:chat.completions:after')
|
|
15
|
+
const responsesBeforeChannel = dc.channel('dd-trace:openai:responses:before')
|
|
16
|
+
const responsesAfterChannel = dc.channel('dd-trace:openai:responses:after')
|
|
17
|
+
|
|
18
|
+
const LIFECYCLE_CHANNELS = {
|
|
19
|
+
'chat.completions': {
|
|
20
|
+
before: chatCompletionsBeforeChannel,
|
|
21
|
+
after: chatCompletionsAfterChannel,
|
|
22
|
+
},
|
|
23
|
+
responses: {
|
|
24
|
+
before: responsesBeforeChannel,
|
|
25
|
+
after: responsesAfterChannel,
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Publishes a provider-native lifecycle payload to a cancelable lifecycle channel.
|
|
31
|
+
*
|
|
32
|
+
* Subscribers push async work into `pending` synchronously during publication and
|
|
33
|
+
* abort `abortController` with an error before the pushed promise resolves to block.
|
|
34
|
+
*
|
|
35
|
+
* @param {object} channel
|
|
36
|
+
* @param {object} payload
|
|
37
|
+
* @returns {Promise<void>}
|
|
38
|
+
*/
|
|
39
|
+
function publishLifecycle (channel, payload) {
|
|
40
|
+
const abortController = new AbortController()
|
|
41
|
+
const ctx = { ...payload, abortController, pending: [] }
|
|
42
|
+
|
|
43
|
+
channel.publish(ctx)
|
|
44
|
+
|
|
45
|
+
return Promise.all(ctx.pending).then(() => {
|
|
46
|
+
if (abortController.signal.aborted) {
|
|
47
|
+
throw abortController.signal.reason
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
11
52
|
const V4_PACKAGE_SHIMS = [
|
|
12
53
|
{
|
|
13
54
|
file: 'resources/chat/completions',
|
|
@@ -217,17 +258,15 @@ for (const extension of extensions) {
|
|
|
217
258
|
|
|
218
259
|
for (const methodName of methods) {
|
|
219
260
|
shimmer.wrap(targetPrototype, methodName, methodFn => function (...args) {
|
|
220
|
-
if (!ch.start.hasSubscribers && !aiGuard.hasSubscribers()) {
|
|
221
|
-
return methodFn.apply(this, args)
|
|
222
|
-
}
|
|
223
261
|
// The OpenAI library lets you set `stream: true` on the options arg to any method
|
|
224
262
|
// However, we only want to handle streamed responses in specific cases
|
|
225
263
|
// chat.completions and completions
|
|
226
264
|
const stream = streamedResponse && getOption(args, 'stream', false)
|
|
227
265
|
|
|
228
|
-
const
|
|
266
|
+
const channels = stream ? null : LIFECYCLE_CHANNELS[baseResource]
|
|
267
|
+
const hasLifecycle = !!channels && (channels.before.hasSubscribers || channels.after.hasSubscribers)
|
|
229
268
|
|
|
230
|
-
if (!ch.start.hasSubscribers && !
|
|
269
|
+
if (!ch.start.hasSubscribers && !hasLifecycle) {
|
|
231
270
|
return methodFn.apply(this, args)
|
|
232
271
|
}
|
|
233
272
|
|
|
@@ -240,12 +279,22 @@ for (const extension of extensions) {
|
|
|
240
279
|
}
|
|
241
280
|
|
|
242
281
|
return ch.start.runStores(ctx, () => {
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
|
|
282
|
+
// Capture the parent span explicitly: the _thenUnwrap/parse path decouples
|
|
283
|
+
// the lazy evaluation from the active scope at call time.
|
|
284
|
+
const parentSpan = hasLifecycle ? ctx.currentStore?.span : undefined
|
|
246
285
|
|
|
247
286
|
const apiProm = methodFn.apply(this, args)
|
|
248
287
|
|
|
288
|
+
const beforeChannel = hasLifecycle && channels.before.hasSubscribers ? channels.before : null
|
|
289
|
+
const afterChannel = hasLifecycle && channels.after.hasSubscribers ? channels.after : null
|
|
290
|
+
let beforeVerdict
|
|
291
|
+
const getBeforeVerdict = beforeChannel
|
|
292
|
+
? function getBeforeVerdict () {
|
|
293
|
+
beforeVerdict ??= publishLifecycle(beforeChannel, { args, parentSpan })
|
|
294
|
+
return beforeVerdict
|
|
295
|
+
}
|
|
296
|
+
: null
|
|
297
|
+
|
|
249
298
|
if (baseResource === 'chat.completions' && typeof apiProm._thenUnwrap === 'function') {
|
|
250
299
|
// this should only ever be invoked from a client.beta.chat.completions.parse call
|
|
251
300
|
shimmer.wrap(apiProm, '_thenUnwrap', origApiPromThenUnwrap => function (...args) {
|
|
@@ -259,7 +308,9 @@ for (const extension of extensions) {
|
|
|
259
308
|
const parsedPromise = origApiPromParse.apply(this, args)
|
|
260
309
|
.then(body => Promise.all([this.responsePromise, body]))
|
|
261
310
|
|
|
262
|
-
return handleUnwrappedAPIPromise(
|
|
311
|
+
return handleUnwrappedAPIPromise(
|
|
312
|
+
parsedPromise, ctx, stream, getBeforeVerdict, afterChannel, parentSpan
|
|
313
|
+
)
|
|
263
314
|
})
|
|
264
315
|
|
|
265
316
|
return unwrappedPromise
|
|
@@ -272,10 +323,16 @@ for (const extension of extensions) {
|
|
|
272
323
|
const parsedPromise = origApiPromParse.apply(this, args)
|
|
273
324
|
.then(body => Promise.all([this.responsePromise, body]))
|
|
274
325
|
|
|
275
|
-
return handleUnwrappedAPIPromise(parsedPromise, ctx, stream,
|
|
326
|
+
return handleUnwrappedAPIPromise(parsedPromise, ctx, stream, getBeforeVerdict, afterChannel, parentSpan)
|
|
276
327
|
})
|
|
277
328
|
|
|
278
|
-
|
|
329
|
+
// Gate `.asResponse()` callers on the before verdict so raw-response paths still block.
|
|
330
|
+
if (beforeChannel && typeof apiProm.asResponse === 'function') {
|
|
331
|
+
shimmer.wrap(apiProm, 'asResponse', origAsResponse => function (...args) {
|
|
332
|
+
const responsePromise = origAsResponse.apply(this, args)
|
|
333
|
+
return Promise.all([getBeforeVerdict(), responsePromise]).then(([, response]) => response)
|
|
334
|
+
})
|
|
335
|
+
}
|
|
279
336
|
|
|
280
337
|
ch.end.publish(ctx)
|
|
281
338
|
|
|
@@ -288,10 +345,12 @@ for (const extension of extensions) {
|
|
|
288
345
|
}
|
|
289
346
|
}
|
|
290
347
|
|
|
291
|
-
function handleUnwrappedAPIPromise (apiProm, ctx, stream,
|
|
292
|
-
const
|
|
348
|
+
function handleUnwrappedAPIPromise (apiProm, ctx, stream, getBeforeVerdict, afterChannel, parentSpan) {
|
|
349
|
+
const gatedApiProm = getBeforeVerdict
|
|
350
|
+
? Promise.all([getBeforeVerdict(), apiProm]).then(([, result]) => result)
|
|
351
|
+
: apiProm
|
|
293
352
|
|
|
294
|
-
return
|
|
353
|
+
return gatedApiProm
|
|
295
354
|
.then(([{ response, options }, body]) => {
|
|
296
355
|
if (stream) {
|
|
297
356
|
if (body.iterator) {
|
|
@@ -313,14 +372,14 @@ function handleUnwrappedAPIPromise (apiProm, ctx, stream, guard) {
|
|
|
313
372
|
},
|
|
314
373
|
}
|
|
315
374
|
|
|
316
|
-
if (!
|
|
375
|
+
if (!afterChannel) {
|
|
317
376
|
finish(ctx, responseData)
|
|
318
377
|
return body
|
|
319
378
|
}
|
|
320
379
|
|
|
321
380
|
// Finish after evaluation so a block propagates the error to openai.request
|
|
322
|
-
// and the span wraps its
|
|
323
|
-
return
|
|
381
|
+
// and the span wraps its child instead of closing before it.
|
|
382
|
+
return publishLifecycle(afterChannel, { args: ctx.args, body, parentSpan }).then(() => {
|
|
324
383
|
finish(ctx, responseData)
|
|
325
384
|
return body
|
|
326
385
|
})
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
4
|
const tracer = require('../../dd-trace')
|
|
5
5
|
const { getValueFromEnvSources } = require('../../dd-trace/src/config/helper')
|
|
6
|
-
const { isFalse, isTrue } = require('../../dd-trace/src/util')
|
|
7
6
|
const { addHook } = require('./helpers/instrument')
|
|
8
7
|
|
|
9
8
|
if (isOtelSdkEnabled()) {
|
|
@@ -21,9 +20,11 @@ if (isOtelSdkEnabled()) {
|
|
|
21
20
|
|
|
22
21
|
function isOtelSdkEnabled () {
|
|
23
22
|
// Datadog explicit opt-out wins over every OTel signal; check it first.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
if (
|
|
28
|
-
|
|
23
|
+
// skipDefault: an unset option must stay undefined so the OTel signal still decides — the
|
|
24
|
+
// registered defaults (false / true) would otherwise force-disable before that check.
|
|
25
|
+
const ddTraceOtelEnabled = getValueFromEnvSources('DD_TRACE_OTEL_ENABLED', true)
|
|
26
|
+
if (ddTraceOtelEnabled === false) return false
|
|
27
|
+
const otelSdkDisabled = getValueFromEnvSources('OTEL_SDK_DISABLED', true)
|
|
28
|
+
if (otelSdkDisabled) return false
|
|
29
|
+
return ddTraceOtelEnabled || otelSdkDisabled === false
|
|
29
30
|
}
|
|
@@ -59,7 +59,7 @@ const testSuiteToTestStatuses = new Map()
|
|
|
59
59
|
const testSuiteToErrors = new Map()
|
|
60
60
|
const testsToTestStatuses = new Map()
|
|
61
61
|
|
|
62
|
-
const RUM_FLUSH_WAIT_TIME =
|
|
62
|
+
const RUM_FLUSH_WAIT_TIME = getValueFromEnvSources('DD_CIVISIBILITY_RUM_FLUSH_WAIT_MILLIS')
|
|
63
63
|
const DD_PROPERTIES_TIMEOUT = 5000
|
|
64
64
|
|
|
65
65
|
let applyRepeatEachIndex = null
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const shimmer = require('../../datadog-shimmer')
|
|
4
|
-
const { addHook, channel } = require('./helpers/instrument')
|
|
4
|
+
const { addHook, channel, createErrorPublisher } = require('./helpers/instrument')
|
|
5
5
|
const handlers = ['use', 'pre']
|
|
6
6
|
const methods = ['del', 'get', 'head', 'opts', 'post', 'put', 'patch']
|
|
7
7
|
|
|
@@ -11,6 +11,7 @@ const enterChannel = channel('apm:restify:middleware:enter')
|
|
|
11
11
|
const exitChannel = channel('apm:restify:middleware:exit')
|
|
12
12
|
const finishChannel = channel('apm:restify:middleware:finish')
|
|
13
13
|
const nextChannel = channel('apm:restify:middleware:next')
|
|
14
|
+
const publishError = createErrorPublisher(errorChannel)
|
|
14
15
|
|
|
15
16
|
function wrapSetupRequest (setupRequest) {
|
|
16
17
|
return function (req, res) {
|
|
@@ -53,7 +54,7 @@ function wrapFn (fn) {
|
|
|
53
54
|
finishChannel.publish({ req })
|
|
54
55
|
return result
|
|
55
56
|
}).catch(function (error) {
|
|
56
|
-
|
|
57
|
+
publishError({ req, error })
|
|
57
58
|
nextChannel.publish({ req })
|
|
58
59
|
finishChannel.publish({ req })
|
|
59
60
|
throw error
|
|
@@ -61,7 +62,7 @@ function wrapFn (fn) {
|
|
|
61
62
|
}
|
|
62
63
|
return result
|
|
63
64
|
} catch (error) {
|
|
64
|
-
|
|
65
|
+
publishError({ req, error })
|
|
65
66
|
nextChannel.publish({ req })
|
|
66
67
|
finishChannel.publish({ req })
|
|
67
68
|
throw error
|