dd-trace 2.12.1 → 3.0.0-pre.2
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 +2 -26
- package/ci/jest/env.js +2 -3
- package/index.d.ts +0 -7
- package/package.json +1 -1
- package/packages/datadog-plugin-grpc/src/client.js +2 -2
- package/packages/datadog-plugin-grpc/src/server.js +2 -2
- package/packages/datadog-plugin-http/src/client.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +1 -1
- package/packages/datadog-plugin-http2/src/client.js +1 -1
- package/packages/dd-trace/src/config.js +8 -0
- package/packages/dd-trace/src/encode/0.4.js +4 -0
- package/packages/dd-trace/src/exporters/common/request.js +49 -34
- package/packages/dd-trace/src/exporters/common/writer.js +8 -1
- package/packages/dd-trace/src/noop/tracer.js +0 -4
- package/packages/dd-trace/src/plugin_manager.js +5 -1
- package/packages/dd-trace/src/plugins/index.js +0 -1
- package/packages/dd-trace/src/plugins/util/web.js +48 -3
- package/packages/dd-trace/src/proxy.js +0 -19
- package/packages/dd-trace/src/scope.js +1 -126
- package/packages/dd-trace/src/tracer.js +0 -4
- package/cypress/plugin.js +0 -5
- package/cypress/support.js +0 -1
- package/packages/datadog-plugin-fs/src/index.js +0 -548
package/ci/init.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
-
|
|
3
|
-
const path = require('path')
|
|
4
2
|
const tracer = require('../packages/dd-trace')
|
|
5
3
|
const { ORIGIN_KEY } = require('../packages/dd-trace/src/constants')
|
|
6
|
-
const {
|
|
7
|
-
const { pickleHook, testCaseHook } = require('../packages/datadog-instrumentations/src/cucumber')
|
|
4
|
+
const { isTrue } = require('../packages/dd-trace/src/util')
|
|
8
5
|
|
|
9
6
|
const options = {
|
|
10
7
|
startupLogs: false,
|
|
@@ -15,9 +12,7 @@ const options = {
|
|
|
15
12
|
|
|
16
13
|
let shouldInit = true
|
|
17
14
|
|
|
18
|
-
const isAgentlessEnabled = process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED
|
|
19
|
-
process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== 'false' &&
|
|
20
|
-
process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== '0'
|
|
15
|
+
const isAgentlessEnabled = isTrue(process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED)
|
|
21
16
|
|
|
22
17
|
if (isAgentlessEnabled) {
|
|
23
18
|
if (process.env.DATADOG_API_KEY || process.env.DD_API_KEY) {
|
|
@@ -32,25 +27,6 @@ so dd-trace will not be initialized.`)
|
|
|
32
27
|
}
|
|
33
28
|
}
|
|
34
29
|
|
|
35
|
-
// TODO: remove this in a later major version since we now recommend using
|
|
36
|
-
// `NODE_OPTIONS='-r dd-trace/ci/init'`.
|
|
37
|
-
try {
|
|
38
|
-
for (const filename in require.cache) {
|
|
39
|
-
const cache = require.cache[filename]
|
|
40
|
-
const id = filename.split(path.sep).join('/')
|
|
41
|
-
|
|
42
|
-
if (id.includes('/node_modules/mocha/lib/runner.js')) {
|
|
43
|
-
cache.exports = mochaHook(cache.exports)
|
|
44
|
-
} else if (id.includes('/node_modules/@cucumber/cucumber/lib/runtime/pickle_runner.js')) {
|
|
45
|
-
cache.exports = pickleHook(cache.exports)
|
|
46
|
-
} else if (id.includes('/node_modules/@cucumber/cucumber/lib/runtime/test_case_runner.js')) {
|
|
47
|
-
cache.exports = testCaseHook(cache.exports)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
} catch (e) {
|
|
51
|
-
// ignore error and let the tracer initialize anyway
|
|
52
|
-
}
|
|
53
|
-
|
|
54
30
|
if (shouldInit) {
|
|
55
31
|
tracer.init(options)
|
|
56
32
|
tracer.use('fs', false)
|
package/ci/jest/env.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const tracer = require('../../packages/dd-trace')
|
|
4
4
|
const { ORIGIN_KEY } = require('../../packages/dd-trace/src/constants')
|
|
5
|
+
const { isTrue } = require('../../packages/dd-trace/src/util')
|
|
5
6
|
|
|
6
7
|
const options = {
|
|
7
8
|
startupLogs: false,
|
|
@@ -10,9 +11,7 @@ const options = {
|
|
|
10
11
|
}
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
const isAgentlessEnabled = process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED
|
|
14
|
-
process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== 'false' &&
|
|
15
|
-
process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED !== '0'
|
|
14
|
+
const isAgentlessEnabled = isTrue(process.env.DD_CIVISIBILITY_AGENTLESS_ENABLED)
|
|
16
15
|
|
|
17
16
|
if (isAgentlessEnabled) {
|
|
18
17
|
if (process.env.DATADOG_API_KEY || process.env.DD_API_KEY) {
|
package/index.d.ts
CHANGED
|
@@ -562,7 +562,6 @@ interface Plugins {
|
|
|
562
562
|
"elasticsearch": plugins.elasticsearch;
|
|
563
563
|
"express": plugins.express;
|
|
564
564
|
"fastify": plugins.fastify;
|
|
565
|
-
"fs": plugins.fs;
|
|
566
565
|
"generic-pool": plugins.generic_pool;
|
|
567
566
|
"google-cloud-pubsub": plugins.google_cloud_pubsub;
|
|
568
567
|
"graphql": plugins.graphql;
|
|
@@ -903,12 +902,6 @@ declare namespace plugins {
|
|
|
903
902
|
*/
|
|
904
903
|
interface fastify extends HttpServer {}
|
|
905
904
|
|
|
906
|
-
/**
|
|
907
|
-
* This plugin automatically instruments the
|
|
908
|
-
* [fs](https://nodejs.org/api/fs.html) module.
|
|
909
|
-
*/
|
|
910
|
-
interface fs extends Instrumentation {}
|
|
911
|
-
|
|
912
905
|
/**
|
|
913
906
|
* This plugin patches the [generic-pool](https://github.com/coopernurse/node-pool)
|
|
914
907
|
* module to bind the callbacks the the caller context.
|
package/package.json
CHANGED
|
@@ -19,13 +19,13 @@ class GrpcClientPlugin extends Plugin {
|
|
|
19
19
|
const metadataFilter = this.config.metadataFilter
|
|
20
20
|
const store = storage.getStore()
|
|
21
21
|
const childOf = store && store.span
|
|
22
|
-
const span = this.tracer.startSpan('grpc.
|
|
22
|
+
const span = this.tracer.startSpan('grpc.client', {
|
|
23
23
|
childOf,
|
|
24
24
|
tags: {
|
|
25
25
|
[Tags.SPAN_KIND]: 'client',
|
|
26
26
|
'span.type': 'http',
|
|
27
27
|
'resource.name': path,
|
|
28
|
-
'service.name': this.config.service ||
|
|
28
|
+
'service.name': this.config.service || this.tracer._service,
|
|
29
29
|
'component': 'grpc'
|
|
30
30
|
}
|
|
31
31
|
})
|
|
@@ -19,13 +19,13 @@ class GrpcServerPlugin extends Plugin {
|
|
|
19
19
|
const metadataFilter = this.config.metadataFilter
|
|
20
20
|
const store = storage.getStore()
|
|
21
21
|
const childOf = extract(this.tracer, metadata)
|
|
22
|
-
const span = this.tracer.startSpan('grpc.
|
|
22
|
+
const span = this.tracer.startSpan('grpc.server', {
|
|
23
23
|
childOf,
|
|
24
24
|
tags: {
|
|
25
25
|
[Tags.SPAN_KIND]: 'server',
|
|
26
26
|
'span.type': 'web',
|
|
27
27
|
'resource.name': name,
|
|
28
|
-
'service.name': this.config.service ||
|
|
28
|
+
'service.name': this.config.service || this.tracer._service,
|
|
29
29
|
'component': 'grpc'
|
|
30
30
|
}
|
|
31
31
|
})
|
|
@@ -15,7 +15,7 @@ class HttpServerPlugin extends Plugin {
|
|
|
15
15
|
|
|
16
16
|
this.addSub('apm:http:server:request:start', ({ req, res }) => {
|
|
17
17
|
const store = storage.getStore()
|
|
18
|
-
const span = web.startSpan(this.tracer, this.config, req, res, '
|
|
18
|
+
const span = web.startSpan(this.tracer, this.config, req, res, 'web.request')
|
|
19
19
|
|
|
20
20
|
this.enter(span, { ...store, req })
|
|
21
21
|
|
|
@@ -13,6 +13,9 @@ const uuid = require('crypto-randomuuid')
|
|
|
13
13
|
const fromEntries = Object.fromEntries || (entries =>
|
|
14
14
|
entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
|
|
15
15
|
|
|
16
|
+
// eslint-disable-next-line max-len
|
|
17
|
+
const qsRegex = '(?:p(?:ass)?w(?:or)?d|pass(?:_?phrase)?|secret|(?:api_?|private_?|public_?|access_?|secret_?)key(?:_?id)?|token|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)(?:(?:\\s|%20)*(?:=|%3D)[^&]+|(?:"|%22)(?:\\s|%20)*(?::|%3A)(?:\\s|%20)*(?:"|%22)(?:%2[^2]|%[^2]|[^"%])+(?:"|%22))|bearer(?:\\s|%20)+[a-z0-9\\._\\-]|token(?::|%3A)[a-z0-9]{13}|gh[opsu]_[0-9a-zA-Z]{36}|ey[I-L](?:[\\w=-]|%3D)+\\.ey[I-L](?:[\\w=-]|%3D)+(?:\\.(?:[\\w.+\\/=-]|%3D|%2F|%2B)+)?|[\\-]{5}BEGIN(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY[\\-]{5}[^\\-]+[\\-]{5}END(?:[a-z\\s]|%20)+PRIVATE(?:\\s|%20)KEY|ssh-rsa(?:\\s|%20)*(?:[a-z0-9\\/\\.+]|%2F|%5C|%2B){100,}'
|
|
18
|
+
|
|
16
19
|
class Config {
|
|
17
20
|
constructor (options) {
|
|
18
21
|
options = options || {}
|
|
@@ -109,6 +112,10 @@ class Config {
|
|
|
109
112
|
parseInt(process.env.DD_TRACE_PARTIAL_FLUSH_MIN_SPANS),
|
|
110
113
|
1000
|
|
111
114
|
)
|
|
115
|
+
const DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP = coalesce(
|
|
116
|
+
process.env.DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
|
|
117
|
+
qsRegex
|
|
118
|
+
)
|
|
112
119
|
const DD_TRACE_B3_ENABLED = coalesce(
|
|
113
120
|
options.experimental && options.experimental.b3,
|
|
114
121
|
process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
|
|
@@ -203,6 +210,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
|
|
|
203
210
|
this.flushInterval = coalesce(parseInt(options.flushInterval, 10), defaultFlushInterval)
|
|
204
211
|
this.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
|
|
205
212
|
this.sampleRate = coalesce(Math.min(Math.max(sampler.sampleRate, 0), 1), 1)
|
|
213
|
+
this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
|
|
206
214
|
this.logger = options.logger
|
|
207
215
|
this.plugins = !!coalesce(options.plugins, true)
|
|
208
216
|
this.service = DD_SERVICE
|
|
@@ -1,22 +1,33 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
// TODO: Add test with slow or unresponsive agent.
|
|
4
|
+
// TODO: Add telemetry for things like dropped requests, errors, etc.
|
|
5
|
+
|
|
3
6
|
const http = require('http')
|
|
4
7
|
const https = require('https')
|
|
5
|
-
const log = require('../../log')
|
|
6
8
|
const docker = require('./docker')
|
|
7
9
|
const { storage } = require('../../../../datadog-core')
|
|
8
10
|
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
+
const keepAlive = true
|
|
12
|
+
const maxTotalSockets = 1
|
|
13
|
+
const maxActiveRequests = 8
|
|
14
|
+
const httpAgent = new http.Agent({ keepAlive, maxTotalSockets })
|
|
15
|
+
const httpsAgent = new https.Agent({ keepAlive, maxTotalSockets })
|
|
11
16
|
const containerId = docker.id()
|
|
12
17
|
|
|
18
|
+
let activeRequests = 0
|
|
19
|
+
|
|
13
20
|
function request (data, options, keepAlive, callback) {
|
|
14
21
|
if (!options.headers) {
|
|
15
22
|
options.headers = {}
|
|
16
23
|
}
|
|
24
|
+
|
|
25
|
+
// The timeout should be kept low to avoid excessive queueing.
|
|
26
|
+
const timeout = options.timeout || 2000
|
|
17
27
|
const isSecure = options.protocol === 'https:'
|
|
18
28
|
const client = isSecure ? https : http
|
|
19
29
|
const dataArray = [].concat(data)
|
|
30
|
+
|
|
20
31
|
options.headers['Content-Length'] = byteLength(dataArray)
|
|
21
32
|
|
|
22
33
|
if (containerId) {
|
|
@@ -27,39 +38,15 @@ function request (data, options, keepAlive, callback) {
|
|
|
27
38
|
options.agent = isSecure ? httpsAgent : httpAgent
|
|
28
39
|
}
|
|
29
40
|
|
|
30
|
-
const
|
|
31
|
-
dataArray.forEach(buffer => firstRequest.write(buffer))
|
|
32
|
-
|
|
33
|
-
// The first request will be retried
|
|
34
|
-
const firstRequestErrorHandler = () => {
|
|
35
|
-
log.debug('Retrying request to the intake')
|
|
36
|
-
const retriedReq = retriableRequest(options, client, callback)
|
|
37
|
-
dataArray.forEach(buffer => retriedReq.write(buffer))
|
|
38
|
-
// The retried request will fail normally
|
|
39
|
-
retriedReq.on('error', e => callback(new Error(`Network error trying to reach the intake: ${e.message}`)))
|
|
40
|
-
retriedReq.end()
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
firstRequest.on('error', firstRequestErrorHandler)
|
|
44
|
-
firstRequest.end()
|
|
45
|
-
|
|
46
|
-
return firstRequest
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function retriableRequest (options, client, callback) {
|
|
50
|
-
const store = storage.getStore()
|
|
51
|
-
|
|
52
|
-
storage.enterWith({ noop: true })
|
|
53
|
-
|
|
54
|
-
const timeout = options.timeout || 15000
|
|
55
|
-
|
|
56
|
-
const request = client.request(options, res => {
|
|
41
|
+
const onResponse = res => {
|
|
57
42
|
let responseData = ''
|
|
58
43
|
|
|
59
44
|
res.setTimeout(timeout)
|
|
60
45
|
|
|
61
46
|
res.on('data', chunk => { responseData += chunk })
|
|
62
47
|
res.on('end', () => {
|
|
48
|
+
activeRequests--
|
|
49
|
+
|
|
63
50
|
if (res.statusCode >= 200 && res.statusCode <= 299) {
|
|
64
51
|
callback(null, responseData, res.statusCode)
|
|
65
52
|
} else {
|
|
@@ -69,15 +56,43 @@ function retriableRequest (options, client, callback) {
|
|
|
69
56
|
callback(error, null, res.statusCode)
|
|
70
57
|
}
|
|
71
58
|
})
|
|
72
|
-
}
|
|
73
|
-
request.setTimeout(timeout, request.abort)
|
|
74
|
-
storage.enterWith(store)
|
|
59
|
+
}
|
|
75
60
|
|
|
76
|
-
|
|
61
|
+
const makeRequest = onError => {
|
|
62
|
+
if (!request.writable) return callback(null)
|
|
63
|
+
|
|
64
|
+
activeRequests++
|
|
65
|
+
|
|
66
|
+
const store = storage.getStore()
|
|
67
|
+
|
|
68
|
+
storage.enterWith({ noop: true })
|
|
69
|
+
|
|
70
|
+
const req = client.request(options, onResponse)
|
|
71
|
+
|
|
72
|
+
req.once('error', err => {
|
|
73
|
+
activeRequests--
|
|
74
|
+
onError(err)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
dataArray.forEach(buffer => req.write(buffer))
|
|
78
|
+
|
|
79
|
+
req.setTimeout(timeout, req.abort)
|
|
80
|
+
req.end()
|
|
81
|
+
|
|
82
|
+
storage.enterWith(store)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
makeRequest(() => makeRequest(callback))
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
function byteLength (data) {
|
|
80
89
|
return data.length > 0 ? data.reduce((prev, next) => prev + next.length, 0) : 0
|
|
81
90
|
}
|
|
82
91
|
|
|
92
|
+
Object.defineProperty(request, 'writable', {
|
|
93
|
+
get () {
|
|
94
|
+
return activeRequests < maxActiveRequests
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
83
98
|
module.exports = request
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
|
+
|
|
3
|
+
const request = require('./request')
|
|
2
4
|
const log = require('../../log')
|
|
3
5
|
|
|
4
6
|
class Writer {
|
|
@@ -9,7 +11,10 @@ class Writer {
|
|
|
9
11
|
flush (done = () => {}) {
|
|
10
12
|
const count = this._encoder.count()
|
|
11
13
|
|
|
12
|
-
if (
|
|
14
|
+
if (!request.writable) {
|
|
15
|
+
this._encoder.reset()
|
|
16
|
+
done()
|
|
17
|
+
} else if (count > 0) {
|
|
13
18
|
const payload = this._encoder.makePayload()
|
|
14
19
|
|
|
15
20
|
this._sendPayload(payload, count, done)
|
|
@@ -19,6 +24,8 @@ class Writer {
|
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
append (spans) {
|
|
27
|
+
if (!request.writable) return
|
|
28
|
+
|
|
22
29
|
log.debug(() => `Encoding trace: ${JSON.stringify(spans)}`)
|
|
23
30
|
|
|
24
31
|
this._encode(spans)
|
|
@@ -63,7 +63,7 @@ module.exports = class PluginManager {
|
|
|
63
63
|
|
|
64
64
|
// like instrumenter.enable()
|
|
65
65
|
configure (config = {}) {
|
|
66
|
-
const { logInjection, serviceMapping, experimental } = config
|
|
66
|
+
const { logInjection, serviceMapping, experimental, queryStringObfuscation } = config
|
|
67
67
|
|
|
68
68
|
for (const PluginClass of Object.values(plugins)) {
|
|
69
69
|
const name = PluginClass.name
|
|
@@ -87,6 +87,10 @@ module.exports = class PluginManager {
|
|
|
87
87
|
pluginConfig.logInjection = logInjection
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
if (queryStringObfuscation !== undefined) {
|
|
91
|
+
pluginConfig.queryStringObfuscation = queryStringObfuscation
|
|
92
|
+
}
|
|
93
|
+
|
|
90
94
|
// TODO: update so that it's available for every CI Visibility's plugin
|
|
91
95
|
if (name === 'mocha') {
|
|
92
96
|
pluginConfig.isAgentlessEnabled = experimental && experimental.exporter === 'datadog'
|
|
@@ -15,7 +15,6 @@ module.exports = {
|
|
|
15
15
|
'express': require('../../../datadog-plugin-express/src'),
|
|
16
16
|
'fastify': require('../../../datadog-plugin-fastify/src'),
|
|
17
17
|
'find-my-way': require('../../../datadog-plugin-find-my-way/src'),
|
|
18
|
-
'fs': require('../../../datadog-plugin-fs/src'),
|
|
19
18
|
'google-cloud-pubsub': require('../../../datadog-plugin-google-cloud-pubsub/src'),
|
|
20
19
|
'graphql': require('../../../datadog-plugin-graphql/src'),
|
|
21
20
|
'grpc': require('../../../datadog-plugin-grpc/src'),
|
|
@@ -43,13 +43,15 @@ const web = {
|
|
|
43
43
|
const hooks = getHooks(config)
|
|
44
44
|
const filter = urlFilter.getFilter(config)
|
|
45
45
|
const middleware = getMiddlewareSetting(config)
|
|
46
|
+
const queryStringObfuscation = getQsObfuscator(config)
|
|
46
47
|
|
|
47
48
|
return Object.assign({}, config, {
|
|
48
49
|
headers,
|
|
49
50
|
validateStatus,
|
|
50
51
|
hooks,
|
|
51
52
|
filter,
|
|
52
|
-
middleware
|
|
53
|
+
middleware,
|
|
54
|
+
queryStringObfuscation
|
|
53
55
|
})
|
|
54
56
|
},
|
|
55
57
|
|
|
@@ -318,6 +320,23 @@ const web = {
|
|
|
318
320
|
web.finishSpan(context)
|
|
319
321
|
},
|
|
320
322
|
|
|
323
|
+
obfuscateQs (config, url) {
|
|
324
|
+
const { queryStringObfuscation } = config
|
|
325
|
+
|
|
326
|
+
if (queryStringObfuscation === false) return url
|
|
327
|
+
|
|
328
|
+
const i = url.indexOf('?')
|
|
329
|
+
if (i === -1) return url
|
|
330
|
+
|
|
331
|
+
const path = url.slice(0, i)
|
|
332
|
+
if (queryStringObfuscation === true) return path
|
|
333
|
+
|
|
334
|
+
let qs = url.slice(i + 1)
|
|
335
|
+
|
|
336
|
+
qs = qs.replace(queryStringObfuscation, '<redacted>')
|
|
337
|
+
|
|
338
|
+
return `${path}?${qs}`
|
|
339
|
+
},
|
|
321
340
|
wrapWriteHead (context) {
|
|
322
341
|
const { req, res } = context
|
|
323
342
|
const writeHead = res.writeHead
|
|
@@ -407,11 +426,11 @@ function reactivate (req, fn) {
|
|
|
407
426
|
}
|
|
408
427
|
|
|
409
428
|
function addRequestTags (context) {
|
|
410
|
-
const { req, span } = context
|
|
429
|
+
const { req, span, config } = context
|
|
411
430
|
const url = extractURL(req)
|
|
412
431
|
|
|
413
432
|
span.addTags({
|
|
414
|
-
[HTTP_URL]:
|
|
433
|
+
[HTTP_URL]: web.obfuscateQs(config, url),
|
|
415
434
|
[HTTP_METHOD]: req.method,
|
|
416
435
|
[SPAN_KIND]: SERVER,
|
|
417
436
|
[SPAN_TYPE]: WEB,
|
|
@@ -522,4 +541,30 @@ function getMiddlewareSetting (config) {
|
|
|
522
541
|
return true
|
|
523
542
|
}
|
|
524
543
|
|
|
544
|
+
function getQsObfuscator (config) {
|
|
545
|
+
const obfuscator = config.queryStringObfuscation
|
|
546
|
+
|
|
547
|
+
if (typeof obfuscator === 'boolean') {
|
|
548
|
+
return obfuscator
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
if (typeof obfuscator === 'string') {
|
|
552
|
+
if (obfuscator === '') return false // disable obfuscator
|
|
553
|
+
|
|
554
|
+
if (obfuscator === '.*') return true // optimize full redact
|
|
555
|
+
|
|
556
|
+
try {
|
|
557
|
+
return new RegExp(obfuscator, 'gi')
|
|
558
|
+
} catch (err) {
|
|
559
|
+
log.error(err)
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (config.hasOwnProperty('queryStringObfuscation')) {
|
|
564
|
+
log.error('Expected `queryStringObfuscation` to be a regex string or boolean.')
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return true
|
|
568
|
+
}
|
|
569
|
+
|
|
525
570
|
module.exports = web
|
|
@@ -22,11 +22,6 @@ class Tracer extends BaseTracer {
|
|
|
22
22
|
this._tracer = noop
|
|
23
23
|
this._instrumenter = new Instrumenter(this)
|
|
24
24
|
this._pluginManager = new PluginManager(this)
|
|
25
|
-
this._deprecate = method => log.deprecate(`tracer.${method}`, [
|
|
26
|
-
`tracer.${method}() is deprecated.`,
|
|
27
|
-
'Please use tracer.startSpan() and tracer.scope() instead.',
|
|
28
|
-
'See: https://datadog.github.io/dd-trace-js/#manual-instrumentation.'
|
|
29
|
-
].join(' '))
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
init (options) {
|
|
@@ -126,20 +121,6 @@ class Tracer extends BaseTracer {
|
|
|
126
121
|
return this._tracer.scope.apply(this._tracer, arguments)
|
|
127
122
|
}
|
|
128
123
|
|
|
129
|
-
currentSpan () {
|
|
130
|
-
this._deprecate('currentSpan')
|
|
131
|
-
return this._tracer.currentSpan.apply(this._tracer, arguments)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
bind (callback) {
|
|
135
|
-
this._deprecate('bind')
|
|
136
|
-
return callback
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
bindEmitter () {
|
|
140
|
-
this._deprecate('bindEmitter')
|
|
141
|
-
}
|
|
142
|
-
|
|
143
124
|
getRumData () {
|
|
144
125
|
return this._tracer.getRumData.apply(this._tracer, arguments)
|
|
145
126
|
}
|
|
@@ -2,13 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
const { storage } = require('../../datadog-core')
|
|
4
4
|
|
|
5
|
-
// TODO:
|
|
5
|
+
// TODO: refactor bind to use shimmer once the new internal tracer lands
|
|
6
6
|
|
|
7
7
|
const originals = new WeakMap()
|
|
8
|
-
const listenerMaps = new WeakMap()
|
|
9
|
-
const emitterSpans = new WeakMap()
|
|
10
|
-
const emitterScopes = new WeakMap()
|
|
11
|
-
const emitters = new WeakSet()
|
|
12
8
|
|
|
13
9
|
class Scope {
|
|
14
10
|
active () {
|
|
@@ -39,7 +35,6 @@ class Scope {
|
|
|
39
35
|
}
|
|
40
36
|
|
|
41
37
|
bind (target, span) {
|
|
42
|
-
target = this._bindEmitter(target, span)
|
|
43
38
|
target = this._bindPromise(target, span)
|
|
44
39
|
target = this._bindFn(target, span)
|
|
45
40
|
|
|
@@ -49,7 +44,6 @@ class Scope {
|
|
|
49
44
|
unbind (target) {
|
|
50
45
|
target = this._unbindFn(target)
|
|
51
46
|
target = this._unbindPromise(target)
|
|
52
|
-
target = this._unbindEmitter(target)
|
|
53
47
|
|
|
54
48
|
return target
|
|
55
49
|
}
|
|
@@ -77,37 +71,6 @@ class Scope {
|
|
|
77
71
|
return originals.get(fn) || fn
|
|
78
72
|
}
|
|
79
73
|
|
|
80
|
-
_bindEmitter (emitter, span) {
|
|
81
|
-
if (!this._isEmitter(emitter)) return emitter
|
|
82
|
-
if (!emitters.has(emitter)) {
|
|
83
|
-
Scope._wrapEmitter(emitter)
|
|
84
|
-
}
|
|
85
|
-
emitterSpans.set(emitter, span)
|
|
86
|
-
emitterScopes.set(emitter, this)
|
|
87
|
-
return emitter
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// Occasionally we want to wrap a prototype rather than emitter instances,
|
|
91
|
-
// so we're exposing this as a static method. This gives us a faster
|
|
92
|
-
// path for binding instances of known EventEmitter subclasses.
|
|
93
|
-
static _wrapEmitter (emitter) {
|
|
94
|
-
wrapMethod(emitter, 'addListener', wrapAddListener)
|
|
95
|
-
wrapMethod(emitter, 'prependListener', wrapAddListener)
|
|
96
|
-
wrapMethod(emitter, 'on', wrapAddListener)
|
|
97
|
-
wrapMethod(emitter, 'once', wrapAddListener)
|
|
98
|
-
wrapMethod(emitter, 'removeListener', wrapRemoveListener)
|
|
99
|
-
wrapMethod(emitter, 'off', wrapRemoveListener)
|
|
100
|
-
wrapMethod(emitter, 'removeAllListeners', wrapRemoveAllListeners)
|
|
101
|
-
emitters.add(emitter)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
_unbindEmitter (emitter) {
|
|
105
|
-
if (!this._isEmitter(emitter)) return emitter
|
|
106
|
-
emitterScopes.delete(emitter)
|
|
107
|
-
emitterSpans.delete(emitter)
|
|
108
|
-
return emitter
|
|
109
|
-
}
|
|
110
|
-
|
|
111
74
|
_bindPromise (promise, span) {
|
|
112
75
|
if (!this._isPromise(promise)) return promise
|
|
113
76
|
|
|
@@ -128,31 +91,11 @@ class Scope {
|
|
|
128
91
|
return span !== undefined ? span : this.active()
|
|
129
92
|
}
|
|
130
93
|
|
|
131
|
-
_isEmitter (emitter) {
|
|
132
|
-
return emitter &&
|
|
133
|
-
typeof emitter.emit === 'function' &&
|
|
134
|
-
typeof emitter.on === 'function' &&
|
|
135
|
-
typeof emitter.addListener === 'function' &&
|
|
136
|
-
typeof emitter.removeListener === 'function'
|
|
137
|
-
}
|
|
138
|
-
|
|
139
94
|
_isPromise (promise) {
|
|
140
95
|
return promise && typeof promise.then === 'function'
|
|
141
96
|
}
|
|
142
97
|
}
|
|
143
98
|
|
|
144
|
-
function getScope (emitter) {
|
|
145
|
-
return emitterScopes.get(emitter) || emitterScopes.get(emitter.constructor.prototype)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
function getSpan (emitter) {
|
|
149
|
-
return emitterSpans.get(emitter) || emitterSpans.get(emitter.constructor.prototype)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function hasScope (emitter) {
|
|
153
|
-
return emitterScopes.has(emitter) || emitterScopes.has(emitter.constructor.prototype)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
99
|
function wrapThen (then, scope, span) {
|
|
157
100
|
return function thenWithTrace (onFulfilled, onRejected) {
|
|
158
101
|
const args = new Array(arguments.length)
|
|
@@ -165,74 +108,6 @@ function wrapThen (then, scope, span) {
|
|
|
165
108
|
}
|
|
166
109
|
}
|
|
167
110
|
|
|
168
|
-
function wrapAddListener (addListener) {
|
|
169
|
-
return function addListenerWithTrace (eventName, listener) {
|
|
170
|
-
const scope = getScope(this)
|
|
171
|
-
if (!scope || !listener || originals.has(listener) || listener.listener) {
|
|
172
|
-
return addListener.apply(this, arguments)
|
|
173
|
-
}
|
|
174
|
-
const span = getSpan(this)
|
|
175
|
-
|
|
176
|
-
const bound = scope.bind(listener, scope._spanOrActive(span))
|
|
177
|
-
const listenerMap = listenerMaps.get(this) || {}
|
|
178
|
-
|
|
179
|
-
listenerMaps.set(this, listenerMap)
|
|
180
|
-
|
|
181
|
-
if (!listenerMap[eventName]) {
|
|
182
|
-
listenerMap[eventName] = new WeakMap()
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const events = listenerMap[eventName]
|
|
186
|
-
|
|
187
|
-
if (!events.has(listener)) {
|
|
188
|
-
events.set(listener, [])
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
events.get(listener).push(bound)
|
|
192
|
-
|
|
193
|
-
return addListener.call(this, eventName, bound)
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function wrapRemoveListener (removeListener) {
|
|
198
|
-
return function removeListenerWithTrace (eventName, listener) {
|
|
199
|
-
if (!hasScope(this)) {
|
|
200
|
-
return removeListener.apply(this, arguments)
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const listenerMap = listenerMaps.get(this)
|
|
204
|
-
const listeners = listenerMap && listenerMap[eventName]
|
|
205
|
-
|
|
206
|
-
if (!listener || !listeners || !listeners.has(listener)) {
|
|
207
|
-
return removeListener.apply(this, arguments)
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
for (const bound of listeners.get(listener)) {
|
|
211
|
-
removeListener.call(this, eventName, bound)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
listeners.delete(listener)
|
|
215
|
-
|
|
216
|
-
return removeListener.apply(this, arguments)
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
function wrapRemoveAllListeners (removeAllListeners) {
|
|
221
|
-
return function removeAllListenersWithTrace (eventName) {
|
|
222
|
-
const listenerMap = listenerMaps.get(this)
|
|
223
|
-
|
|
224
|
-
if (hasScope(this) && listenerMap) {
|
|
225
|
-
if (eventName) {
|
|
226
|
-
delete listenerMap[eventName]
|
|
227
|
-
} else {
|
|
228
|
-
listenerMaps.delete(this)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return removeAllListeners.apply(this, arguments)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
111
|
function wrapMethod (target, name, wrapper, ...args) {
|
|
237
112
|
if (!target[name] || originals.has(target[name])) return
|
|
238
113
|
|
package/cypress/plugin.js
DELETED
package/cypress/support.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require('../packages/datadog-plugin-cypress/src/support')
|
|
@@ -1,548 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { storage } = require('../../datadog-core')
|
|
4
|
-
|
|
5
|
-
let kDirReadPromisified
|
|
6
|
-
let kDirClosePromisified
|
|
7
|
-
let kHandle
|
|
8
|
-
|
|
9
|
-
const ddFhSym = Symbol('ddFileHandle')
|
|
10
|
-
|
|
11
|
-
const tagMakers = {
|
|
12
|
-
open: createOpenTags,
|
|
13
|
-
close: createCloseTags,
|
|
14
|
-
readFile: createReadFileTags,
|
|
15
|
-
writeFile: createWriteFileTags,
|
|
16
|
-
appendFile: createAppendFileTags,
|
|
17
|
-
access: createPathTags,
|
|
18
|
-
copyFile: createCopyFileTags,
|
|
19
|
-
stat: createPathTags,
|
|
20
|
-
lstat: createPathTags,
|
|
21
|
-
fstat: createFDTags,
|
|
22
|
-
readdir: createPathTags,
|
|
23
|
-
opendir: createPathTags,
|
|
24
|
-
read: createFDTags,
|
|
25
|
-
write: createFDTags,
|
|
26
|
-
writev: createFDTags,
|
|
27
|
-
chmod: createChmodTags,
|
|
28
|
-
lchmod: createChmodTags,
|
|
29
|
-
fchmod: createFchmodTags,
|
|
30
|
-
chown: createChownTags,
|
|
31
|
-
lchown: createChownTags,
|
|
32
|
-
fchown: createFchownTags,
|
|
33
|
-
realpath: createPathTags,
|
|
34
|
-
readlink: createPathTags,
|
|
35
|
-
unlink: createPathTags,
|
|
36
|
-
symlink: createCopyFileTags,
|
|
37
|
-
link: createCopyFileTags,
|
|
38
|
-
rmdir: createPathTags,
|
|
39
|
-
rename: createCopyFileTags,
|
|
40
|
-
fsync: createFDTags,
|
|
41
|
-
fdatasync: createFDTags,
|
|
42
|
-
mkdir: createPathTags,
|
|
43
|
-
truncate: createPathTags,
|
|
44
|
-
ftruncate: createFDTags,
|
|
45
|
-
utimes: createPathTags,
|
|
46
|
-
futimes: createFDTags,
|
|
47
|
-
mkdtemp: createPathTags
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const promisifiable = ['read', 'readv', 'write', 'writev']
|
|
51
|
-
|
|
52
|
-
const orphanable = false
|
|
53
|
-
|
|
54
|
-
function createWrapCreateReadStream (config, tracer) {
|
|
55
|
-
return function wrapCreateReadStream (createReadStream) {
|
|
56
|
-
return function createReadStreamWithTrace (path, options) {
|
|
57
|
-
if (!hasParent()) {
|
|
58
|
-
return createReadStream.apply(this, arguments)
|
|
59
|
-
}
|
|
60
|
-
const tags = makeFSFlagTags('ReadStream', path, options, 'r', config, tracer)
|
|
61
|
-
return tracer.trace('fs.operation', { tags, orphanable }, (span, done) => {
|
|
62
|
-
const stream = createReadStream.apply(this, arguments)
|
|
63
|
-
stream.once('close', done)
|
|
64
|
-
stream.once('end', done)
|
|
65
|
-
stream.once('error', done)
|
|
66
|
-
return stream
|
|
67
|
-
})
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function createWrapCreateWriteStream (config, tracer) {
|
|
73
|
-
return function wrapCreateWriteStream (createWriteStream) {
|
|
74
|
-
return function createWriteStreamWithTrace (path, options) {
|
|
75
|
-
const tags = makeFSFlagTags('WriteStream', path, options, 'w', config, tracer)
|
|
76
|
-
return tracer.trace('fs.operation', { tags, orphanable }, (span, done) => {
|
|
77
|
-
const stream = createWriteStream.apply(this, arguments)
|
|
78
|
-
stream.once('close', done)
|
|
79
|
-
stream.once('finish', done)
|
|
80
|
-
stream.once('error', done)
|
|
81
|
-
return stream
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function createWrapExists (config, tracer) {
|
|
88
|
-
return function wrapExists (exists) {
|
|
89
|
-
const existsWithTrace = function existsWithTrace (path, cb) {
|
|
90
|
-
if (typeof cb !== 'function') {
|
|
91
|
-
return exists.apply(this, arguments)
|
|
92
|
-
}
|
|
93
|
-
const tags = makeFSTags('exists', path, null, config, tracer)
|
|
94
|
-
return tracer.trace('fs.operation', { tags, orphanable }, (span, done) => {
|
|
95
|
-
arguments[1] = function (result) {
|
|
96
|
-
done()
|
|
97
|
-
cb.apply(this, arguments)
|
|
98
|
-
}
|
|
99
|
-
return exists.apply(this, arguments)
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
copySymbols(exists, existsWithTrace)
|
|
104
|
-
|
|
105
|
-
return existsWithTrace
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function createWrapDirRead (config, tracer, sync) {
|
|
110
|
-
const name = sync ? 'dir.readSync' : 'dir.read'
|
|
111
|
-
return function wrapDirRead (read) {
|
|
112
|
-
function options () {
|
|
113
|
-
const tags = makeFSTags(name, this.path, null, config, tracer)
|
|
114
|
-
return { tags, orphanable }
|
|
115
|
-
}
|
|
116
|
-
return tracer.wrap('fs.operation', options, read, true)
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function createWrapDirClose (config, tracer, sync) {
|
|
121
|
-
const name = sync ? 'dir.closeSync' : 'dir.close'
|
|
122
|
-
return function wrapDirClose (close) {
|
|
123
|
-
function options () {
|
|
124
|
-
const tags = makeFSTags(name, this.path, null, config, tracer)
|
|
125
|
-
return { tags, orphanable }
|
|
126
|
-
}
|
|
127
|
-
return tracer.wrap('fs.operation', options, close, true)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function createWrapDirAsyncIterator (config, tracer, instrumenter) {
|
|
132
|
-
return function wrapDirAsyncIterator (asyncIterator) {
|
|
133
|
-
return function asyncIteratorWithTrace () {
|
|
134
|
-
if (!kDirReadPromisified) {
|
|
135
|
-
const keys = Reflect.ownKeys(this)
|
|
136
|
-
for (const key of keys) {
|
|
137
|
-
if (kDirReadPromisified && kDirClosePromisified) break
|
|
138
|
-
if (typeof key !== 'symbol') continue
|
|
139
|
-
if (!kDirReadPromisified && getSymbolName(key).includes('kDirReadPromisified')) {
|
|
140
|
-
kDirReadPromisified = key
|
|
141
|
-
}
|
|
142
|
-
if (!kDirClosePromisified && getSymbolName(key).includes('kDirClosePromisified')) {
|
|
143
|
-
kDirClosePromisified = key
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
instrumenter.wrap(this, kDirReadPromisified, createWrapDirRead(config, tracer))
|
|
148
|
-
instrumenter.wrap(this, kDirClosePromisified, createWrapKDirClose(config, tracer, instrumenter))
|
|
149
|
-
return asyncIterator.apply(this, arguments)
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
function createWrapKDirClose (config, tracer, instrumenter) {
|
|
155
|
-
return function wrapKDirClose (kDirClose) {
|
|
156
|
-
return function kDirCloseWithTrace () {
|
|
157
|
-
const tags = makeFSTags('dir.close', this.path, null, config, tracer)
|
|
158
|
-
return tracer.trace('fs.operation', { tags, orphanable }, (span) => {
|
|
159
|
-
const p = kDirClose.apply(this, arguments)
|
|
160
|
-
const unwrapBoth = () => {
|
|
161
|
-
instrumenter.unwrap(this, kDirReadPromisified)
|
|
162
|
-
instrumenter.unwrap(this, kDirClosePromisified)
|
|
163
|
-
}
|
|
164
|
-
p.then(unwrapBoth, unwrapBoth)
|
|
165
|
-
return p
|
|
166
|
-
})
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function createOpenTags (resourceName, config, tracer) {
|
|
172
|
-
return function openTags (path, flag, mode) {
|
|
173
|
-
if (!flag || typeof flag === 'function') {
|
|
174
|
-
flag = null
|
|
175
|
-
}
|
|
176
|
-
return makeFSFlagTags(resourceName, path, { flag }, 'r', config, tracer)
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function createCloseTags (resourceName, config, tracer) {
|
|
181
|
-
return function closeTags (fd) {
|
|
182
|
-
if (typeof fd === 'undefined' && this && this[ddFhSym]) {
|
|
183
|
-
fd = this[ddFhSym].fd
|
|
184
|
-
}
|
|
185
|
-
if (typeof fd !== 'number' || !Number.isInteger(fd)) {
|
|
186
|
-
return
|
|
187
|
-
}
|
|
188
|
-
return makeFSTags(resourceName, fd, null, config, tracer)
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function createReadFileTags (resourceName, config, tracer) {
|
|
193
|
-
return function readFileTags (path, options) {
|
|
194
|
-
return makeFSFlagTags(resourceName, path, options, 'r', config, tracer)
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function createWriteFileTags (resourceName, config, tracer) {
|
|
199
|
-
return function writeFileTags (path, data, options) {
|
|
200
|
-
return makeFSFlagTags(resourceName, path, options, 'w', config, tracer)
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
function createAppendFileTags (resourceName, config, tracer) {
|
|
205
|
-
return function appendFileTags (path, data, options) {
|
|
206
|
-
return makeFSFlagTags(resourceName, path, options, 'a', config, tracer)
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function createCopyFileTags (resourceName, config, tracer) {
|
|
211
|
-
return function copyFileTags (src, dest, flag) {
|
|
212
|
-
return makeFSTags(resourceName, { src, dest }, null, config, tracer)
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function createChmodTags (resourceName, config, tracer) {
|
|
217
|
-
return function chmodTags (fd, mode) {
|
|
218
|
-
const tags = makeFSTags(resourceName, fd, null, config, tracer)
|
|
219
|
-
tags['file.mode'] = mode.toString(8)
|
|
220
|
-
return tags
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
function createFchmodTags (resourceName, config, tracer) {
|
|
225
|
-
return function fchmodTags (fd, mode) {
|
|
226
|
-
if (typeof this === 'object' && this !== null && this.fd) {
|
|
227
|
-
mode = fd
|
|
228
|
-
fd = this.fd
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const tags = makeFSTags(resourceName, fd, null, config, tracer)
|
|
232
|
-
if (mode) {
|
|
233
|
-
tags['file.mode'] = mode.toString(8)
|
|
234
|
-
}
|
|
235
|
-
return tags
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
function createPathTags (resourceName, config, tracer) {
|
|
240
|
-
return function pathTags (path) {
|
|
241
|
-
return makeFSTags(resourceName, path, null, config, tracer)
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
function createFDTags (resourceName, config, tracer) {
|
|
246
|
-
return function fdTags (fd) {
|
|
247
|
-
if (typeof this === 'object' && this !== null && this.fd) {
|
|
248
|
-
fd = this.fd
|
|
249
|
-
}
|
|
250
|
-
return makeFSTags(resourceName, fd, null, config, tracer)
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
function createChownTags (resourceName, config, tracer) {
|
|
255
|
-
return function chownTags (fd, uid, gid) {
|
|
256
|
-
const tags = makeFSTags(resourceName, fd, null, config, tracer)
|
|
257
|
-
if (typeof uid === 'number') {
|
|
258
|
-
tags['file.uid'] = uid.toString()
|
|
259
|
-
}
|
|
260
|
-
if (typeof gid === 'number') {
|
|
261
|
-
tags['file.gid'] = gid.toString()
|
|
262
|
-
}
|
|
263
|
-
return tags
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function createFchownTags (resourceName, config, tracer) {
|
|
268
|
-
return function fchownTags (fd, uid, gid) {
|
|
269
|
-
if (typeof this === 'object' && this !== null && this.fd) {
|
|
270
|
-
gid = uid
|
|
271
|
-
uid = fd
|
|
272
|
-
fd = this.fd
|
|
273
|
-
}
|
|
274
|
-
const tags = makeFSTags(resourceName, fd, null, config, tracer)
|
|
275
|
-
if (typeof uid === 'number') {
|
|
276
|
-
tags['file.uid'] = uid.toString()
|
|
277
|
-
}
|
|
278
|
-
if (typeof gid === 'number') {
|
|
279
|
-
tags['file.gid'] = gid.toString()
|
|
280
|
-
}
|
|
281
|
-
return tags
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
function getSymbolName (sym) {
|
|
286
|
-
return sym.description || sym.toString()
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
function hasParent () {
|
|
290
|
-
const store = storage.getStore()
|
|
291
|
-
|
|
292
|
-
return store && store.span && !store.noop
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
function createWrapCb (tracer, config, name, tagMaker) {
|
|
296
|
-
const makeTags = tagMaker(name, config, tracer)
|
|
297
|
-
return function wrapFunction (fn) {
|
|
298
|
-
return tracer.wrap('fs.operation', function () {
|
|
299
|
-
if (typeof arguments[arguments.length - 1] !== 'function') {
|
|
300
|
-
return
|
|
301
|
-
}
|
|
302
|
-
const tags = makeTags.apply(this, arguments)
|
|
303
|
-
return tags ? { tags, orphanable } : { orphanable }
|
|
304
|
-
}, fn, true)
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function createWrap (tracer, config, name, tagMaker) {
|
|
309
|
-
const makeTags = tagMaker(name, config, tracer)
|
|
310
|
-
|
|
311
|
-
return function wrapSyncFunction (fn) {
|
|
312
|
-
return tracer.wrap('fs.operation', function () {
|
|
313
|
-
const tags = makeTags.apply(this, arguments)
|
|
314
|
-
return tags ? { tags, orphanable } : { orphanable }
|
|
315
|
-
}, fn, true)
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
function makeFSFlagTags (resourceName, path, options, defaultFlag, config, tracer) {
|
|
320
|
-
const tags = makeFSTags(resourceName, path, options, config, tracer)
|
|
321
|
-
|
|
322
|
-
if (tags) {
|
|
323
|
-
let flag = defaultFlag
|
|
324
|
-
if (typeof options === 'object' && options !== null) {
|
|
325
|
-
if (options.flag) {
|
|
326
|
-
flag = options.flag
|
|
327
|
-
} else if (options.flags) {
|
|
328
|
-
flag = options.flags
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
tags['file.flag'] = flag
|
|
332
|
-
return tags
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function makeFSTags (resourceName, path, options, config, tracer) {
|
|
337
|
-
path = options && typeof options === 'object' && 'fd' in options ? options.fd : path
|
|
338
|
-
const tags = {
|
|
339
|
-
'component': 'fs',
|
|
340
|
-
'span.kind': 'internal',
|
|
341
|
-
'resource.name': resourceName,
|
|
342
|
-
'service.name': config.service || tracer._service
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
switch (typeof path) {
|
|
346
|
-
case 'object': {
|
|
347
|
-
if (path === null) return tags
|
|
348
|
-
const src = 'src' in path ? path.src : null
|
|
349
|
-
const dest = 'dest' in path ? path.dest : null
|
|
350
|
-
if (src || dest) {
|
|
351
|
-
tags['file.src'] = src
|
|
352
|
-
tags['file.dest'] = dest
|
|
353
|
-
} else {
|
|
354
|
-
tags['file.path'] = path
|
|
355
|
-
}
|
|
356
|
-
break
|
|
357
|
-
}
|
|
358
|
-
case 'string': {
|
|
359
|
-
tags['file.path'] = path
|
|
360
|
-
break
|
|
361
|
-
}
|
|
362
|
-
case 'number': {
|
|
363
|
-
tags['file.descriptor'] = path.toString()
|
|
364
|
-
break
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
return tags
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function copySymbols (from, to) {
|
|
372
|
-
const props = Object.getOwnPropertyDescriptors(from)
|
|
373
|
-
const keys = Reflect.ownKeys(props)
|
|
374
|
-
|
|
375
|
-
for (const key of keys) {
|
|
376
|
-
if (typeof key !== 'symbol' || to.hasOwnProperty(key)) continue
|
|
377
|
-
|
|
378
|
-
Object.defineProperty(to, key, props[key])
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function getFileHandlePrototype (fs) {
|
|
383
|
-
return fs.promises.open(__filename, 'r')
|
|
384
|
-
.then(fh => {
|
|
385
|
-
if (!kHandle) {
|
|
386
|
-
kHandle = Reflect.ownKeys(fh).find(key => typeof key === 'symbol' && key.toString().includes('kHandle'))
|
|
387
|
-
}
|
|
388
|
-
fh.close()
|
|
389
|
-
|
|
390
|
-
return Object.getPrototypeOf(fh)
|
|
391
|
-
})
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
function patchClassicFunctions (fs, tracer, config) {
|
|
395
|
-
for (const name in fs) {
|
|
396
|
-
if (!fs[name]) continue
|
|
397
|
-
const tagMakerName = name.endsWith('Sync') ? name.substr(0, name.length - 4) : name
|
|
398
|
-
const original = fs[name]
|
|
399
|
-
if (tagMakerName in tagMakers) {
|
|
400
|
-
const tagMaker = tagMakers[tagMakerName]
|
|
401
|
-
if (name.endsWith('Sync')) {
|
|
402
|
-
this.wrap(fs, name, createWrap(tracer, config, name, tagMaker))
|
|
403
|
-
} else {
|
|
404
|
-
this.wrap(fs, name, createWrapCb(tracer, config, name, tagMaker))
|
|
405
|
-
}
|
|
406
|
-
if (name in promisifiable) {
|
|
407
|
-
copySymbols(original, fs[name])
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function patchFileHandle (fs, tracer, config) {
|
|
414
|
-
getFileHandlePrototype(fs).then((fileHandlePrototype) => {
|
|
415
|
-
for (const name of Reflect.ownKeys(fileHandlePrototype)) {
|
|
416
|
-
if (typeof name !== 'string' || name === 'constructor' || name === 'fd' || name === 'getAsyncId') {
|
|
417
|
-
continue
|
|
418
|
-
}
|
|
419
|
-
let tagMaker
|
|
420
|
-
const fName = 'f' + name
|
|
421
|
-
if (fName in tagMakers) {
|
|
422
|
-
tagMaker = tagMakers[fName]
|
|
423
|
-
} else {
|
|
424
|
-
tagMaker = createFDTags
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const instrumenter = this
|
|
428
|
-
|
|
429
|
-
const desc = Reflect.getOwnPropertyDescriptor(fileHandlePrototype, kHandle)
|
|
430
|
-
if (!desc || !desc.get) {
|
|
431
|
-
Reflect.defineProperty(fileHandlePrototype, kHandle, {
|
|
432
|
-
get () {
|
|
433
|
-
return this[ddFhSym]
|
|
434
|
-
},
|
|
435
|
-
set (h) {
|
|
436
|
-
this[ddFhSym] = h
|
|
437
|
-
instrumenter.wrap(this, 'close', createWrap(tracer, config, 'filehandle.close', tagMakers.close))
|
|
438
|
-
},
|
|
439
|
-
configurable: true
|
|
440
|
-
})
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
this.wrap(fileHandlePrototype, name, createWrap(tracer, config, 'filehandle.' + name, tagMaker))
|
|
444
|
-
}
|
|
445
|
-
})
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
function patchPromiseFunctions (fs, tracer, config) {
|
|
449
|
-
for (const name in fs.promises) {
|
|
450
|
-
if (name in tagMakers) {
|
|
451
|
-
const tagMaker = tagMakers[name]
|
|
452
|
-
this.wrap(fs.promises, name, createWrap(tracer, config, 'promises.' + name, tagMaker))
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
function patchDirFunctions (fs, tracer, config) {
|
|
458
|
-
this.wrap(fs.Dir.prototype, 'close', createWrapDirClose(config, tracer))
|
|
459
|
-
this.wrap(fs.Dir.prototype, 'closeSync', createWrapDirClose(config, tracer, true))
|
|
460
|
-
this.wrap(fs.Dir.prototype, 'read', createWrapDirRead(config, tracer))
|
|
461
|
-
this.wrap(fs.Dir.prototype, 'readSync', createWrapDirRead(config, tracer, true))
|
|
462
|
-
this.wrap(fs.Dir.prototype, Symbol.asyncIterator, createWrapDirAsyncIterator(config, tracer, this))
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
function unpatchClassicFunctions (fs) {
|
|
466
|
-
for (const name in fs) {
|
|
467
|
-
if (!fs[name]) continue
|
|
468
|
-
const tagMakerName = name.endsWith('Sync') ? name.substr(0, name.length - 4) : name
|
|
469
|
-
if (tagMakerName in tagMakers) {
|
|
470
|
-
this.unwrap(fs, name)
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
function unpatchFileHandle (fs) {
|
|
476
|
-
getFileHandlePrototype(fs).then(fileHandlePrototype => {
|
|
477
|
-
for (const name of Reflect.ownKeys(fileHandlePrototype)) {
|
|
478
|
-
if (typeof name !== 'string' || name === 'constructor' || name === 'fd' || name === 'getAsyncId') {
|
|
479
|
-
continue
|
|
480
|
-
}
|
|
481
|
-
this.unwrap(fileHandlePrototype, name)
|
|
482
|
-
}
|
|
483
|
-
delete fileHandlePrototype[kHandle]
|
|
484
|
-
})
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
function unpatchPromiseFunctions (fs) {
|
|
488
|
-
for (const name in fs.promises) {
|
|
489
|
-
if (name in tagMakers) {
|
|
490
|
-
this.unwrap(fs.promises, name)
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
function unpatchDirFunctions (fs) {
|
|
496
|
-
this.unwrap(fs.Dir.prototype, 'close')
|
|
497
|
-
this.unwrap(fs.Dir.prototype, 'closeSync')
|
|
498
|
-
this.unwrap(fs.Dir.prototype, 'read')
|
|
499
|
-
this.unwrap(fs.Dir.prototype, 'readSync')
|
|
500
|
-
this.unwrap(fs.Dir.prototype, Symbol.asyncIterator)
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
module.exports = {
|
|
504
|
-
name: 'fs',
|
|
505
|
-
patch (fs, tracer, config) {
|
|
506
|
-
const realpathNative = fs.realpath.native
|
|
507
|
-
const realpathSyncNative = fs.realpathSync.native
|
|
508
|
-
patchClassicFunctions.call(this, fs, tracer, config)
|
|
509
|
-
if (fs.promises) {
|
|
510
|
-
patchFileHandle.call(this, fs, tracer, config)
|
|
511
|
-
patchPromiseFunctions.call(this, fs, tracer, config)
|
|
512
|
-
}
|
|
513
|
-
if (fs.Dir) {
|
|
514
|
-
patchDirFunctions.call(this, fs, tracer, config)
|
|
515
|
-
}
|
|
516
|
-
this.wrap(fs, 'createReadStream', createWrapCreateReadStream(config, tracer))
|
|
517
|
-
this.wrap(fs, 'createWriteStream', createWrapCreateWriteStream(config, tracer))
|
|
518
|
-
this.wrap(fs, 'existsSync', createWrap(tracer, config, 'existsSync', createPathTags))
|
|
519
|
-
this.wrap(fs, 'exists', createWrapExists(config, tracer))
|
|
520
|
-
if (realpathNative) {
|
|
521
|
-
fs.realpath.native = createWrapCb(tracer, config, 'realpath.native', createPathTags)(realpathNative)
|
|
522
|
-
}
|
|
523
|
-
if (realpathSyncNative) {
|
|
524
|
-
fs.realpathSync.native = createWrap(tracer, config, 'realpath.native', createPathTags)(realpathSyncNative)
|
|
525
|
-
}
|
|
526
|
-
},
|
|
527
|
-
unpatch (fs) {
|
|
528
|
-
unpatchClassicFunctions.call(this, fs)
|
|
529
|
-
if (fs.promises) {
|
|
530
|
-
unpatchFileHandle.call(this, fs)
|
|
531
|
-
unpatchPromiseFunctions.call(this, fs)
|
|
532
|
-
}
|
|
533
|
-
if (fs.Dir) {
|
|
534
|
-
unpatchDirFunctions.call(this, fs)
|
|
535
|
-
}
|
|
536
|
-
this.unwrap(fs, 'createReadStream')
|
|
537
|
-
this.unwrap(fs, 'createWriteStream')
|
|
538
|
-
this.unwrap(fs, 'existsSync')
|
|
539
|
-
this.unwrap(fs, 'exists')
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
/** TODO fs functions:
|
|
544
|
-
|
|
545
|
-
unwatchFile
|
|
546
|
-
watch
|
|
547
|
-
watchFile
|
|
548
|
-
*/
|