dd-trace 5.62.0 → 5.63.1
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 -5
- package/package.json +2 -2
- package/packages/datadog-instrumentations/src/ai.js +140 -0
- package/packages/datadog-instrumentations/src/couchbase.js +102 -65
- package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
- package/packages/datadog-instrumentations/src/helpers/register.js +2 -22
- package/packages/datadog-instrumentations/src/hono.js +11 -8
- package/packages/datadog-instrumentations/src/knex.js +15 -17
- package/packages/datadog-instrumentations/src/moleculer/client.js +2 -3
- package/packages/datadog-instrumentations/src/mongodb-core.js +4 -6
- package/packages/datadog-instrumentations/src/next.js +4 -8
- package/packages/datadog-instrumentations/src/pg.js +38 -48
- package/packages/datadog-plugin-aerospike/src/index.js +6 -2
- package/packages/datadog-plugin-ai/src/index.js +17 -0
- package/packages/datadog-plugin-ai/src/tracing.js +33 -0
- package/packages/datadog-plugin-ai/src/utils.js +28 -0
- package/packages/datadog-plugin-couchbase/src/index.js +37 -17
- package/packages/datadog-plugin-pg/src/index.js +5 -2
- package/packages/dd-trace/src/appsec/iast/analyzers/sql-injection-analyzer.js +14 -7
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +3 -3
- package/packages/dd-trace/src/appsec/recommended.json +271 -2
- package/packages/dd-trace/src/guardrails/telemetry.js +18 -2
- package/packages/dd-trace/src/llmobs/plugins/ai/index.js +351 -0
- package/packages/dd-trace/src/llmobs/plugins/ai/util.js +179 -0
- package/packages/dd-trace/src/llmobs/writers/base.js +8 -3
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +2 -2
- package/packages/dd-trace/src/opentracing/span_context.js +4 -0
- package/packages/dd-trace/src/plugin_manager.js +8 -4
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/util/ip_extractor.js +44 -3
- package/packages/dd-trace/src/profiling/profilers/event_plugins/event.js +24 -23
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -2
- package/packages/dd-trace/src/profiling/profilers/wall.js +2 -2
- package/packages/dd-trace/src/supported-configurations.json +6 -0
- package/packages/dd-trace/src/tracer_metadata.js +1 -1
package/README.md
CHANGED
|
@@ -22,11 +22,6 @@ Most of the documentation for `dd-trace` is available on these webpages:
|
|
|
22
22
|
|
|
23
23
|
## Version Release Lines and Maintenance
|
|
24
24
|
|
|
25
|
-
> **Node.js v24 Notice**: We're currently adding compatibility for Node.js v24. To use the tracer with your application either continue to use Node.js v22 (LTS), or do both of the following as a workaround:
|
|
26
|
-
> * Install v5.52.0 (or newer) of the tracer
|
|
27
|
-
> * Set `--no-async-context-frame` either using a CLI argument or via `NODE_OPTIONS`
|
|
28
|
-
> Once support for Node.js v24 is complete this flag will no longer be needed.
|
|
29
|
-
|
|
30
25
|
| Release Line | Latest Version | Node.js | [SSI](https://docs.datadoghq.com/tracing/trace_collection/automatic_instrumentation/single-step-apm/?tab=linuxhostorvm) | [K8s Injection](https://docs.datadoghq.com/tracing/trace_collection/library_injection_local/?tab=kubernetes) |Status |Initial Release | End of Life |
|
|
31
26
|
| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
|
32
27
|
| [`v1`](https://github.com/DataDog/dd-trace-js/tree/v1.x) |  | `>= v12` | NO | NO | **EOL** | 2021-07-13 | 2022-02-25 |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dd-trace",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.63.1",
|
|
4
4
|
"description": "Datadog APM tracing client for JavaScript",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"typings": "index.d.ts",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
],
|
|
115
115
|
"dependencies": {
|
|
116
116
|
"@datadog/libdatadog": "0.7.0",
|
|
117
|
-
"@datadog/native-appsec": "10.0
|
|
117
|
+
"@datadog/native-appsec": "10.1.0",
|
|
118
118
|
"@datadog/native-iast-taint-tracking": "4.0.0",
|
|
119
119
|
"@datadog/native-metrics": "3.1.1",
|
|
120
120
|
"@datadog/pprof": "5.9.0",
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { addHook } = require('./helpers/instrument')
|
|
4
|
+
const shimmer = require('../../datadog-shimmer')
|
|
5
|
+
|
|
6
|
+
const { channel, tracingChannel } = require('dc-polyfill')
|
|
7
|
+
const toolCreationChannel = channel('dd-trace:vercel-ai:tool')
|
|
8
|
+
|
|
9
|
+
const TRACED_FUNCTIONS = {
|
|
10
|
+
generateText: wrapWithTracer,
|
|
11
|
+
streamText: wrapWithTracer,
|
|
12
|
+
generateObject: wrapWithTracer,
|
|
13
|
+
streamObject: wrapWithTracer,
|
|
14
|
+
embed: wrapWithTracer,
|
|
15
|
+
embedMany: wrapWithTracer,
|
|
16
|
+
tool: wrapTool
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const vercelAiTracingChannel = tracingChannel('dd-trace:vercel-ai')
|
|
20
|
+
const vercelAiSpanSetAttributesChannel = channel('dd-trace:vercel-ai:span:setAttributes')
|
|
21
|
+
|
|
22
|
+
const noopTracer = {
|
|
23
|
+
startActiveSpan () {
|
|
24
|
+
const fn = arguments[arguments.length - 1]
|
|
25
|
+
|
|
26
|
+
const span = {
|
|
27
|
+
spanContext () { return { traceId: '', spanId: '', traceFlags: 0 } },
|
|
28
|
+
setAttribute () { return this },
|
|
29
|
+
setAttributes () { return this },
|
|
30
|
+
addEvent () { return this },
|
|
31
|
+
addLink () { return this },
|
|
32
|
+
addLinks () { return this },
|
|
33
|
+
setStatus () { return this },
|
|
34
|
+
updateName () { return this },
|
|
35
|
+
end () { return this },
|
|
36
|
+
isRecording () { return false },
|
|
37
|
+
recordException () { return this }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return fn(span)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function wrapTracer (tracer) {
|
|
45
|
+
if (Object.hasOwn(tracer, Symbol.for('_dd.wrapped'))) return
|
|
46
|
+
|
|
47
|
+
shimmer.wrap(tracer, 'startActiveSpan', function (startActiveSpan) {
|
|
48
|
+
return function () {
|
|
49
|
+
const name = arguments[0]
|
|
50
|
+
const options = arguments.length > 2 ? (arguments[1] ?? {}) : {} // startActiveSpan(name, fn)
|
|
51
|
+
const cb = arguments[arguments.length - 1]
|
|
52
|
+
|
|
53
|
+
const ctx = {
|
|
54
|
+
name,
|
|
55
|
+
attributes: options.attributes ?? {}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
arguments[arguments.length - 1] = shimmer.wrapFunction(cb, function (originalCb) {
|
|
59
|
+
return function (span) {
|
|
60
|
+
shimmer.wrap(span, 'end', function (spanEnd) {
|
|
61
|
+
return function () {
|
|
62
|
+
vercelAiTracingChannel.asyncEnd.publish(ctx)
|
|
63
|
+
return spanEnd.apply(this, arguments)
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
shimmer.wrap(span, 'setAttributes', function (setAttributes) {
|
|
68
|
+
return function (attributes) {
|
|
69
|
+
vercelAiSpanSetAttributesChannel.publish({ ctx, attributes })
|
|
70
|
+
return setAttributes.apply(this, arguments)
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
shimmer.wrap(span, 'recordException', function (recordException) {
|
|
75
|
+
return function (exception) {
|
|
76
|
+
ctx.error = exception
|
|
77
|
+
vercelAiTracingChannel.error.publish(ctx)
|
|
78
|
+
return recordException.apply(this, arguments)
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
return originalCb.apply(this, arguments)
|
|
83
|
+
}
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return vercelAiTracingChannel.start.runStores(ctx, () => {
|
|
87
|
+
const result = startActiveSpan.apply(this, arguments)
|
|
88
|
+
vercelAiTracingChannel.end.publish(ctx)
|
|
89
|
+
return result
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
Object.defineProperty(tracer, Symbol.for('_dd.wrapped'), { value: true })
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function wrapWithTracer (fn) {
|
|
98
|
+
return function () {
|
|
99
|
+
const options = arguments[0]
|
|
100
|
+
|
|
101
|
+
options.experimental_telemetry ??= { isEnabled: true, tracer: noopTracer }
|
|
102
|
+
wrapTracer(options.experimental_telemetry.tracer)
|
|
103
|
+
|
|
104
|
+
return fn.apply(this, arguments)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function wrapTool (tool) {
|
|
109
|
+
return function () {
|
|
110
|
+
const args = arguments[0]
|
|
111
|
+
toolCreationChannel.publish(args)
|
|
112
|
+
|
|
113
|
+
return tool.apply(this, arguments)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// CJS exports
|
|
118
|
+
addHook({
|
|
119
|
+
name: 'ai',
|
|
120
|
+
versions: ['>=4.0.0'],
|
|
121
|
+
}, exports => {
|
|
122
|
+
for (const [fnName, patchingFn] of Object.entries(TRACED_FUNCTIONS)) {
|
|
123
|
+
exports = shimmer.wrap(exports, fnName, patchingFn, { replaceGetter: true })
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return exports
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
// ESM exports
|
|
130
|
+
addHook({
|
|
131
|
+
name: 'ai',
|
|
132
|
+
versions: ['>=4.0.0'],
|
|
133
|
+
file: 'dist/index.mjs'
|
|
134
|
+
}, exports => {
|
|
135
|
+
for (const [fnName, patchingFn] of Object.entries(TRACED_FUNCTIONS)) {
|
|
136
|
+
exports = shimmer.wrap(exports, fnName, patchingFn, { replaceGetter: true })
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return exports
|
|
140
|
+
})
|
|
@@ -3,8 +3,7 @@
|
|
|
3
3
|
const { errorMonitor } = require('events')
|
|
4
4
|
const {
|
|
5
5
|
channel,
|
|
6
|
-
addHook
|
|
7
|
-
AsyncResource
|
|
6
|
+
addHook
|
|
8
7
|
} = require('./helpers/instrument')
|
|
9
8
|
const shimmer = require('../../datadog-shimmer')
|
|
10
9
|
|
|
@@ -24,31 +23,50 @@ function wrapAllNames (names, action) {
|
|
|
24
23
|
names.forEach(name => action(name))
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments)
|
|
31
|
-
|
|
32
|
-
const callbackIndex = args.length - 1
|
|
33
|
-
const callback = args[callbackIndex]
|
|
26
|
+
function wrapCallback (callback, ctx, channelPrefix) {
|
|
27
|
+
const callbackStartCh = channel(`${channelPrefix}:callback:start`)
|
|
28
|
+
const callbackFinishCh = channel(`${channelPrefix}:callback:finish`)
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
30
|
+
const wrapped = callbackStartCh.runStores(ctx, () => {
|
|
31
|
+
return function (...args) {
|
|
32
|
+
return callbackFinishCh.runStores(ctx, () => {
|
|
33
|
+
return callback.apply(this, args)
|
|
34
|
+
})
|
|
37
35
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
36
|
+
})
|
|
37
|
+
Object.defineProperty(wrapped, '_dd_wrapped', { value: true })
|
|
41
38
|
return wrapped
|
|
42
39
|
}
|
|
43
40
|
|
|
44
41
|
function wrapQuery (query) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
return function (q, params, callback) {
|
|
43
|
+
const cb = arguments[arguments.length - 1]
|
|
44
|
+
if (typeof cb === 'function') {
|
|
45
|
+
const ctx = {}
|
|
46
|
+
arguments[arguments.length - 1] = wrapCallback(cb, ctx, 'apm:couchbase:query')
|
|
48
47
|
}
|
|
49
48
|
|
|
50
49
|
return query.apply(this, arguments)
|
|
51
50
|
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function wrapCallbackFinish (callback, thisArg, _args, errorCh, finishCh, ctx, channelPrefix) {
|
|
54
|
+
const callbackStartCh = channel(`${channelPrefix}:callback:start`)
|
|
55
|
+
const callbackFinishCh = channel(`${channelPrefix}:callback:finish`)
|
|
56
|
+
|
|
57
|
+
const wrapped = callbackStartCh.runStores(ctx, () => {
|
|
58
|
+
return function finish (error, result) {
|
|
59
|
+
return callbackFinishCh.runStores(ctx, () => {
|
|
60
|
+
if (error) {
|
|
61
|
+
ctx.error = error
|
|
62
|
+
errorCh.publish(ctx)
|
|
63
|
+
}
|
|
64
|
+
finishCh.publish(ctx)
|
|
65
|
+
return callback.apply(thisArg, [error, result])
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
Object.defineProperty(wrapped, '_dd_wrapped', { value: true })
|
|
52
70
|
return wrapped
|
|
53
71
|
}
|
|
54
72
|
|
|
@@ -62,31 +80,24 @@ function wrap (prefix, fn) {
|
|
|
62
80
|
return fn.apply(this, arguments)
|
|
63
81
|
}
|
|
64
82
|
|
|
65
|
-
const callbackIndex = findCallbackIndex(arguments)
|
|
83
|
+
const callbackIndex = findCallbackIndex(arguments, 1)
|
|
66
84
|
|
|
67
85
|
if (callbackIndex < 0) return fn.apply(this, arguments)
|
|
68
86
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
return asyncResource.runInAsyncScope(() => {
|
|
73
|
-
const cb = callbackResource.bind(arguments[callbackIndex])
|
|
87
|
+
const ctx = { bucket: { name: this.name || this._name }, seedNodes: this._dd_hosts }
|
|
88
|
+
return startCh.runStores(ctx, () => {
|
|
89
|
+
const cb = arguments[callbackIndex]
|
|
74
90
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
if (error) {
|
|
79
|
-
errorCh.publish(error)
|
|
80
|
-
}
|
|
81
|
-
finishCh.publish(result)
|
|
82
|
-
return cb.apply(this, arguments)
|
|
83
|
-
}))
|
|
91
|
+
arguments[callbackIndex] = shimmer.wrapFunction(cb, (cb) => {
|
|
92
|
+
return wrapCallbackFinish(cb, this, arguments, errorCh, finishCh, ctx, prefix)
|
|
93
|
+
})
|
|
84
94
|
|
|
85
95
|
try {
|
|
86
96
|
return fn.apply(this, arguments)
|
|
87
97
|
} catch (error) {
|
|
98
|
+
ctx.error = error
|
|
88
99
|
error.stack // trigger getting the stack at the original throwing point
|
|
89
|
-
errorCh.publish(
|
|
100
|
+
errorCh.publish(ctx)
|
|
90
101
|
|
|
91
102
|
throw error
|
|
92
103
|
}
|
|
@@ -95,6 +106,26 @@ function wrap (prefix, fn) {
|
|
|
95
106
|
return wrapped
|
|
96
107
|
}
|
|
97
108
|
|
|
109
|
+
// semver >=2 <3
|
|
110
|
+
function wrapMaybeInvoke (_maybeInvoke, channelPrefix) {
|
|
111
|
+
return function (fn, args) {
|
|
112
|
+
if (!Array.isArray(args)) return _maybeInvoke.apply(this, arguments)
|
|
113
|
+
|
|
114
|
+
const callbackIndex = findCallbackIndex(args, 0)
|
|
115
|
+
|
|
116
|
+
if (callbackIndex === -1) return _maybeInvoke.apply(this, arguments)
|
|
117
|
+
|
|
118
|
+
const callback = args[callbackIndex]
|
|
119
|
+
|
|
120
|
+
if (typeof callback === 'function' && !callback._dd_wrapped) {
|
|
121
|
+
const ctx = {}
|
|
122
|
+
args[callbackIndex] = wrapCallback(callback, ctx, channelPrefix)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return _maybeInvoke.apply(this, arguments)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
98
129
|
// semver >=3
|
|
99
130
|
|
|
100
131
|
function wrapCBandPromise (fn, name, startData, thisArg, args) {
|
|
@@ -104,36 +135,36 @@ function wrapCBandPromise (fn, name, startData, thisArg, args) {
|
|
|
104
135
|
|
|
105
136
|
if (!startCh.hasSubscribers) return fn.apply(thisArg, args)
|
|
106
137
|
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return asyncResource.runInAsyncScope(() => {
|
|
111
|
-
startCh.publish(startData)
|
|
112
|
-
|
|
138
|
+
const ctx = startData
|
|
139
|
+
return startCh.runStores(ctx, () => {
|
|
113
140
|
try {
|
|
114
141
|
const cbIndex = findCallbackIndex(args, 1)
|
|
115
142
|
if (cbIndex >= 0) {
|
|
116
143
|
// v3 offers callback or promises event handling
|
|
117
144
|
// NOTE: this does not work with v3.2.0-3.2.1 cluster.query, as there is a bug in the couchbase source code
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
errorCh.publish(error)
|
|
122
|
-
}
|
|
123
|
-
finishCh.publish({ result })
|
|
124
|
-
return cb.apply(thisArg, arguments)
|
|
125
|
-
}))
|
|
145
|
+
args[cbIndex] = shimmer.wrapFunction(args[cbIndex], (cb) => {
|
|
146
|
+
return wrapCallbackFinish(cb, thisArg, args, errorCh, finishCh, ctx, `apm:couchbase:${name}`)
|
|
147
|
+
})
|
|
126
148
|
}
|
|
127
149
|
const res = fn.apply(thisArg, args)
|
|
128
150
|
|
|
129
151
|
// semver >=3 will always return promise by default
|
|
130
152
|
res.then(
|
|
131
|
-
|
|
132
|
-
|
|
153
|
+
(result) => {
|
|
154
|
+
ctx.result = result
|
|
155
|
+
finishCh.publish(ctx)
|
|
156
|
+
},
|
|
157
|
+
(err) => {
|
|
158
|
+
ctx.error = err
|
|
159
|
+
errorCh.publish(ctx)
|
|
160
|
+
finishCh.publish(ctx)
|
|
161
|
+
}
|
|
162
|
+
)
|
|
133
163
|
return res
|
|
134
164
|
} catch (e) {
|
|
135
165
|
e.stack
|
|
136
|
-
|
|
166
|
+
ctx.error = e
|
|
167
|
+
errorCh.publish(ctx)
|
|
137
168
|
throw e
|
|
138
169
|
}
|
|
139
170
|
})
|
|
@@ -160,11 +191,14 @@ function wrapV3Query (query) {
|
|
|
160
191
|
|
|
161
192
|
// semver >=2 <3
|
|
162
193
|
addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.12'] }, Bucket => {
|
|
194
|
+
shimmer.wrap(Bucket.prototype, '_maybeInvoke', maybeInvoke => {
|
|
195
|
+
return wrapMaybeInvoke(maybeInvoke, 'apm:couchbase:bucket:maybeInvoke')
|
|
196
|
+
})
|
|
197
|
+
|
|
163
198
|
const startCh = channel('apm:couchbase:query:start')
|
|
164
199
|
const finishCh = channel('apm:couchbase:query:finish')
|
|
165
200
|
const errorCh = channel('apm:couchbase:query:error')
|
|
166
201
|
|
|
167
|
-
shimmer.wrap(Bucket.prototype, '_maybeInvoke', maybeInvoke => wrapMaybeInvoke(maybeInvoke))
|
|
168
202
|
shimmer.wrap(Bucket.prototype, 'query', query => wrapQuery(query))
|
|
169
203
|
|
|
170
204
|
shimmer.wrap(Bucket.prototype, '_n1qlReq', _n1qlReq => function (host, q, adhoc, emitter) {
|
|
@@ -176,24 +210,25 @@ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.12'] }, Buc
|
|
|
176
210
|
|
|
177
211
|
const n1qlQuery = getQueryResource(q)
|
|
178
212
|
|
|
179
|
-
const
|
|
180
|
-
return
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
finishCh.publish()
|
|
185
|
-
}))
|
|
213
|
+
const ctx = { resource: n1qlQuery, bucket: { name: this.name || this._name }, seedNodes: this._dd_hosts }
|
|
214
|
+
return startCh.runStores(ctx, () => {
|
|
215
|
+
emitter.once('rows', () => {
|
|
216
|
+
finishCh.publish(ctx)
|
|
217
|
+
})
|
|
186
218
|
|
|
187
|
-
emitter.once(errorMonitor,
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
219
|
+
emitter.once(errorMonitor, (error) => {
|
|
220
|
+
if (!error) return
|
|
221
|
+
ctx.error = error
|
|
222
|
+
errorCh.publish(ctx)
|
|
223
|
+
finishCh.publish(ctx)
|
|
224
|
+
})
|
|
191
225
|
|
|
192
226
|
try {
|
|
193
227
|
return _n1qlReq.apply(this, arguments)
|
|
194
228
|
} catch (err) {
|
|
195
229
|
err.stack // trigger getting the stack at the original throwing point
|
|
196
|
-
|
|
230
|
+
ctx.error = err
|
|
231
|
+
errorCh.publish(ctx)
|
|
197
232
|
|
|
198
233
|
throw err
|
|
199
234
|
}
|
|
@@ -208,9 +243,11 @@ addHook({ name: 'couchbase', file: 'lib/bucket.js', versions: ['^2.6.12'] }, Buc
|
|
|
208
243
|
})
|
|
209
244
|
|
|
210
245
|
addHook({ name: 'couchbase', file: 'lib/cluster.js', versions: ['^2.6.12'] }, Cluster => {
|
|
211
|
-
shimmer.wrap(Cluster.prototype, '_maybeInvoke', maybeInvoke =>
|
|
212
|
-
|
|
246
|
+
shimmer.wrap(Cluster.prototype, '_maybeInvoke', maybeInvoke => {
|
|
247
|
+
return wrapMaybeInvoke(maybeInvoke, 'apm:couchbase:cluster:maybeInvoke')
|
|
248
|
+
})
|
|
213
249
|
|
|
250
|
+
shimmer.wrap(Cluster.prototype, 'query', query => wrapQuery(query))
|
|
214
251
|
shimmer.wrap(Cluster.prototype, 'openBucket', openBucket => {
|
|
215
252
|
return function () {
|
|
216
253
|
const bucket = openBucket.apply(this, arguments)
|
|
@@ -30,6 +30,7 @@ module.exports = {
|
|
|
30
30
|
'@smithy/smithy-client': () => require('../aws-sdk'),
|
|
31
31
|
'@vitest/runner': { esmFirst: true, fn: () => require('../vitest') },
|
|
32
32
|
aerospike: () => require('../aerospike'),
|
|
33
|
+
ai: () => require('../ai'),
|
|
33
34
|
amqp10: () => require('../amqp10'),
|
|
34
35
|
amqplib: () => require('../amqplib'),
|
|
35
36
|
avsc: () => require('../avsc'),
|
|
@@ -9,7 +9,6 @@ const log = require('../../../dd-trace/src/log')
|
|
|
9
9
|
const checkRequireCache = require('./check-require-cache')
|
|
10
10
|
const telemetry = require('../../../dd-trace/src/guardrails/telemetry')
|
|
11
11
|
const { isInServerlessEnvironment } = require('../../../dd-trace/src/serverless')
|
|
12
|
-
const { isFalse, isTrue, normalizePluginEnvName } = require('../../../dd-trace/src/util')
|
|
13
12
|
const { getEnvironmentVariables } = require('../../../dd-trace/src/config-helper')
|
|
14
13
|
|
|
15
14
|
const envs = getEnvironmentVariables()
|
|
@@ -25,22 +24,8 @@ const names = Object.keys(hooks)
|
|
|
25
24
|
const pathSepExpr = new RegExp(`\\${path.sep}`, 'g')
|
|
26
25
|
|
|
27
26
|
const disabledInstrumentations = new Set(
|
|
28
|
-
DD_TRACE_DISABLED_INSTRUMENTATIONS?.split(',')
|
|
27
|
+
DD_TRACE_DISABLED_INSTRUMENTATIONS?.split(',')
|
|
29
28
|
)
|
|
30
|
-
const reenabledInstrumentations = new Set()
|
|
31
|
-
|
|
32
|
-
// Check for DD_TRACE_<INTEGRATION>_ENABLED environment variables
|
|
33
|
-
for (const [key, value] of Object.entries(envs)) {
|
|
34
|
-
const match = key.match(/^DD_TRACE_(.+)_ENABLED$/)
|
|
35
|
-
if (match && value) {
|
|
36
|
-
const integration = normalizePluginEnvName(match[1], true)
|
|
37
|
-
if (isFalse(value)) {
|
|
38
|
-
disabledInstrumentations.add(integration)
|
|
39
|
-
} else if (isTrue(value)) {
|
|
40
|
-
reenabledInstrumentations.add(integration)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
29
|
|
|
45
30
|
const loadChannel = channel('dd-trace:instrumentation:load')
|
|
46
31
|
|
|
@@ -65,8 +50,7 @@ const allInstrumentations = {}
|
|
|
65
50
|
|
|
66
51
|
// TODO: make this more efficient
|
|
67
52
|
for (const packageName of names) {
|
|
68
|
-
|
|
69
|
-
if (disabledInstrumentations.has(normalizedPackageName)) continue
|
|
53
|
+
if (disabledInstrumentations.has(packageName)) continue
|
|
70
54
|
|
|
71
55
|
const hookOptions = {}
|
|
72
56
|
|
|
@@ -75,10 +59,6 @@ for (const packageName of names) {
|
|
|
75
59
|
if (hook !== null && typeof hook === 'object') {
|
|
76
60
|
if (hook.serverless === false && isInServerlessEnvironment()) continue
|
|
77
61
|
|
|
78
|
-
// some integrations are disabled by default, but can be enabled by setting
|
|
79
|
-
// the DD_TRACE_<INTEGRATION>_ENABLED environment variable to true
|
|
80
|
-
if (hook.disabled && !reenabledInstrumentations.has(normalizedPackageName)) continue
|
|
81
|
-
|
|
82
62
|
hookOptions.internals = hook.esmFirst
|
|
83
63
|
hook = hook.fn
|
|
84
64
|
}
|
|
@@ -17,8 +17,14 @@ function wrapFetch (fetch) {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
function onErrorFn (error, _context_) {
|
|
21
|
+
throw error
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
function wrapCompose (compose) {
|
|
21
|
-
return function (
|
|
25
|
+
return function (middlewares, onError, onNotFound) {
|
|
26
|
+
onError ??= onErrorFn
|
|
27
|
+
|
|
22
28
|
const instrumentedOnError = (...args) => {
|
|
23
29
|
const [error, context] = args
|
|
24
30
|
const req = context.env.incoming
|
|
@@ -26,23 +32,20 @@ function wrapCompose (compose) {
|
|
|
26
32
|
return onError(...args)
|
|
27
33
|
}
|
|
28
34
|
|
|
29
|
-
const instrumentedMiddlewares =
|
|
35
|
+
const instrumentedMiddlewares = middlewares.map(h => {
|
|
30
36
|
const [[fn, meta], params] = h
|
|
31
37
|
|
|
32
|
-
// TODO: handle middleware instrumentation
|
|
33
38
|
const instrumentedFn = (...args) => {
|
|
34
39
|
const context = args[0]
|
|
35
|
-
const req = context.env.incoming
|
|
36
|
-
const route = meta.path
|
|
37
40
|
routeChannel.publish({
|
|
38
|
-
req,
|
|
39
|
-
route
|
|
41
|
+
req: context.env.incoming,
|
|
42
|
+
route: meta?.path
|
|
40
43
|
})
|
|
41
44
|
return fn(...args)
|
|
42
45
|
}
|
|
43
46
|
return [[instrumentedFn, meta], params]
|
|
44
47
|
})
|
|
45
|
-
return compose.
|
|
48
|
+
return compose.call(this, instrumentedMiddlewares, instrumentedOnError, onNotFound)
|
|
46
49
|
}
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const { addHook, channel
|
|
3
|
+
const { addHook, channel } = require('./helpers/instrument')
|
|
4
4
|
const { wrapThen } = require('./helpers/promise')
|
|
5
5
|
const shimmer = require('../../datadog-shimmer')
|
|
6
6
|
|
|
7
7
|
const startRawQueryCh = channel('datadog:knex:raw:start')
|
|
8
|
+
const rawQuerySubscribes = channel('datadog:knex:raw:subscribes')
|
|
8
9
|
const finishRawQueryCh = channel('datadog:knex:raw:finish')
|
|
9
10
|
|
|
10
11
|
patch('lib/query/builder.js')
|
|
@@ -22,8 +23,8 @@ function patch (file) {
|
|
|
22
23
|
})
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
function finish () {
|
|
26
|
-
finishRawQueryCh.
|
|
26
|
+
function finish (context, cb) {
|
|
27
|
+
finishRawQueryCh.runStores(context, cb)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
30
|
addHook({
|
|
@@ -43,21 +44,18 @@ addHook({
|
|
|
43
44
|
return raw.apply(this, arguments)
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
return asyncResource.runInAsyncScope(() => {
|
|
49
|
-
startRawQueryCh.publish({ sql, dialect: this.dialect })
|
|
50
|
-
|
|
47
|
+
const context = { sql, dialect: this.dialect }
|
|
48
|
+
return startRawQueryCh.runStores(context, () => {
|
|
51
49
|
const rawResult = raw.apply(this, arguments)
|
|
52
50
|
shimmer.wrap(rawResult, 'then', originalThen => function () {
|
|
53
|
-
return
|
|
54
|
-
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
55
|
-
if (arguments[1]) arguments[1] = wrapCallbackWithFinish(arguments[1], finish)
|
|
51
|
+
return rawQuerySubscribes.runStores(context, () => {
|
|
52
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish, context)
|
|
53
|
+
if (arguments[1]) arguments[1] = wrapCallbackWithFinish(arguments[1], finish, context)
|
|
56
54
|
|
|
57
55
|
const originalThenResult = originalThen.apply(this, arguments)
|
|
58
56
|
|
|
59
57
|
shimmer.wrap(originalThenResult, 'catch', originalCatch => function () {
|
|
60
|
-
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
58
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish, context)
|
|
61
59
|
return originalCatch.apply(this, arguments)
|
|
62
60
|
})
|
|
63
61
|
|
|
@@ -66,8 +64,8 @@ addHook({
|
|
|
66
64
|
})
|
|
67
65
|
|
|
68
66
|
shimmer.wrap(rawResult, 'asCallback', originalAsCallback => function () {
|
|
69
|
-
return
|
|
70
|
-
arguments[0] = wrapCallbackWithFinish(arguments[0], finish)
|
|
67
|
+
return rawQuerySubscribes.runStores(context, () => {
|
|
68
|
+
arguments[0] = wrapCallbackWithFinish(arguments[0], finish, context)
|
|
71
69
|
return originalAsCallback.apply(this, arguments)
|
|
72
70
|
})
|
|
73
71
|
})
|
|
@@ -75,14 +73,14 @@ addHook({
|
|
|
75
73
|
return rawResult
|
|
76
74
|
})
|
|
77
75
|
})
|
|
76
|
+
|
|
78
77
|
return Knex
|
|
79
78
|
})
|
|
80
79
|
|
|
81
|
-
function wrapCallbackWithFinish (callback, finish) {
|
|
80
|
+
function wrapCallbackWithFinish (callback, finish, context) {
|
|
82
81
|
if (typeof callback !== 'function') return callback
|
|
83
82
|
|
|
84
83
|
return shimmer.wrapFunction(callback, callback => function () {
|
|
85
|
-
finish()
|
|
86
|
-
callback.apply(this, arguments)
|
|
84
|
+
finish(context, () => callback.apply(this, arguments))
|
|
87
85
|
})
|
|
88
86
|
}
|
|
@@ -21,19 +21,18 @@ function wrapCall (call) {
|
|
|
21
21
|
ctx.promiseCtx = promise.ctx
|
|
22
22
|
ctx.broker = broker
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
promise
|
|
25
25
|
.then(
|
|
26
26
|
result => {
|
|
27
27
|
finishChannel.publish(ctx)
|
|
28
|
-
return result
|
|
29
28
|
},
|
|
30
29
|
error => {
|
|
31
30
|
ctx.error = error
|
|
32
31
|
errorChannel.publish(ctx)
|
|
33
32
|
finishChannel.publish(ctx)
|
|
34
|
-
throw error
|
|
35
33
|
}
|
|
36
34
|
)
|
|
35
|
+
return promise
|
|
37
36
|
})
|
|
38
37
|
}
|
|
39
38
|
}
|
|
@@ -199,17 +199,15 @@ function instrumentPromise (operation, command, instance, args, server, ns, ops,
|
|
|
199
199
|
return startCh.runStores(ctx, () => {
|
|
200
200
|
const promise = command.apply(instance, args)
|
|
201
201
|
|
|
202
|
-
|
|
202
|
+
promise.then(function (res) {
|
|
203
203
|
ctx.result = res
|
|
204
|
-
|
|
205
|
-
return res
|
|
206
|
-
})
|
|
204
|
+
finishCh.publish(ctx)
|
|
207
205
|
}, function (err) {
|
|
208
206
|
ctx.error = err
|
|
209
207
|
errorCh.publish(ctx)
|
|
210
208
|
finishCh.publish(ctx)
|
|
211
|
-
|
|
212
|
-
throw err
|
|
213
209
|
})
|
|
210
|
+
|
|
211
|
+
return promise
|
|
214
212
|
})
|
|
215
213
|
}
|