dd-trace 5.102.0 → 5.103.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/ext/exporters.js +1 -0
- package/package.json +12 -11
- package/packages/datadog-esbuild/src/utils.js +2 -2
- package/packages/datadog-instrumentations/src/ai.js +1 -1
- package/packages/datadog-instrumentations/src/confluentinc-kafka-javascript.js +32 -15
- package/packages/datadog-instrumentations/src/couchbase.js +69 -220
- package/packages/datadog-instrumentations/src/cucumber.js +1 -1
- package/packages/datadog-instrumentations/src/electron/preload.js +42 -0
- package/packages/datadog-instrumentations/src/electron.js +240 -0
- package/packages/datadog-instrumentations/src/fetch.js +5 -5
- package/packages/datadog-instrumentations/src/graphql.js +13 -12
- package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +1 -1
- package/packages/datadog-instrumentations/src/helpers/hook.js +4 -1
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/kafka.js +41 -0
- package/packages/datadog-instrumentations/src/ioredis.js +16 -12
- package/packages/datadog-instrumentations/src/jest.js +351 -50
- package/packages/datadog-instrumentations/src/kafkajs.js +164 -173
- package/packages/datadog-instrumentations/src/mocha/main.js +73 -1
- package/packages/datadog-instrumentations/src/mongodb-core.js +33 -8
- package/packages/datadog-instrumentations/src/pg.js +24 -10
- package/packages/datadog-instrumentations/src/playwright.js +427 -55
- package/packages/datadog-instrumentations/src/redis.js +19 -10
- package/packages/datadog-plugin-apollo/src/gateway/request.js +1 -21
- package/packages/datadog-plugin-aws-sdk/src/base.js +18 -24
- package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
- package/packages/datadog-plugin-couchbase/src/index.js +58 -52
- package/packages/datadog-plugin-cucumber/src/index.js +1 -0
- package/packages/datadog-plugin-cypress/src/cypress-plugin.js +214 -22
- package/packages/datadog-plugin-cypress/src/support.js +13 -1
- package/packages/datadog-plugin-electron/src/index.js +17 -0
- package/packages/datadog-plugin-electron/src/ipc.js +143 -0
- package/packages/datadog-plugin-electron/src/net.js +82 -0
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +27 -18
- package/packages/datadog-plugin-graphql/src/execute.js +6 -28
- package/packages/datadog-plugin-graphql/src/resolve.js +30 -35
- package/packages/datadog-plugin-graphql/src/tools/signature.js +32 -7
- package/packages/datadog-plugin-graphql/src/tools/transforms.js +118 -100
- package/packages/datadog-plugin-graphql/src/utils.js +29 -0
- package/packages/datadog-plugin-grpc/src/client.js +6 -7
- package/packages/datadog-plugin-grpc/src/util.js +57 -22
- package/packages/datadog-plugin-http/src/client.js +2 -2
- package/packages/datadog-plugin-jest/src/index.js +92 -50
- package/packages/datadog-plugin-mocha/src/index.js +1 -0
- package/packages/datadog-plugin-mongodb-core/src/index.js +36 -70
- package/packages/datadog-plugin-mysql/src/index.js +1 -1
- package/packages/datadog-plugin-openai/src/services.js +2 -1
- package/packages/datadog-plugin-pg/src/index.js +3 -3
- package/packages/datadog-plugin-playwright/src/index.js +4 -0
- package/packages/datadog-plugin-redis/src/index.js +18 -23
- package/packages/dd-trace/src/aiguard/index.js +3 -1
- package/packages/dd-trace/src/aiguard/sdk.js +36 -30
- package/packages/dd-trace/src/aiguard/tags.js +20 -11
- package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +2 -2
- package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +1 -1
- package/packages/dd-trace/src/azure_metadata.js +17 -6
- package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +4 -4
- package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +4 -2
- package/packages/dd-trace/src/ci-visibility/exporters/test-worker/index.js +6 -4
- package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +1 -1
- package/packages/dd-trace/src/config/defaults.js +3 -14
- package/packages/dd-trace/src/config/generated-config-types.d.ts +3 -1
- package/packages/dd-trace/src/config/helper.js +4 -0
- package/packages/dd-trace/src/config/index.js +2 -2
- package/packages/dd-trace/src/config/major-overrides.js +98 -0
- package/packages/dd-trace/src/config/parsers.js +7 -1
- package/packages/dd-trace/src/config/supported-configurations.json +51 -38
- package/packages/dd-trace/src/datastreams/checkpointer.js +2 -2
- package/packages/dd-trace/src/datastreams/manager.js +1 -1
- package/packages/dd-trace/src/datastreams/processor.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +2 -2
- package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +1 -1
- package/packages/dd-trace/src/debugger/devtools_client/state.js +2 -1
- package/packages/dd-trace/src/debugger/index.js +7 -7
- package/packages/dd-trace/src/dogstatsd.js +2 -2
- package/packages/dd-trace/src/encode/0.4.js +45 -54
- package/packages/dd-trace/src/encode/0.5.js +34 -3
- package/packages/dd-trace/src/encode/agentless-json.js +1 -1
- package/packages/dd-trace/src/exporter.js +2 -0
- package/packages/dd-trace/src/exporters/agent/index.js +2 -1
- package/packages/dd-trace/src/exporters/agentless/index.js +3 -2
- package/packages/dd-trace/src/exporters/agentless/writer.js +2 -2
- package/packages/dd-trace/src/exporters/common/buffering-exporter.js +2 -1
- package/packages/dd-trace/src/exporters/common/request.js +1 -1
- package/packages/dd-trace/src/exporters/electron/index.js +49 -0
- package/packages/dd-trace/src/external-logger/src/index.js +2 -1
- package/packages/dd-trace/src/git_metadata.js +10 -8
- package/packages/dd-trace/src/lambda/handler-paths.js +52 -0
- package/packages/dd-trace/src/lambda/index.js +62 -14
- package/packages/dd-trace/src/lambda/runtime/patch.js +21 -46
- package/packages/dd-trace/src/llmobs/index.js +13 -2
- package/packages/dd-trace/src/llmobs/plugins/bedrockruntime.js +45 -15
- package/packages/dd-trace/src/llmobs/writers/base.js +2 -1
- package/packages/dd-trace/src/openfeature/writers/base.js +2 -1
- package/packages/dd-trace/src/opentelemetry/metrics/periodic_metric_reader.js +2 -1
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +20 -9
- package/packages/dd-trace/src/payload-tagging/config/index.js +2 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +49 -4
- package/packages/dd-trace/src/plugins/database.js +54 -12
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/plugin.js +2 -4
- package/packages/dd-trace/src/plugins/util/ci.js +8 -8
- package/packages/dd-trace/src/plugins/util/git-cache.js +20 -18
- package/packages/dd-trace/src/plugins/util/stacktrace.js +2 -2
- package/packages/dd-trace/src/plugins/util/test.js +37 -5
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -15
- package/packages/dd-trace/src/priority_sampler.js +1 -1
- package/packages/dd-trace/src/profiling/profiler.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- package/packages/dd-trace/src/profiling/ssi-heuristics.js +1 -1
- package/packages/dd-trace/src/rate_limiter.js +1 -1
- package/packages/dd-trace/src/remote_config/scheduler.js +1 -1
- package/packages/dd-trace/src/ritm.js +2 -1
- package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +5 -8
- package/packages/dd-trace/src/serverless.js +5 -2
- package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +20 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/messaging.js +20 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
- package/packages/dd-trace/src/span_stats.js +1 -1
- package/packages/dd-trace/src/telemetry/dependencies.js +1 -1
- package/packages/dd-trace/src/telemetry/endpoints.js +1 -1
- package/packages/dd-trace/src/telemetry/telemetry.js +2 -2
- package/packages/dd-trace/src/lambda/runtime/ritm.js +0 -133
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { channel } = require('dc-polyfill')
|
|
4
|
+
const { truncateSpan, normalizeSpan } = require('../../encode/tags-processors')
|
|
5
|
+
|
|
6
|
+
const traceChannel = channel('datadog:apm:electron:export')
|
|
7
|
+
|
|
8
|
+
class ElectronExporter {
|
|
9
|
+
#timer
|
|
10
|
+
#traces = []
|
|
11
|
+
|
|
12
|
+
constructor (config) {
|
|
13
|
+
this._config = config
|
|
14
|
+
|
|
15
|
+
globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(this.flush.bind(this))
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export (spans) {
|
|
19
|
+
this.#traces.push(spans)
|
|
20
|
+
|
|
21
|
+
const { flushInterval } = this._config
|
|
22
|
+
|
|
23
|
+
if (flushInterval === 0) {
|
|
24
|
+
this.flush()
|
|
25
|
+
} else if (this.#timer === undefined) {
|
|
26
|
+
this.#timer = setTimeout(() => {
|
|
27
|
+
this.flush()
|
|
28
|
+
this.#timer = undefined
|
|
29
|
+
}, flushInterval)
|
|
30
|
+
this.#timer.unref?.()
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
flush (done = () => {}) {
|
|
35
|
+
clearTimeout(this.#timer)
|
|
36
|
+
this.#timer = undefined
|
|
37
|
+
|
|
38
|
+
const traces = this.#traces.splice(0)
|
|
39
|
+
|
|
40
|
+
if (traces.length > 0 && traceChannel.hasSubscribers) {
|
|
41
|
+
const formattedTraces = traces.map(spans => spans.map(span => normalizeSpan(truncateSpan(span))))
|
|
42
|
+
traceChannel.publish(formattedTraces)
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
done()
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = ElectronExporter
|
|
@@ -12,19 +12,21 @@ const {
|
|
|
12
12
|
resolveGitHeadSHA,
|
|
13
13
|
} = require('./config/git_properties')
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {{ commitSHA: string | undefined, repositoryUrl: string | undefined }} GitMetadata
|
|
17
|
+
* @type {{ enabled?: GitMetadata, disabled?: GitMetadata }}
|
|
18
|
+
*/
|
|
19
|
+
const cache = {}
|
|
17
20
|
|
|
18
21
|
/**
|
|
19
22
|
* @param {import('./config/config-types').ConfigProperties} config
|
|
20
23
|
*/
|
|
21
24
|
function getGitMetadata (config) {
|
|
22
|
-
if (cached) return cached
|
|
23
|
-
|
|
24
25
|
if (!config.DD_TRACE_GIT_METADATA_ENABLED) {
|
|
25
|
-
|
|
26
|
-
return
|
|
26
|
+
cache.disabled ??= { commitSHA: undefined, repositoryUrl: undefined }
|
|
27
|
+
return cache.disabled
|
|
27
28
|
}
|
|
29
|
+
if (cache.enabled) return cache.enabled
|
|
28
30
|
|
|
29
31
|
let repositoryUrl = removeUserSensitiveInfo(config.DD_GIT_REPOSITORY_URL ?? config.tags[GIT_REPOSITORY_URL])
|
|
30
32
|
let commitSHA = config.DD_GIT_COMMIT_SHA ?? config.tags[GIT_COMMIT_SHA]
|
|
@@ -59,8 +61,8 @@ function getGitMetadata (config) {
|
|
|
59
61
|
|
|
60
62
|
commitSHA ??= resolveGitHeadSHA(gitFolderPath)
|
|
61
63
|
|
|
62
|
-
|
|
63
|
-
return
|
|
64
|
+
cache.enabled = { commitSHA, repositoryUrl }
|
|
65
|
+
return cache.enabled
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
module.exports = getGitMetadata
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* Modifications copyright 2022 Datadog, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Some functions are part of aws-lambda-nodejs-runtime-interface-client
|
|
6
|
+
* https://github.com/aws/aws-lambda-nodejs-runtime-interface-client/blob/v2.1.0/src/utils/UserFunction.ts
|
|
7
|
+
*/
|
|
8
|
+
'use strict'
|
|
9
|
+
|
|
10
|
+
const path = require('path')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Example: `'./api/src/index.nested.handler'` → `['./api/src/', 'index.nested.handler']`.
|
|
14
|
+
*
|
|
15
|
+
* @param {string} fullHandler
|
|
16
|
+
*/
|
|
17
|
+
function extractModuleRootAndHandler (fullHandler) {
|
|
18
|
+
const handlerString = path.basename(fullHandler)
|
|
19
|
+
const moduleRoot = fullHandler.slice(0, Math.max(0, fullHandler.indexOf(handlerString)))
|
|
20
|
+
return [moduleRoot, handlerString]
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Example: `'index.nested.handler'` → `['index', 'nested.handler']`.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} handler
|
|
27
|
+
* @throws {Error} When the handler is not of the form `<module>.<path>`.
|
|
28
|
+
*/
|
|
29
|
+
function extractModuleNameAndHandlerPath (handler) {
|
|
30
|
+
const match = handler.match(/^([^.]*)\.(.*)$/)
|
|
31
|
+
if (!match || match.length !== 3) {
|
|
32
|
+
throw new Error(`Malformed handler name: ${handler}`)
|
|
33
|
+
}
|
|
34
|
+
return [match[1], match[2]]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {string} lambdaStylePath `LAMBDA_TASK_ROOT` joined with the module root and module name.
|
|
39
|
+
*/
|
|
40
|
+
function getLambdaFilePaths (lambdaStylePath) {
|
|
41
|
+
return [
|
|
42
|
+
`${lambdaStylePath}.js`,
|
|
43
|
+
`${lambdaStylePath}.mjs`,
|
|
44
|
+
`${lambdaStylePath}.cjs`,
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
module.exports = {
|
|
49
|
+
extractModuleRootAndHandler,
|
|
50
|
+
extractModuleNameAndHandlerPath,
|
|
51
|
+
getLambdaFilePaths,
|
|
52
|
+
}
|
|
@@ -1,17 +1,65 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
3
|
+
const path = require('path')
|
|
4
|
+
|
|
5
|
+
const log = require('../log')
|
|
6
|
+
const { getEnvironmentVariable, getValueFromEnvSources } = require('../config/helper')
|
|
7
|
+
const Hook = require('../../../datadog-instrumentations/src/helpers/hook')
|
|
8
|
+
const instrumentations = require('../../../datadog-instrumentations/src/helpers/instrumentations')
|
|
9
|
+
const {
|
|
10
|
+
filename,
|
|
11
|
+
pathSepExpr,
|
|
12
|
+
} = require('../../../datadog-instrumentations/src/helpers/register')
|
|
13
|
+
const {
|
|
14
|
+
extractModuleNameAndHandlerPath,
|
|
15
|
+
extractModuleRootAndHandler,
|
|
16
|
+
getLambdaFilePaths,
|
|
17
|
+
} = require('./handler-paths')
|
|
18
|
+
|
|
19
|
+
if (!getValueFromEnvSources('DD_TRACE_DISABLED_INSTRUMENTATIONS')?.split(',').includes('lambda')) {
|
|
20
|
+
const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
|
|
21
|
+
const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
|
|
22
|
+
|
|
23
|
+
if (originalLambdaHandler !== undefined && lambdaTaskRoot !== undefined) {
|
|
24
|
+
const [moduleRoot, moduleAndHandler] = extractModuleRootAndHandler(originalLambdaHandler)
|
|
25
|
+
const [moduleName] = extractModuleNameAndHandlerPath(moduleAndHandler)
|
|
26
|
+
|
|
27
|
+
const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, moduleName)
|
|
28
|
+
const lambdaFilePaths = getLambdaFilePaths(lambdaStylePath)
|
|
29
|
+
|
|
30
|
+
// TODO: Redo this like any other instrumentation.
|
|
31
|
+
Hook(lambdaFilePaths, (moduleExports, name, _, moduleVersion) => {
|
|
32
|
+
require('./runtime/patch')
|
|
33
|
+
|
|
34
|
+
for (const { hook } of instrumentations[name]) {
|
|
35
|
+
try {
|
|
36
|
+
moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
|
|
37
|
+
} catch (error) {
|
|
38
|
+
log.error('Error executing lambda hook', error)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return moduleExports
|
|
43
|
+
})
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const moduleToPatch = 'datadog-lambda-js'
|
|
48
|
+
Hook([moduleToPatch], (moduleExports, moduleName, _, moduleVersion) => {
|
|
49
|
+
moduleName = moduleName.replace(pathSepExpr, '/')
|
|
50
|
+
require('./runtime/patch')
|
|
51
|
+
|
|
52
|
+
for (const { file, hook } of instrumentations[moduleToPatch]) {
|
|
53
|
+
const fullFilename = filename(moduleToPatch, file)
|
|
54
|
+
if (moduleName === fullFilename) {
|
|
55
|
+
try {
|
|
56
|
+
moduleExports = hook(moduleExports, moduleVersion) ?? moduleExports
|
|
57
|
+
} catch (error) {
|
|
58
|
+
log.error('Error executing lambda hook for datadog-lambda-js', error)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return moduleExports
|
|
64
|
+
})
|
|
17
65
|
}
|
|
@@ -6,54 +6,32 @@ const { datadog } = require('../handler')
|
|
|
6
6
|
const { addHook } = require('../../../../datadog-instrumentations/src/helpers/instrument')
|
|
7
7
|
const shimmer = require('../../../../datadog-shimmer')
|
|
8
8
|
const { getEnvironmentVariable, getValueFromEnvSources } = require('../../config/helper')
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* `datadog-lambda-js` patched.
|
|
18
|
-
*/
|
|
19
|
-
const patchDatadogLambdaModule = (datadogLambdaModule) => {
|
|
9
|
+
const {
|
|
10
|
+
extractModuleNameAndHandlerPath,
|
|
11
|
+
extractModuleRootAndHandler,
|
|
12
|
+
getLambdaFilePaths,
|
|
13
|
+
} = require('../handler-paths')
|
|
14
|
+
|
|
15
|
+
/** @param {object} datadogLambdaModule */
|
|
16
|
+
function patchDatadogLambdaModule (datadogLambdaModule) {
|
|
20
17
|
shimmer.wrap(datadogLambdaModule, 'datadog', patchDatadogLambdaHandler)
|
|
21
|
-
|
|
22
18
|
return datadogLambdaModule
|
|
23
19
|
}
|
|
24
20
|
|
|
25
|
-
/**
|
|
26
|
-
* Patches a Datadog Lambda handler in order to do
|
|
27
|
-
* Datadog instrumentation by getting the Lambda handler from its
|
|
28
|
-
* arguments.
|
|
29
|
-
*
|
|
30
|
-
* @param {Function} datadogHandler the Datadog Lambda handler to destructure.
|
|
31
|
-
* @returns the datadogHandler with its arguments patched.
|
|
32
|
-
*/
|
|
21
|
+
/** @param {Function} datadogHandler */
|
|
33
22
|
function patchDatadogLambdaHandler (datadogHandler) {
|
|
34
|
-
return
|
|
35
|
-
return datadogHandler(datadog(userHandler))
|
|
36
|
-
}
|
|
23
|
+
return userHandler => datadogHandler(datadog(userHandler))
|
|
37
24
|
}
|
|
38
25
|
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const patchLambdaModule = (handlerPath) => (lambdaModule) => {
|
|
46
|
-
shimmer.wrap(lambdaModule, handlerPath, patchLambdaHandler)
|
|
47
|
-
|
|
48
|
-
return lambdaModule
|
|
26
|
+
/** @param {string} handlerPath */
|
|
27
|
+
function patchLambdaModule (handlerPath) {
|
|
28
|
+
return lambdaModule => {
|
|
29
|
+
shimmer.wrap(lambdaModule, handlerPath, patchLambdaHandler)
|
|
30
|
+
return lambdaModule
|
|
31
|
+
}
|
|
49
32
|
}
|
|
50
33
|
|
|
51
|
-
/**
|
|
52
|
-
* Patches a Lambda handler in order to do Datadog instrumentation.
|
|
53
|
-
*
|
|
54
|
-
* @param {Function} lambdaHandler the Lambda handler to be patched.
|
|
55
|
-
* @returns a function which patches the given Lambda handler.
|
|
56
|
-
*/
|
|
34
|
+
/** @param {Function} lambdaHandler */
|
|
57
35
|
function patchLambdaHandler (lambdaHandler) {
|
|
58
36
|
return datadog(lambdaHandler)
|
|
59
37
|
}
|
|
@@ -62,16 +40,13 @@ const lambdaTaskRoot = getEnvironmentVariable('LAMBDA_TASK_ROOT')
|
|
|
62
40
|
const originalLambdaHandler = getValueFromEnvSources('DD_LAMBDA_HANDLER')
|
|
63
41
|
|
|
64
42
|
if (originalLambdaHandler === undefined) {
|
|
65
|
-
// Instrumentation is done manually.
|
|
66
43
|
addHook({ name: 'datadog-lambda-js' }, patchDatadogLambdaModule)
|
|
67
44
|
} else {
|
|
68
|
-
const [moduleRoot, moduleAndHandler] =
|
|
69
|
-
const [
|
|
70
|
-
|
|
71
|
-
const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, _module)
|
|
72
|
-
const lambdaFilePaths = _getLambdaFilePaths(lambdaStylePath)
|
|
45
|
+
const [moduleRoot, moduleAndHandler] = extractModuleRootAndHandler(originalLambdaHandler)
|
|
46
|
+
const [moduleName, handlerPath] = extractModuleNameAndHandlerPath(moduleAndHandler)
|
|
73
47
|
|
|
74
|
-
|
|
48
|
+
const lambdaStylePath = path.resolve(lambdaTaskRoot, moduleRoot, moduleName)
|
|
49
|
+
for (const lambdaFilePath of getLambdaFilePaths(lambdaStylePath)) {
|
|
75
50
|
addHook({ name: lambdaFilePath }, patchLambdaModule(handlerPath))
|
|
76
51
|
}
|
|
77
52
|
}
|
|
@@ -108,6 +108,10 @@ function disable () {
|
|
|
108
108
|
// since LLMObs traces can extend between services and be the same trace,
|
|
109
109
|
// we need to propagate the parent id and mlApp.
|
|
110
110
|
function handleLLMObsParentIdInjection ({ carrier }) {
|
|
111
|
+
// Respect the standard propagator's gate: when trace tag propagation is
|
|
112
|
+
// disabled, don't write `x-datadog-tags` for LLMObs either.
|
|
113
|
+
if (globalTracerConfig.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) return
|
|
114
|
+
|
|
111
115
|
const parent = storage.getStore()?.span
|
|
112
116
|
const mlObsSpanTags = LLMObsTagger.tagMap.get(parent)
|
|
113
117
|
|
|
@@ -118,8 +122,15 @@ function handleLLMObsParentIdInjection ({ carrier }) {
|
|
|
118
122
|
parentContext?._trace?.tags?.[PROPAGATED_ML_APP_KEY] ||
|
|
119
123
|
globalTracerConfig.llmobs.mlApp
|
|
120
124
|
|
|
121
|
-
if (parentId
|
|
122
|
-
|
|
125
|
+
if (!parentId && !mlApp) return
|
|
126
|
+
|
|
127
|
+
// `_injectTags` only writes `x-datadog-tags` when the trace has `_dd.p.*`
|
|
128
|
+
// tags, so it may be undefined here — coalesce before appending.
|
|
129
|
+
const existing = carrier['x-datadog-tags']
|
|
130
|
+
let tags = existing || ''
|
|
131
|
+
if (parentId) tags += `${tags ? ',' : ''}${PROPAGATED_PARENT_ID_KEY}=${parentId}`
|
|
132
|
+
if (mlApp) tags += `${tags ? ',' : ''}${PROPAGATED_ML_APP_KEY}=${mlApp}`
|
|
133
|
+
if (tags !== existing) carrier['x-datadog-tags'] = tags
|
|
123
134
|
}
|
|
124
135
|
|
|
125
136
|
function handleFlush () {
|
|
@@ -14,7 +14,17 @@ const llmobsStore = storage('llmobs')
|
|
|
14
14
|
|
|
15
15
|
const ENABLED_OPERATIONS = new Set(['invokeModel', 'invokeModelWithResponseStream'])
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {{
|
|
19
|
+
* inputTokensFromHeaders?: number,
|
|
20
|
+
* outputTokensFromHeaders?: number,
|
|
21
|
+
* cacheReadTokensFromHeaders?: number,
|
|
22
|
+
* cacheWriteTokensFromHeaders?: number,
|
|
23
|
+
* }} HeaderTokens
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** @type {Map<string, HeaderTokens>} */
|
|
27
|
+
const pendingTokenHeaders = new Map()
|
|
18
28
|
|
|
19
29
|
class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
20
30
|
constructor () {
|
|
@@ -24,33 +34,39 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
24
34
|
const { response } = ctx
|
|
25
35
|
const request = response.request
|
|
26
36
|
const operation = request.operation
|
|
37
|
+
|
|
38
|
+
// Release the cached headers even for operations the plugin does not tag,
|
|
39
|
+
// so non-LLM Bedrock calls do not leak entries into pendingTokenHeaders.
|
|
40
|
+
const tokensFromHeaders = consumeTokenHeaders(response.$metadata?.requestId)
|
|
41
|
+
|
|
27
42
|
// avoids instrumenting other non supported runtime operations
|
|
28
|
-
if (!ENABLED_OPERATIONS.has(operation))
|
|
29
|
-
|
|
30
|
-
}
|
|
43
|
+
if (!ENABLED_OPERATIONS.has(operation)) return
|
|
44
|
+
|
|
31
45
|
const { modelProvider, modelName } = parseModelId(request.params.modelId)
|
|
32
46
|
|
|
33
47
|
// avoids instrumenting non llm type
|
|
34
|
-
if (modelName.includes('embed'))
|
|
35
|
-
|
|
36
|
-
}
|
|
48
|
+
if (modelName.includes('embed')) return
|
|
49
|
+
|
|
37
50
|
const span = ctx.currentStore?.span
|
|
38
|
-
this.setLLMObsTags({ ctx, request, span, response, modelProvider, modelName })
|
|
51
|
+
this.setLLMObsTags({ ctx, request, span, response, modelProvider, modelName, tokensFromHeaders })
|
|
39
52
|
})
|
|
40
53
|
|
|
41
54
|
this.addSub('apm:aws:response:deserialize:bedrockruntime', ({ headers }) => {
|
|
42
55
|
const requestId = headers['x-amzn-requestid']
|
|
56
|
+
// No request id means no way to correlate with the :complete: event.
|
|
57
|
+
if (!requestId) return
|
|
58
|
+
|
|
43
59
|
const inputTokenCount = headers['x-amzn-bedrock-input-token-count']
|
|
44
60
|
const outputTokenCount = headers['x-amzn-bedrock-output-token-count']
|
|
45
61
|
const cacheReadTokenCount = headers['x-amzn-bedrock-cache-read-input-token-count']
|
|
46
62
|
const cacheWriteTokenCount = headers['x-amzn-bedrock-cache-write-input-token-count']
|
|
47
63
|
|
|
48
|
-
|
|
64
|
+
pendingTokenHeaders.set(requestId, {
|
|
49
65
|
inputTokensFromHeaders: inputTokenCount && Number.parseInt(inputTokenCount),
|
|
50
66
|
outputTokensFromHeaders: outputTokenCount && Number.parseInt(outputTokenCount),
|
|
51
67
|
cacheReadTokensFromHeaders: cacheReadTokenCount && Number.parseInt(cacheReadTokenCount),
|
|
52
68
|
cacheWriteTokensFromHeaders: cacheWriteTokenCount && Number.parseInt(cacheWriteTokenCount),
|
|
53
|
-
}
|
|
69
|
+
})
|
|
54
70
|
})
|
|
55
71
|
|
|
56
72
|
this.addSub('apm:aws:response:streamed-chunk:bedrockruntime', ({ ctx, chunk }) => {
|
|
@@ -60,7 +76,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
60
76
|
})
|
|
61
77
|
}
|
|
62
78
|
|
|
63
|
-
setLLMObsTags ({ ctx, request, span, response, modelProvider, modelName }) {
|
|
79
|
+
setLLMObsTags ({ ctx, request, span, response, modelProvider, modelName, tokensFromHeaders }) {
|
|
64
80
|
const isStream = request?.operation?.toLowerCase().includes('stream')
|
|
65
81
|
telemetry.incrementLLMObsSpanStartCount({ autoinstrumented: true, integration: 'bedrock' })
|
|
66
82
|
|
|
@@ -97,7 +113,7 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
97
113
|
|
|
98
114
|
// add token metrics
|
|
99
115
|
const { inputTokens, outputTokens, totalTokens, cacheReadTokens, cacheWriteTokens } = extractTokens({
|
|
100
|
-
|
|
116
|
+
tokensFromHeaders,
|
|
101
117
|
usage: textAndResponseReason.usage,
|
|
102
118
|
})
|
|
103
119
|
this._tagger.tagMetrics(span, {
|
|
@@ -110,14 +126,28 @@ class BedrockRuntimeLLMObsPlugin extends BaseLLMObsPlugin {
|
|
|
110
126
|
}
|
|
111
127
|
}
|
|
112
128
|
|
|
113
|
-
|
|
129
|
+
/**
|
|
130
|
+
* @param {string | undefined} requestId
|
|
131
|
+
* @returns {HeaderTokens | undefined}
|
|
132
|
+
*/
|
|
133
|
+
function consumeTokenHeaders (requestId) {
|
|
134
|
+
const tokens = pendingTokenHeaders.get(requestId)
|
|
135
|
+
pendingTokenHeaders.delete(requestId)
|
|
136
|
+
return tokens
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Combine response-body usage with header-derived counts, preferring the body.
|
|
141
|
+
*
|
|
142
|
+
* @param {{ tokensFromHeaders: HeaderTokens | undefined, usage: Record<string, number | undefined> }} options
|
|
143
|
+
*/
|
|
144
|
+
function extractTokens ({ tokensFromHeaders, usage }) {
|
|
114
145
|
const {
|
|
115
146
|
inputTokensFromHeaders,
|
|
116
147
|
outputTokensFromHeaders,
|
|
117
148
|
cacheReadTokensFromHeaders,
|
|
118
149
|
cacheWriteTokensFromHeaders,
|
|
119
|
-
} =
|
|
120
|
-
delete requestIdsToTokens[requestId]
|
|
150
|
+
} = tokensFromHeaders ?? {}
|
|
121
151
|
|
|
122
152
|
const inputTokens = usage.inputTokens || inputTokensFromHeaders || 0
|
|
123
153
|
const outputTokens = usage.outputTokens || outputTokensFromHeaders || 0
|
|
@@ -54,7 +54,8 @@ class BaseLLMObsWriter {
|
|
|
54
54
|
|
|
55
55
|
this._periodic = setInterval(() => {
|
|
56
56
|
this.flush()
|
|
57
|
-
}, this._interval)
|
|
57
|
+
}, this._interval)
|
|
58
|
+
this._periodic.unref?.()
|
|
58
59
|
|
|
59
60
|
const destroyer = this.destroy.bind(this)
|
|
60
61
|
globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(destroyer)
|
|
@@ -55,7 +55,8 @@ class BaseFFEWriter {
|
|
|
55
55
|
|
|
56
56
|
this._periodic = setInterval(() => {
|
|
57
57
|
this.flush()
|
|
58
|
-
}, this._interval)
|
|
58
|
+
}, this._interval)
|
|
59
|
+
this._periodic.unref?.()
|
|
59
60
|
|
|
60
61
|
const destroyer = this.destroy.bind(this)
|
|
61
62
|
globalThis[Symbol.for('dd-trace')].beforeExitHandlers.add(destroyer)
|
|
@@ -9,6 +9,7 @@ const tags = require('../../../../../ext/tags')
|
|
|
9
9
|
const { getConfiguredEnvName } = require('../../config/helper')
|
|
10
10
|
const { setAllBaggageItems, getAllBaggageItems, removeAllBaggageItems } = require('../../baggage')
|
|
11
11
|
const telemetryMetrics = require('../../telemetry/metrics')
|
|
12
|
+
const { DD_MAJOR } = require('../../../../../version')
|
|
12
13
|
|
|
13
14
|
const { AUTO_KEEP, AUTO_REJECT, USER_KEEP } = require('../../../../../ext/priority')
|
|
14
15
|
const TraceState = require('./tracestate')
|
|
@@ -78,10 +79,17 @@ class TextMapPropagator {
|
|
|
78
79
|
constructor (config) {
|
|
79
80
|
this._config = config
|
|
80
81
|
|
|
81
|
-
//
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
// v6: `'b3'` is always single-header. v5: env-name decides — OTEL_PROPAGATORS callers expect
|
|
83
|
+
// single, the legacy `DD_TRACE_PROPAGATION_STYLE` callers expect multi.
|
|
84
|
+
if (DD_MAJOR >= 6) {
|
|
85
|
+
this.#extractB3Context = this._extractB3SingleContext
|
|
86
|
+
} else {
|
|
87
|
+
const envName = getConfiguredEnvName('DD_TRACE_PROPAGATION_STYLE')
|
|
88
|
+
// eslint-disable-next-line eslint-rules/eslint-env-aliases
|
|
89
|
+
this.#extractB3Context = envName === 'OTEL_PROPAGATORS'
|
|
90
|
+
? this._extractB3SingleContext
|
|
91
|
+
: this._extractB3MultiContext
|
|
92
|
+
}
|
|
85
93
|
}
|
|
86
94
|
|
|
87
95
|
/**
|
|
@@ -262,9 +270,10 @@ class TextMapPropagator {
|
|
|
262
270
|
}
|
|
263
271
|
|
|
264
272
|
_injectB3MultipleHeaders (spanContext, carrier) {
|
|
265
|
-
|
|
266
|
-
const hasB3multi = this._hasPropagationStyle('inject', 'b3multi')
|
|
267
|
-
|
|
273
|
+
// v5 also accepts the legacy `'b3'` spelling for multi; v6 routes `'b3'` to single-header.
|
|
274
|
+
const hasB3multi = this._hasPropagationStyle('inject', 'b3multi') ||
|
|
275
|
+
(DD_MAJOR < 6 && this._hasPropagationStyle('inject', 'b3'))
|
|
276
|
+
if (!hasB3multi) return
|
|
268
277
|
|
|
269
278
|
carrier[b3TraceKey] = this._getB3TraceId(spanContext)
|
|
270
279
|
carrier[b3SpanKey] = spanContext._spanId.toString(16)
|
|
@@ -280,7 +289,9 @@ class TextMapPropagator {
|
|
|
280
289
|
}
|
|
281
290
|
|
|
282
291
|
_injectB3SingleHeader (spanContext, carrier) {
|
|
283
|
-
|
|
292
|
+
// v6 keeps `'b3 single header'` as a back-compat alias for callers that bypass parser normalisation.
|
|
293
|
+
const hasB3SingleHeader = this._hasPropagationStyle('inject', 'b3 single header') ||
|
|
294
|
+
(DD_MAJOR >= 6 && this._hasPropagationStyle('inject', 'b3'))
|
|
284
295
|
if (!hasB3SingleHeader) return null
|
|
285
296
|
|
|
286
297
|
const traceId = this._getB3TraceId(spanContext)
|
|
@@ -394,7 +405,7 @@ class TextMapPropagator {
|
|
|
394
405
|
case 'tracecontext':
|
|
395
406
|
extractedContext = this._extractTraceparentContext(carrier)
|
|
396
407
|
break
|
|
397
|
-
case 'b3 single header':
|
|
408
|
+
case 'b3 single header':
|
|
398
409
|
extractedContext = this._extractB3SingleContext(carrier)
|
|
399
410
|
break
|
|
400
411
|
case 'b3':
|
|
@@ -30,8 +30,8 @@ function getSDKRules (sdk, requestInput, responseInput) {
|
|
|
30
30
|
* Appends input rules to all supported SDKs and returns a structure mapping SDK
|
|
31
31
|
* names to per-service rules.
|
|
32
32
|
*
|
|
33
|
-
* @param {string[]} [requestInput
|
|
34
|
-
* @param {string[]} [responseInput
|
|
33
|
+
* @param {string[]} [requestInput]
|
|
34
|
+
* @param {string[]} [responseInput]
|
|
35
35
|
* @returns {Record<string, SDKRules>}
|
|
36
36
|
*/
|
|
37
37
|
function appendRules (requestInput = [], responseInput = []) {
|