dd-trace 5.23.0 → 5.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-3rdparty.csv +0 -1
- package/ext/types.d.ts +1 -0
- package/ext/types.js +1 -0
- package/index.d.ts +26 -0
- package/package.json +6 -7
- package/packages/datadog-code-origin/index.js +38 -0
- package/packages/datadog-core/index.js +2 -2
- package/packages/datadog-instrumentations/src/avsc.js +37 -0
- package/packages/datadog-instrumentations/src/azure-functions.js +48 -0
- package/packages/datadog-instrumentations/src/child_process.js +17 -8
- package/packages/datadog-instrumentations/src/express.js +37 -4
- package/packages/datadog-instrumentations/src/fastify.js +12 -1
- package/packages/datadog-instrumentations/src/fs.js +27 -7
- package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -0
- package/packages/datadog-instrumentations/src/jest.js +2 -1
- package/packages/datadog-instrumentations/src/mocha/common.js +1 -1
- package/packages/datadog-instrumentations/src/mysql2.js +220 -1
- package/packages/datadog-instrumentations/src/protobufjs.js +127 -0
- package/packages/datadog-instrumentations/src/winston.js +22 -0
- package/packages/datadog-plugin-avsc/src/index.js +9 -0
- package/packages/datadog-plugin-avsc/src/schema_iterator.js +169 -0
- package/packages/datadog-plugin-azure-functions/src/index.js +77 -0
- package/packages/datadog-plugin-fastify/src/code_origin.js +31 -0
- package/packages/datadog-plugin-fastify/src/index.js +10 -12
- package/packages/datadog-plugin-fastify/src/tracing.js +19 -0
- package/packages/datadog-plugin-protobufjs/src/index.js +14 -0
- package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +180 -0
- package/packages/dd-trace/src/appsec/addresses.js +6 -1
- package/packages/dd-trace/src/appsec/channels.js +5 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/cookie-analyzer.js +13 -1
- package/packages/dd-trace/src/appsec/iast/analyzers/path-traversal-analyzer.js +8 -1
- package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
- package/packages/dd-trace/src/appsec/iast/index.js +3 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +1 -0
- package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +15 -0
- package/packages/dd-trace/src/appsec/index.js +58 -43
- package/packages/dd-trace/src/appsec/rasp/fs-plugin.js +99 -0
- package/packages/dd-trace/src/appsec/rasp/index.js +24 -10
- package/packages/dd-trace/src/appsec/rasp/lfi.js +112 -0
- package/packages/dd-trace/src/appsec/rasp/sql_injection.js +24 -4
- package/packages/dd-trace/src/appsec/rasp/utils.js +2 -1
- package/packages/dd-trace/src/appsec/recommended.json +2 -4
- package/packages/dd-trace/src/appsec/remote_config/capabilities.js +5 -1
- package/packages/dd-trace/src/appsec/remote_config/index.js +8 -0
- package/packages/dd-trace/src/appsec/reporter.js +12 -5
- package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -0
- package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +1 -1
- package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -14
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +53 -0
- package/packages/dd-trace/src/config.js +12 -1
- package/packages/dd-trace/src/datastreams/schemas/schema_builder.js +25 -17
- package/packages/dd-trace/src/debugger/devtools_client/config.js +2 -0
- package/packages/dd-trace/src/debugger/devtools_client/index.js +56 -5
- package/packages/dd-trace/src/debugger/devtools_client/remote_config.js +4 -4
- package/packages/dd-trace/src/debugger/devtools_client/send.js +14 -1
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +153 -0
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/index.js +30 -0
- package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +241 -0
- package/packages/dd-trace/src/debugger/devtools_client/state.js +10 -4
- package/packages/dd-trace/src/exporters/common/request.js +8 -34
- package/packages/dd-trace/src/exporters/common/url-to-http-options-polyfill.js +31 -0
- package/packages/dd-trace/src/payload-tagging/index.js +1 -1
- package/packages/dd-trace/src/payload-tagging/jsonpath-plus.js +2094 -0
- package/packages/dd-trace/src/plugin_manager.js +4 -2
- package/packages/dd-trace/src/plugins/ci_plugin.js +2 -0
- package/packages/dd-trace/src/plugins/index.js +3 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
- package/packages/dd-trace/src/plugins/schema.js +35 -0
- package/packages/dd-trace/src/plugins/util/ci.js +23 -1
- package/packages/dd-trace/src/plugins/util/serverless.js +7 -0
- package/packages/dd-trace/src/plugins/util/stacktrace.js +94 -0
- package/packages/dd-trace/src/plugins/util/tags.js +7 -0
- package/packages/dd-trace/src/plugins/util/test.js +20 -22
- package/packages/dd-trace/src/plugins/util/web.js +6 -4
- package/packages/dd-trace/src/profiling/profiler.js +24 -14
- package/packages/dd-trace/src/profiling/profilers/events.js +3 -3
- package/packages/dd-trace/src/profiling/profilers/wall.js +94 -66
- package/packages/dd-trace/src/proxy.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v0/index.js +2 -1
- package/packages/dd-trace/src/service-naming/schemas/v0/serverless.js +12 -0
- package/packages/dd-trace/src/service-naming/schemas/v1/index.js +2 -1
- package/packages/dd-trace/src/service-naming/schemas/v1/serverless.js +12 -0
- package/packages/datadog-core/src/storage/async_resource.js +0 -108
- package/packages/datadog-core/src/storage/index.js +0 -5
|
@@ -6,11 +6,14 @@ const {
|
|
|
6
6
|
AsyncResource
|
|
7
7
|
} = require('./helpers/instrument')
|
|
8
8
|
const shimmer = require('../../datadog-shimmer')
|
|
9
|
+
const semver = require('semver')
|
|
9
10
|
|
|
10
|
-
addHook({ name: 'mysql2', file: 'lib/connection.js', versions: ['>=1'] }, Connection => {
|
|
11
|
+
addHook({ name: 'mysql2', file: 'lib/connection.js', versions: ['>=1'] }, (Connection, version) => {
|
|
11
12
|
const startCh = channel('apm:mysql2:query:start')
|
|
12
13
|
const finishCh = channel('apm:mysql2:query:finish')
|
|
13
14
|
const errorCh = channel('apm:mysql2:query:error')
|
|
15
|
+
const startOuterQueryCh = channel('datadog:mysql2:outerquery:start')
|
|
16
|
+
const shouldEmitEndAfterQueryAbort = semver.intersects(version, '>=1.3.3')
|
|
14
17
|
|
|
15
18
|
shimmer.wrap(Connection.prototype, 'addCommand', addCommand => function (cmd) {
|
|
16
19
|
if (!startCh.hasSubscribers) return addCommand.apply(this, arguments)
|
|
@@ -28,6 +31,76 @@ addHook({ name: 'mysql2', file: 'lib/connection.js', versions: ['>=1'] }, Connec
|
|
|
28
31
|
return asyncResource.bind(addCommand, this).apply(this, arguments)
|
|
29
32
|
})
|
|
30
33
|
|
|
34
|
+
shimmer.wrap(Connection.prototype, 'query', query => function (sql, values, cb) {
|
|
35
|
+
if (!startOuterQueryCh.hasSubscribers) return query.apply(this, arguments)
|
|
36
|
+
|
|
37
|
+
if (typeof sql === 'object') sql = sql?.sql
|
|
38
|
+
|
|
39
|
+
if (!sql) return query.apply(this, arguments)
|
|
40
|
+
|
|
41
|
+
const abortController = new AbortController()
|
|
42
|
+
startOuterQueryCh.publish({ sql, abortController })
|
|
43
|
+
|
|
44
|
+
if (abortController.signal.aborted) {
|
|
45
|
+
const addCommand = this.addCommand
|
|
46
|
+
this.addCommand = function (cmd) { return cmd }
|
|
47
|
+
|
|
48
|
+
let queryCommand
|
|
49
|
+
try {
|
|
50
|
+
queryCommand = query.apply(this, arguments)
|
|
51
|
+
} finally {
|
|
52
|
+
this.addCommand = addCommand
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
cb = queryCommand.onResult
|
|
56
|
+
|
|
57
|
+
process.nextTick(() => {
|
|
58
|
+
if (cb) {
|
|
59
|
+
cb(abortController.signal.reason)
|
|
60
|
+
} else {
|
|
61
|
+
queryCommand.emit('error', abortController.signal.reason)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (shouldEmitEndAfterQueryAbort) {
|
|
65
|
+
queryCommand.emit('end')
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
return queryCommand
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return query.apply(this, arguments)
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
shimmer.wrap(Connection.prototype, 'execute', execute => function (sql, values, cb) {
|
|
76
|
+
if (!startOuterQueryCh.hasSubscribers) return execute.apply(this, arguments)
|
|
77
|
+
|
|
78
|
+
if (typeof sql === 'object') sql = sql?.sql
|
|
79
|
+
|
|
80
|
+
if (!sql) return execute.apply(this, arguments)
|
|
81
|
+
|
|
82
|
+
const abortController = new AbortController()
|
|
83
|
+
startOuterQueryCh.publish({ sql, abortController })
|
|
84
|
+
|
|
85
|
+
if (abortController.signal.aborted) {
|
|
86
|
+
const addCommand = this.addCommand
|
|
87
|
+
this.addCommand = function (cmd) { return cmd }
|
|
88
|
+
|
|
89
|
+
let result
|
|
90
|
+
try {
|
|
91
|
+
result = execute.apply(this, arguments)
|
|
92
|
+
} finally {
|
|
93
|
+
this.addCommand = addCommand
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
result?.onResult(abortController.signal.reason)
|
|
97
|
+
|
|
98
|
+
return result
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return execute.apply(this, arguments)
|
|
102
|
+
})
|
|
103
|
+
|
|
31
104
|
return Connection
|
|
32
105
|
|
|
33
106
|
function bindExecute (cmd, execute, asyncResource) {
|
|
@@ -79,3 +152,149 @@ addHook({ name: 'mysql2', file: 'lib/connection.js', versions: ['>=1'] }, Connec
|
|
|
79
152
|
}, cmd))
|
|
80
153
|
}
|
|
81
154
|
})
|
|
155
|
+
|
|
156
|
+
addHook({ name: 'mysql2', file: 'lib/pool.js', versions: ['>=1'] }, (Pool, version) => {
|
|
157
|
+
const startOuterQueryCh = channel('datadog:mysql2:outerquery:start')
|
|
158
|
+
const shouldEmitEndAfterQueryAbort = semver.intersects(version, '>=1.3.3')
|
|
159
|
+
|
|
160
|
+
shimmer.wrap(Pool.prototype, 'query', query => function (sql, values, cb) {
|
|
161
|
+
if (!startOuterQueryCh.hasSubscribers) return query.apply(this, arguments)
|
|
162
|
+
|
|
163
|
+
if (typeof sql === 'object') sql = sql?.sql
|
|
164
|
+
|
|
165
|
+
if (!sql) return query.apply(this, arguments)
|
|
166
|
+
|
|
167
|
+
const abortController = new AbortController()
|
|
168
|
+
startOuterQueryCh.publish({ sql, abortController })
|
|
169
|
+
|
|
170
|
+
if (abortController.signal.aborted) {
|
|
171
|
+
const getConnection = this.getConnection
|
|
172
|
+
this.getConnection = function () {}
|
|
173
|
+
|
|
174
|
+
let queryCommand
|
|
175
|
+
try {
|
|
176
|
+
queryCommand = query.apply(this, arguments)
|
|
177
|
+
} finally {
|
|
178
|
+
this.getConnection = getConnection
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
process.nextTick(() => {
|
|
182
|
+
if (queryCommand.onResult) {
|
|
183
|
+
queryCommand.onResult(abortController.signal.reason)
|
|
184
|
+
} else {
|
|
185
|
+
queryCommand.emit('error', abortController.signal.reason)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (shouldEmitEndAfterQueryAbort) {
|
|
189
|
+
queryCommand.emit('end')
|
|
190
|
+
}
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
return queryCommand
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return query.apply(this, arguments)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
shimmer.wrap(Pool.prototype, 'execute', execute => function (sql, values, cb) {
|
|
200
|
+
if (!startOuterQueryCh.hasSubscribers) return execute.apply(this, arguments)
|
|
201
|
+
|
|
202
|
+
if (typeof sql === 'object') sql = sql?.sql
|
|
203
|
+
|
|
204
|
+
if (!sql) return execute.apply(this, arguments)
|
|
205
|
+
|
|
206
|
+
const abortController = new AbortController()
|
|
207
|
+
startOuterQueryCh.publish({ sql, abortController })
|
|
208
|
+
|
|
209
|
+
if (abortController.signal.aborted) {
|
|
210
|
+
if (typeof values === 'function') {
|
|
211
|
+
cb = values
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
process.nextTick(() => {
|
|
215
|
+
cb(abortController.signal.reason)
|
|
216
|
+
})
|
|
217
|
+
return
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return execute.apply(this, arguments)
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
return Pool
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
// PoolNamespace.prototype.query does not exist in mysql2<2.3.0
|
|
227
|
+
addHook({ name: 'mysql2', file: 'lib/pool_cluster.js', versions: ['>=2.3.0'] }, PoolCluster => {
|
|
228
|
+
const startOuterQueryCh = channel('datadog:mysql2:outerquery:start')
|
|
229
|
+
const wrappedPoolNamespaces = new WeakSet()
|
|
230
|
+
|
|
231
|
+
shimmer.wrap(PoolCluster.prototype, 'of', of => function () {
|
|
232
|
+
const poolNamespace = of.apply(this, arguments)
|
|
233
|
+
|
|
234
|
+
if (startOuterQueryCh.hasSubscribers && !wrappedPoolNamespaces.has(poolNamespace)) {
|
|
235
|
+
shimmer.wrap(poolNamespace, 'query', query => function (sql, values, cb) {
|
|
236
|
+
if (typeof sql === 'object') sql = sql?.sql
|
|
237
|
+
|
|
238
|
+
if (!sql) return query.apply(this, arguments)
|
|
239
|
+
|
|
240
|
+
const abortController = new AbortController()
|
|
241
|
+
startOuterQueryCh.publish({ sql, abortController })
|
|
242
|
+
|
|
243
|
+
if (abortController.signal.aborted) {
|
|
244
|
+
const getConnection = this.getConnection
|
|
245
|
+
this.getConnection = function () {}
|
|
246
|
+
|
|
247
|
+
let queryCommand
|
|
248
|
+
try {
|
|
249
|
+
queryCommand = query.apply(this, arguments)
|
|
250
|
+
} finally {
|
|
251
|
+
this.getConnection = getConnection
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
process.nextTick(() => {
|
|
255
|
+
if (queryCommand.onResult) {
|
|
256
|
+
queryCommand.onResult(abortController.signal.reason)
|
|
257
|
+
} else {
|
|
258
|
+
queryCommand.emit('error', abortController.signal.reason)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
queryCommand.emit('end')
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
return queryCommand
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return query.apply(this, arguments)
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
shimmer.wrap(poolNamespace, 'execute', execute => function (sql, values, cb) {
|
|
271
|
+
if (typeof sql === 'object') sql = sql?.sql
|
|
272
|
+
|
|
273
|
+
if (!sql) return execute.apply(this, arguments)
|
|
274
|
+
|
|
275
|
+
const abortController = new AbortController()
|
|
276
|
+
startOuterQueryCh.publish({ sql, abortController })
|
|
277
|
+
|
|
278
|
+
if (abortController.signal.aborted) {
|
|
279
|
+
if (typeof values === 'function') {
|
|
280
|
+
cb = values
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
process.nextTick(() => {
|
|
284
|
+
cb(abortController.signal.reason)
|
|
285
|
+
})
|
|
286
|
+
|
|
287
|
+
return
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return execute.apply(this, arguments)
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
wrappedPoolNamespaces.add(poolNamespace)
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return poolNamespace
|
|
297
|
+
})
|
|
298
|
+
|
|
299
|
+
return PoolCluster
|
|
300
|
+
})
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
const shimmer = require('../../datadog-shimmer')
|
|
2
|
+
const { addHook } = require('./helpers/instrument')
|
|
3
|
+
|
|
4
|
+
const dc = require('dc-polyfill')
|
|
5
|
+
const serializeChannel = dc.channel('apm:protobufjs:serialize-start')
|
|
6
|
+
const deserializeChannel = dc.channel('apm:protobufjs:deserialize-end')
|
|
7
|
+
|
|
8
|
+
function wrapSerialization (messageClass) {
|
|
9
|
+
if (messageClass?.encode) {
|
|
10
|
+
shimmer.wrap(messageClass, 'encode', original => function () {
|
|
11
|
+
if (!serializeChannel.hasSubscribers) {
|
|
12
|
+
return original.apply(this, arguments)
|
|
13
|
+
}
|
|
14
|
+
serializeChannel.publish({ messageClass: this })
|
|
15
|
+
return original.apply(this, arguments)
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function wrapDeserialization (messageClass) {
|
|
21
|
+
if (messageClass?.decode) {
|
|
22
|
+
shimmer.wrap(messageClass, 'decode', original => function () {
|
|
23
|
+
if (!deserializeChannel.hasSubscribers) {
|
|
24
|
+
return original.apply(this, arguments)
|
|
25
|
+
}
|
|
26
|
+
const result = original.apply(this, arguments)
|
|
27
|
+
deserializeChannel.publish({ messageClass: result })
|
|
28
|
+
return result
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function wrapSetup (messageClass) {
|
|
34
|
+
if (messageClass?.setup) {
|
|
35
|
+
shimmer.wrap(messageClass, 'setup', original => function () {
|
|
36
|
+
const result = original.apply(this, arguments)
|
|
37
|
+
|
|
38
|
+
wrapSerialization(messageClass)
|
|
39
|
+
wrapDeserialization(messageClass)
|
|
40
|
+
|
|
41
|
+
return result
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function wrapProtobufClasses (root) {
|
|
47
|
+
if (!root) {
|
|
48
|
+
return
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (root.decode) {
|
|
52
|
+
wrapSetup(root)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (root.nestedArray) {
|
|
56
|
+
for (const subRoot of root.nestedArray) {
|
|
57
|
+
wrapProtobufClasses(subRoot)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function wrapReflection (protobuf) {
|
|
63
|
+
const reflectionMethods = [
|
|
64
|
+
{
|
|
65
|
+
target: protobuf.Root,
|
|
66
|
+
name: 'fromJSON'
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
target: protobuf.Type.prototype,
|
|
70
|
+
name: 'fromObject'
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
reflectionMethods.forEach(method => {
|
|
75
|
+
shimmer.wrap(method.target, method.name, original => function () {
|
|
76
|
+
const result = original.apply(this, arguments)
|
|
77
|
+
if (result.nested) {
|
|
78
|
+
for (const type in result.nested) {
|
|
79
|
+
wrapSetup(result.nested[type])
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
if (result.$type) {
|
|
83
|
+
wrapSetup(result.$type)
|
|
84
|
+
}
|
|
85
|
+
return result
|
|
86
|
+
})
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function isPromise (obj) {
|
|
91
|
+
return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
addHook({
|
|
95
|
+
name: 'protobufjs',
|
|
96
|
+
versions: ['>=6.8.0']
|
|
97
|
+
}, protobuf => {
|
|
98
|
+
shimmer.wrap(protobuf.Root.prototype, 'load', original => function () {
|
|
99
|
+
const result = original.apply(this, arguments)
|
|
100
|
+
if (isPromise(result)) {
|
|
101
|
+
return result.then(root => {
|
|
102
|
+
wrapProtobufClasses(root)
|
|
103
|
+
return root
|
|
104
|
+
})
|
|
105
|
+
} else {
|
|
106
|
+
// If result is not a promise, directly wrap the protobuf classes
|
|
107
|
+
wrapProtobufClasses(result)
|
|
108
|
+
return result
|
|
109
|
+
}
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
shimmer.wrap(protobuf.Root.prototype, 'loadSync', original => function () {
|
|
113
|
+
const root = original.apply(this, arguments)
|
|
114
|
+
wrapProtobufClasses(root)
|
|
115
|
+
return root
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
shimmer.wrap(protobuf, 'Type', Original => function () {
|
|
119
|
+
const typeInstance = new Original(...arguments)
|
|
120
|
+
wrapSetup(typeInstance)
|
|
121
|
+
return typeInstance
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
wrapReflection(protobuf)
|
|
125
|
+
|
|
126
|
+
return protobuf
|
|
127
|
+
})
|
|
@@ -8,6 +8,18 @@ const shimmer = require('../../datadog-shimmer')
|
|
|
8
8
|
|
|
9
9
|
const patched = new WeakSet()
|
|
10
10
|
|
|
11
|
+
// Test Visibility log submission channels
|
|
12
|
+
const configureCh = channel('ci:log-submission:winston:configure')
|
|
13
|
+
const addTransport = channel('ci:log-submission:winston:add-transport')
|
|
14
|
+
|
|
15
|
+
addHook({ name: 'winston', file: 'lib/winston/transports/index.js', versions: ['>=3'] }, transportsPackage => {
|
|
16
|
+
if (configureCh.hasSubscribers) {
|
|
17
|
+
configureCh.publish(transportsPackage.Http)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return transportsPackage
|
|
21
|
+
})
|
|
22
|
+
|
|
11
23
|
addHook({ name: 'winston', file: 'lib/winston/logger.js', versions: ['>=3'] }, Logger => {
|
|
12
24
|
const logCh = channel('apm:winston:log')
|
|
13
25
|
shimmer.wrap(Logger.prototype, 'write', write => {
|
|
@@ -20,6 +32,16 @@ addHook({ name: 'winston', file: 'lib/winston/logger.js', versions: ['>=3'] }, L
|
|
|
20
32
|
return write.apply(this, arguments)
|
|
21
33
|
}
|
|
22
34
|
})
|
|
35
|
+
|
|
36
|
+
shimmer.wrap(Logger.prototype, 'configure', configure => function () {
|
|
37
|
+
const configureResponse = configure.apply(this, arguments)
|
|
38
|
+
// After the original `configure`, because it resets transports
|
|
39
|
+
if (addTransport.hasSubscribers) {
|
|
40
|
+
addTransport.publish(this)
|
|
41
|
+
}
|
|
42
|
+
return configureResponse
|
|
43
|
+
})
|
|
44
|
+
|
|
23
45
|
return Logger
|
|
24
46
|
})
|
|
25
47
|
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
const SchemaPlugin = require('../../dd-trace/src/plugins/schema')
|
|
2
|
+
const SchemaExtractor = require('./schema_iterator')
|
|
3
|
+
|
|
4
|
+
class AvscPlugin extends SchemaPlugin {
|
|
5
|
+
static get id () { return 'avsc' }
|
|
6
|
+
static get schemaExtractor () { return SchemaExtractor }
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
module.exports = AvscPlugin
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
const AVRO = 'avro'
|
|
2
|
+
const {
|
|
3
|
+
SCHEMA_DEFINITION,
|
|
4
|
+
SCHEMA_ID,
|
|
5
|
+
SCHEMA_NAME,
|
|
6
|
+
SCHEMA_OPERATION,
|
|
7
|
+
SCHEMA_WEIGHT,
|
|
8
|
+
SCHEMA_TYPE
|
|
9
|
+
} = require('../../dd-trace/src/constants')
|
|
10
|
+
const log = require('../../dd-trace/src/log')
|
|
11
|
+
const {
|
|
12
|
+
SchemaBuilder
|
|
13
|
+
} = require('../../dd-trace/src/datastreams/schemas/schema_builder')
|
|
14
|
+
|
|
15
|
+
class SchemaExtractor {
|
|
16
|
+
constructor (schema) {
|
|
17
|
+
this.schema = schema
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static getType (type) {
|
|
21
|
+
const typeMapping = {
|
|
22
|
+
string: 'string',
|
|
23
|
+
int: 'integer',
|
|
24
|
+
long: 'integer',
|
|
25
|
+
float: 'number',
|
|
26
|
+
double: 'number',
|
|
27
|
+
boolean: 'boolean',
|
|
28
|
+
bytes: 'string',
|
|
29
|
+
record: 'object',
|
|
30
|
+
enum: 'string',
|
|
31
|
+
array: 'array',
|
|
32
|
+
map: 'object',
|
|
33
|
+
fixed: 'string'
|
|
34
|
+
}
|
|
35
|
+
const typeName = type.typeName ?? type.name ?? type
|
|
36
|
+
return typeName === 'null' ? typeName : typeMapping[typeName] || 'string'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static extractProperty (field, schemaName, fieldName, builder, depth) {
|
|
40
|
+
let array = false
|
|
41
|
+
let type
|
|
42
|
+
let format
|
|
43
|
+
let enumValues
|
|
44
|
+
let description
|
|
45
|
+
let ref
|
|
46
|
+
|
|
47
|
+
const fieldType = field.type?.types ?? field.type?.typeName ?? field.type
|
|
48
|
+
|
|
49
|
+
if (Array.isArray(fieldType)) {
|
|
50
|
+
// Union Type
|
|
51
|
+
type = 'union[' + fieldType.map(t => SchemaExtractor.getType(t.type || t)).join(',') + ']'
|
|
52
|
+
} else if (fieldType === 'array') {
|
|
53
|
+
// Array Type
|
|
54
|
+
array = true
|
|
55
|
+
const nestedType = field.type.itemsType.typeName
|
|
56
|
+
type = SchemaExtractor.getType(nestedType)
|
|
57
|
+
} else if (fieldType === 'record') {
|
|
58
|
+
// Nested Record Type
|
|
59
|
+
type = 'object'
|
|
60
|
+
ref = `#/components/schemas/${field.type.name}`
|
|
61
|
+
if (!SchemaExtractor.extractSchema(field.type, builder, depth + 1, this)) {
|
|
62
|
+
return false
|
|
63
|
+
}
|
|
64
|
+
} else if (fieldType === 'enum') {
|
|
65
|
+
enumValues = []
|
|
66
|
+
let i = 0
|
|
67
|
+
type = 'string'
|
|
68
|
+
while (field.type.symbols[i]) {
|
|
69
|
+
enumValues.push(field.type.symbols[i])
|
|
70
|
+
i += 1
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
// Primitive type
|
|
74
|
+
type = SchemaExtractor.getType(fieldType.type || fieldType)
|
|
75
|
+
if (fieldType === 'bytes') {
|
|
76
|
+
format = 'byte'
|
|
77
|
+
} else if (fieldType === 'int') {
|
|
78
|
+
format = 'int32'
|
|
79
|
+
} else if (fieldType === 'long') {
|
|
80
|
+
format = 'int64'
|
|
81
|
+
} else if (fieldType === 'float') {
|
|
82
|
+
format = 'float'
|
|
83
|
+
} else if (fieldType === 'double') {
|
|
84
|
+
format = 'double'
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return builder.addProperty(schemaName, fieldName, array, type, description, ref, format, enumValues)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static extractSchema (schema, builder, depth, extractor) {
|
|
92
|
+
depth += 1
|
|
93
|
+
const schemaName = schema.name
|
|
94
|
+
if (extractor) {
|
|
95
|
+
// if we already have a defined extractor, this is a nested schema. create a new extractor for the nested
|
|
96
|
+
// schema, ensure it is added to our schema builder's cache, and replace the builders iterator with our
|
|
97
|
+
// nested schema iterator / extractor. Once complete, add the new schema to our builder's schemas.
|
|
98
|
+
const nestedSchemaExtractor = new SchemaExtractor(schema)
|
|
99
|
+
builder.iterator = nestedSchemaExtractor
|
|
100
|
+
const nestedSchema = SchemaBuilder.getSchema(schemaName, nestedSchemaExtractor, builder)
|
|
101
|
+
for (const nestedSubSchemaName in nestedSchema.components.schemas) {
|
|
102
|
+
if (nestedSchema.components.schemas.hasOwnProperty(nestedSubSchemaName)) {
|
|
103
|
+
builder.schema.components.schemas[nestedSubSchemaName] = nestedSchema.components.schemas[nestedSubSchemaName]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return true
|
|
107
|
+
} else {
|
|
108
|
+
if (!builder.shouldExtractSchema(schemaName, depth)) {
|
|
109
|
+
return false
|
|
110
|
+
}
|
|
111
|
+
for (const field of schema.fields) {
|
|
112
|
+
if (!this.extractProperty(field, schemaName, field.name, builder, depth)) {
|
|
113
|
+
log.warn(`DSM: Unable to extract field with name: ${field.name} from Avro schema with name: ${schemaName}`)
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return true
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
static extractSchemas (descriptor, dataStreamsProcessor) {
|
|
121
|
+
return dataStreamsProcessor.getSchema(descriptor.name, new SchemaExtractor(descriptor))
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
iterateOverSchema (builder) {
|
|
125
|
+
this.constructor.extractSchema(this.schema, builder, 0)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
static attachSchemaOnSpan (args, span, operation, tracer) {
|
|
129
|
+
const { messageClass } = args
|
|
130
|
+
const descriptor = messageClass?.constructor?.type ?? messageClass
|
|
131
|
+
|
|
132
|
+
if (!descriptor || !span) {
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (span.context()._tags[SCHEMA_TYPE] && operation === 'serialization') {
|
|
137
|
+
// we have already added a schema to this span, this call is an encode of nested schema types
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
span.setTag(SCHEMA_TYPE, AVRO)
|
|
142
|
+
span.setTag(SCHEMA_NAME, descriptor.name)
|
|
143
|
+
span.setTag(SCHEMA_OPERATION, operation)
|
|
144
|
+
|
|
145
|
+
if (!tracer._dataStreamsProcessor.canSampleSchema(operation)) {
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// if the span is unsampled, do not sample the schema
|
|
150
|
+
if (!tracer._prioritySampler.isSampled(span)) {
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const weight = tracer._dataStreamsProcessor.trySampleSchema(operation)
|
|
155
|
+
if (weight === 0) {
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const schemaData = SchemaBuilder.getSchemaDefinition(
|
|
160
|
+
this.extractSchemas(descriptor, tracer._dataStreamsProcessor)
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
span.setTag(SCHEMA_DEFINITION, schemaData.definition)
|
|
164
|
+
span.setTag(SCHEMA_WEIGHT, weight)
|
|
165
|
+
span.setTag(SCHEMA_ID, schemaData.id)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = SchemaExtractor
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const TracingPlugin = require('../../dd-trace/src/plugins/tracing')
|
|
4
|
+
const { storage } = require('../../datadog-core')
|
|
5
|
+
const serverless = require('../../dd-trace/src/plugins/util/serverless')
|
|
6
|
+
const web = require('../../dd-trace/src/plugins/util/web')
|
|
7
|
+
|
|
8
|
+
const triggerMap = {
|
|
9
|
+
deleteRequest: 'Http',
|
|
10
|
+
http: 'Http',
|
|
11
|
+
get: 'Http',
|
|
12
|
+
patch: 'Http',
|
|
13
|
+
post: 'Http',
|
|
14
|
+
put: 'Http'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
class AzureFunctionsPlugin extends TracingPlugin {
|
|
18
|
+
static get id () { return 'azure-functions' }
|
|
19
|
+
static get operation () { return 'invoke' }
|
|
20
|
+
static get kind () { return 'server' }
|
|
21
|
+
static get type () { return 'serverless' }
|
|
22
|
+
|
|
23
|
+
static get prefix () { return 'tracing:datadog:azure-functions:invoke' }
|
|
24
|
+
|
|
25
|
+
bindStart (ctx) {
|
|
26
|
+
const { functionName, methodName } = ctx
|
|
27
|
+
const store = storage.getStore()
|
|
28
|
+
|
|
29
|
+
const span = this.startSpan(this.operationName(), {
|
|
30
|
+
service: this.serviceName(),
|
|
31
|
+
type: 'serverless',
|
|
32
|
+
meta: {
|
|
33
|
+
'aas.function.name': functionName,
|
|
34
|
+
'aas.function.trigger': mapTriggerTag(methodName)
|
|
35
|
+
}
|
|
36
|
+
}, false)
|
|
37
|
+
|
|
38
|
+
ctx.span = span
|
|
39
|
+
ctx.parentStore = store
|
|
40
|
+
ctx.currentStore = { ...store, span }
|
|
41
|
+
|
|
42
|
+
return ctx.currentStore
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
error (ctx) {
|
|
46
|
+
this.addError(ctx.error)
|
|
47
|
+
ctx.currentStore.span.setTag('error.message', ctx.error)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
asyncEnd (ctx) {
|
|
51
|
+
const { httpRequest, result = {} } = ctx
|
|
52
|
+
const path = (new URL(httpRequest.url)).pathname
|
|
53
|
+
const req = {
|
|
54
|
+
method: httpRequest.method,
|
|
55
|
+
headers: Object.fromEntries(httpRequest.headers.entries()),
|
|
56
|
+
url: path
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const context = web.patch(req)
|
|
60
|
+
context.config = this.config
|
|
61
|
+
context.paths = [path]
|
|
62
|
+
context.res = { statusCode: result.status }
|
|
63
|
+
context.span = ctx.currentStore.span
|
|
64
|
+
|
|
65
|
+
serverless.finishSpan(context)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
configure (config) {
|
|
69
|
+
return super.configure(web.normalizeConfig(config))
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function mapTriggerTag (methodName) {
|
|
74
|
+
return triggerMap[methodName] || 'Unknown'
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = AzureFunctionsPlugin
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { entryTag } = require('../../datadog-code-origin')
|
|
4
|
+
const Plugin = require('../../dd-trace/src/plugins/plugin')
|
|
5
|
+
const web = require('../../dd-trace/src/plugins/util/web')
|
|
6
|
+
|
|
7
|
+
const kCodeOriginForSpansTagsSym = Symbol('datadog.codeOriginForSpansTags')
|
|
8
|
+
|
|
9
|
+
class FastifyCodeOriginForSpansPlugin extends Plugin {
|
|
10
|
+
static get id () {
|
|
11
|
+
return 'fastify'
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
constructor (...args) {
|
|
15
|
+
super(...args)
|
|
16
|
+
|
|
17
|
+
this.addSub('apm:fastify:request:handle', ({ req, routeConfig }) => {
|
|
18
|
+
const tags = routeConfig?.[kCodeOriginForSpansTagsSym]
|
|
19
|
+
if (!tags) return
|
|
20
|
+
const context = web.getContext(req)
|
|
21
|
+
context.span?.addTags(tags)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
this.addSub('apm:fastify:route:added', ({ routeOptions, onRoute }) => {
|
|
25
|
+
if (!routeOptions.config) routeOptions.config = {}
|
|
26
|
+
routeOptions.config[kCodeOriginForSpansTagsSym] = entryTag(onRoute)
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = FastifyCodeOriginForSpansPlugin
|