dd-trace 2.0.0-appsec-beta.3 → 2.0.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/MIGRATING.md +65 -0
- package/NOTICE +4 -0
- package/ci/cypress/plugin.js +3 -0
- package/ci/cypress/support.js +1 -0
- package/ci/init.js +13 -0
- package/ci/jest/env.js +14 -0
- package/index.d.ts +35 -48
- package/package.json +7 -4
- package/packages/datadog-instrumentations/index.js +10 -0
- package/packages/datadog-instrumentations/src/bluebird.js +26 -0
- package/packages/datadog-instrumentations/src/dns.js +94 -0
- package/packages/datadog-instrumentations/src/helpers/instrument.js +120 -0
- package/packages/datadog-instrumentations/src/helpers/promise.js +29 -0
- package/packages/datadog-instrumentations/src/memcached.js +53 -0
- package/packages/datadog-instrumentations/src/mysql.js +67 -0
- package/packages/datadog-instrumentations/src/promise-js.js +15 -0
- package/packages/datadog-instrumentations/src/promise.js +14 -0
- package/packages/datadog-instrumentations/src/q.js +13 -0
- package/packages/datadog-instrumentations/src/when.js +14 -0
- package/packages/datadog-plugin-cucumber/src/index.js +4 -4
- package/packages/datadog-plugin-cypress/src/plugin.js +12 -2
- package/packages/datadog-plugin-cypress/src/support.js +21 -6
- package/packages/datadog-plugin-dns/src/index.js +65 -178
- package/packages/datadog-plugin-fs/src/index.js +7 -3
- package/packages/datadog-plugin-http/src/client.js +9 -24
- package/packages/datadog-plugin-http/src/server.js +5 -0
- package/packages/datadog-plugin-http2/src/client.js +1 -24
- package/packages/datadog-plugin-http2/src/server.js +2 -2
- package/packages/datadog-plugin-jest/src/jest-environment.js +4 -4
- package/packages/datadog-plugin-jest/src/jest-jasmine2.js +2 -2
- package/packages/datadog-plugin-knex/src/index.js +3 -3
- package/packages/datadog-plugin-memcached/src/index.js +41 -63
- package/packages/datadog-plugin-mocha/src/index.js +3 -2
- package/packages/datadog-plugin-moleculer/src/client.js +60 -0
- package/packages/datadog-plugin-moleculer/src/index.js +8 -0
- package/packages/datadog-plugin-moleculer/src/server.js +61 -0
- package/packages/datadog-plugin-moleculer/src/util.js +21 -0
- package/packages/datadog-plugin-mongoose/src/index.js +2 -2
- package/packages/datadog-plugin-mysql/src/index.js +37 -89
- package/packages/datadog-plugin-net/src/index.js +5 -0
- package/packages/datadog-plugin-pino/src/index.js +25 -1
- package/packages/datadog-plugin-redis/src/index.js +31 -1
- package/packages/datadog-plugin-router/src/index.js +28 -3
- package/packages/dd-trace/lib/version.js +1 -1
- package/packages/dd-trace/src/appsec/addresses.js +11 -4
- package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +5 -8
- package/packages/dd-trace/src/{gateway → appsec/gateway}/als.js +1 -0
- package/packages/dd-trace/src/appsec/gateway/channels.js +11 -0
- package/packages/dd-trace/src/{gateway → appsec/gateway}/engine/engine.js +20 -30
- package/packages/dd-trace/src/{gateway → appsec/gateway}/engine/index.js +0 -0
- package/packages/dd-trace/src/{gateway → appsec/gateway}/engine/runner.js +2 -0
- package/packages/dd-trace/src/appsec/index.js +54 -38
- package/packages/dd-trace/src/appsec/recommended.json +1 -1
- package/packages/dd-trace/src/appsec/reporter.js +27 -10
- package/packages/dd-trace/src/config.js +31 -27
- package/packages/dd-trace/src/constants.js +6 -3
- package/packages/dd-trace/src/exporters/agent/request.js +8 -0
- package/packages/dd-trace/src/format.js +26 -39
- package/packages/dd-trace/src/instrumenter.js +6 -1
- package/packages/dd-trace/src/log.js +6 -15
- package/packages/dd-trace/src/noop/span_context.js +0 -1
- package/packages/dd-trace/src/noop/tracer.js +0 -6
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +79 -46
- package/packages/dd-trace/src/opentracing/span.js +2 -7
- package/packages/dd-trace/src/opentracing/span_context.js +2 -4
- package/packages/dd-trace/src/opentracing/tracer.js +5 -23
- package/packages/dd-trace/src/plugin_manager.js +65 -0
- package/packages/dd-trace/src/plugins/index.js +1 -5
- package/packages/dd-trace/src/plugins/plugin.js +63 -0
- package/packages/dd-trace/src/plugins/util/ci.js +13 -4
- package/packages/dd-trace/src/plugins/util/redis.js +0 -2
- package/packages/dd-trace/src/plugins/util/test.js +9 -4
- package/packages/dd-trace/src/plugins/util/user-provided-git.js +17 -2
- package/packages/dd-trace/src/plugins/util/web.js +6 -16
- package/packages/dd-trace/src/priority_sampler.js +71 -19
- package/packages/dd-trace/src/profiling/exporters/agent.js +35 -34
- package/packages/dd-trace/src/proxy.js +39 -35
- package/packages/dd-trace/src/ritm.js +40 -16
- package/packages/dd-trace/src/span_processor.js +0 -7
- package/packages/dd-trace/src/tracer.js +5 -6
- package/scripts/install_plugin_modules.js +30 -1
- package/packages/datadog-plugin-bluebird/src/index.js +0 -69
- package/packages/datadog-plugin-promise/src/index.js +0 -17
- package/packages/datadog-plugin-promise-js/src/index.js +0 -20
- package/packages/datadog-plugin-q/src/index.js +0 -16
- package/packages/datadog-plugin-when/src/index.js +0 -17
- package/packages/dd-trace/src/gateway/channels.js +0 -8
- package/packages/dd-trace/src/gateway/dc_block.js +0 -68
- package/packages/dd-trace/src/plugins/util/ci-app-spec.json +0 -36
- package/packages/dd-trace/src/plugins/util/promise.js +0 -31
- package/packages/dd-trace/src/scope/noop/scope_manager.js +0 -28
|
@@ -8,7 +8,7 @@ const tags = require('../../../../../ext/tags')
|
|
|
8
8
|
const types = require('../../../../../ext/types')
|
|
9
9
|
const kinds = require('../../../../../ext/kinds')
|
|
10
10
|
const urlFilter = require('./urlfilter')
|
|
11
|
-
const {
|
|
11
|
+
const { incomingHttpRequestEnd } = require('../../appsec/gateway/channels')
|
|
12
12
|
|
|
13
13
|
const WEB = types.WEB
|
|
14
14
|
const SERVER = kinds.SERVER
|
|
@@ -23,6 +23,7 @@ const HTTP_STATUS_CODE = tags.HTTP_STATUS_CODE
|
|
|
23
23
|
const HTTP_ROUTE = tags.HTTP_ROUTE
|
|
24
24
|
const HTTP_REQUEST_HEADERS = tags.HTTP_REQUEST_HEADERS
|
|
25
25
|
const HTTP_RESPONSE_HEADERS = tags.HTTP_RESPONSE_HEADERS
|
|
26
|
+
const MANUAL_DROP = tags.MANUAL_DROP
|
|
26
27
|
|
|
27
28
|
const HTTP2_HEADER_AUTHORITY = ':authority'
|
|
28
29
|
const HTTP2_HEADER_SCHEME = ':scheme'
|
|
@@ -54,9 +55,8 @@ const web = {
|
|
|
54
55
|
|
|
55
56
|
const span = startSpan(tracer, config, req, res, name)
|
|
56
57
|
|
|
57
|
-
// TODO: replace this with a REFERENCE_NOOP after we split http/express/etc
|
|
58
58
|
if (!config.filter(req.url)) {
|
|
59
|
-
span.
|
|
59
|
+
span.setTag(MANUAL_DROP, true)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
if (config.service) {
|
|
@@ -72,17 +72,7 @@ const web = {
|
|
|
72
72
|
req._datadog.instrumented = true
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
76
|
-
return tracer.scope().activate(span, () => {
|
|
77
|
-
if (INCOMING_HTTP_REQUEST_START.hasSubscribers) {
|
|
78
|
-
INCOMING_HTTP_REQUEST_START.publish({ req, res })
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
callback(span)
|
|
82
|
-
})
|
|
83
|
-
} else if (INCOMING_HTTP_REQUEST_START.hasSubscribers) {
|
|
84
|
-
INCOMING_HTTP_REQUEST_START.publish({ req, res })
|
|
85
|
-
}
|
|
75
|
+
return callback && tracer.scope().activate(span, () => callback(span))
|
|
86
76
|
},
|
|
87
77
|
|
|
88
78
|
// Reactivate the request scope in case it was changed by a middleware.
|
|
@@ -277,7 +267,7 @@ function wrapEnd (req) {
|
|
|
277
267
|
|
|
278
268
|
finishMiddleware(req, res)
|
|
279
269
|
|
|
280
|
-
if (
|
|
270
|
+
if (incomingHttpRequestEnd.hasSubscribers) incomingHttpRequestEnd.publish({ req, res })
|
|
281
271
|
|
|
282
272
|
const returnValue = end.apply(res, arguments)
|
|
283
273
|
|
|
@@ -320,7 +310,7 @@ function addAllowHeaders (req, headers) {
|
|
|
320
310
|
const contextHeaders = [
|
|
321
311
|
'x-datadog-origin',
|
|
322
312
|
'x-datadog-parent-id',
|
|
323
|
-
'x-datadog-sampled',
|
|
313
|
+
'x-datadog-sampled', // Deprecated, but still accept it in case it's sent.
|
|
324
314
|
'x-datadog-sampling-priority',
|
|
325
315
|
'x-datadog-trace-id'
|
|
326
316
|
]
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
+
const coalesce = require('koalas')
|
|
3
4
|
const RateLimiter = require('./rate_limiter')
|
|
4
5
|
const Sampler = require('./sampler')
|
|
5
6
|
const ext = require('../../../ext')
|
|
6
7
|
const { setSamplingRules } = require('./startup-log')
|
|
7
8
|
|
|
8
9
|
const {
|
|
10
|
+
SAMPLING_MECHANISM_DEFAULT,
|
|
11
|
+
SAMPLING_MECHANISM_AGENT,
|
|
12
|
+
SAMPLING_MECHANISM_RULE,
|
|
13
|
+
SAMPLING_MECHANISM_MANUAL,
|
|
9
14
|
SAMPLING_RULE_DECISION,
|
|
10
15
|
SAMPLING_LIMIT_DECISION,
|
|
11
|
-
SAMPLING_AGENT_DECISION
|
|
16
|
+
SAMPLING_AGENT_DECISION,
|
|
17
|
+
UPSTREAM_SERVICES_KEY
|
|
12
18
|
} = require('./constants')
|
|
13
19
|
|
|
14
20
|
const SERVICE_NAME = ext.tags.SERVICE_NAME
|
|
@@ -21,6 +27,9 @@ const AUTO_KEEP = ext.priority.AUTO_KEEP
|
|
|
21
27
|
const USER_KEEP = ext.priority.USER_KEEP
|
|
22
28
|
const DEFAULT_KEY = 'service:,env:'
|
|
23
29
|
|
|
30
|
+
const defaultSampler = new Sampler(AUTO_KEEP)
|
|
31
|
+
const serviceNames = new Map()
|
|
32
|
+
|
|
24
33
|
class PrioritySampler {
|
|
25
34
|
constructor (env, { sampleRate, rateLimit = 100, rules = [] } = {}) {
|
|
26
35
|
this._env = env
|
|
@@ -33,12 +42,8 @@ class PrioritySampler {
|
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
isSampled (span) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return rule
|
|
40
|
-
? this._isSampledByRule(context, rule) && this._isSampledByRateLimit(context)
|
|
41
|
-
: this._isSampledByAgent(context)
|
|
45
|
+
const priority = this._getPriorityFromAuto(span)
|
|
46
|
+
return priority === USER_KEEP || priority === AUTO_KEEP
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
sample (span, auto = true) {
|
|
@@ -50,16 +55,18 @@ class PrioritySampler {
|
|
|
50
55
|
if (context._sampling.priority !== undefined) return
|
|
51
56
|
if (!root) return // noop span
|
|
52
57
|
|
|
53
|
-
const tag = this.
|
|
58
|
+
const tag = this._getPriorityFromTags(context._tags)
|
|
54
59
|
|
|
55
60
|
if (this.validate(tag)) {
|
|
56
61
|
context._sampling.priority = tag
|
|
62
|
+
context._sampling.mechanism = SAMPLING_MECHANISM_MANUAL
|
|
63
|
+
} else if (auto) {
|
|
64
|
+
context._sampling.priority = this._getPriorityFromAuto(root)
|
|
65
|
+
} else {
|
|
57
66
|
return
|
|
58
67
|
}
|
|
59
68
|
|
|
60
|
-
|
|
61
|
-
context._sampling.priority = this.isSampled(root) ? AUTO_KEEP : AUTO_REJECT
|
|
62
|
-
}
|
|
69
|
+
this._addUpstreamService(root)
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
update (rates) {
|
|
@@ -72,7 +79,7 @@ class PrioritySampler {
|
|
|
72
79
|
samplers[key] = sampler
|
|
73
80
|
}
|
|
74
81
|
|
|
75
|
-
samplers[DEFAULT_KEY] = samplers[DEFAULT_KEY] ||
|
|
82
|
+
samplers[DEFAULT_KEY] = samplers[DEFAULT_KEY] || defaultSampler
|
|
76
83
|
|
|
77
84
|
this._samplers = samplers
|
|
78
85
|
}
|
|
@@ -93,7 +100,16 @@ class PrioritySampler {
|
|
|
93
100
|
return typeof span.context === 'function' ? span.context() : span
|
|
94
101
|
}
|
|
95
102
|
|
|
96
|
-
|
|
103
|
+
_getPriorityFromAuto (span) {
|
|
104
|
+
const context = this._getContext(span)
|
|
105
|
+
const rule = this._findRule(context)
|
|
106
|
+
|
|
107
|
+
return rule
|
|
108
|
+
? this._getPriorityByRule(context, rule)
|
|
109
|
+
: this._getPriorityByAgent(context)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
_getPriorityFromTags (tags) {
|
|
97
113
|
if (tags.hasOwnProperty(MANUAL_KEEP) && tags[MANUAL_KEEP] !== false) {
|
|
98
114
|
return USER_KEEP
|
|
99
115
|
} else if (tags.hasOwnProperty(MANUAL_DROP) && tags[MANUAL_DROP] !== false) {
|
|
@@ -109,10 +125,11 @@ class PrioritySampler {
|
|
|
109
125
|
}
|
|
110
126
|
}
|
|
111
127
|
|
|
112
|
-
|
|
128
|
+
_getPriorityByRule (context, rule) {
|
|
113
129
|
context._trace[SAMPLING_RULE_DECISION] = rule.sampleRate
|
|
130
|
+
context._sampling.mechanism = SAMPLING_MECHANISM_RULE
|
|
114
131
|
|
|
115
|
-
return rule.sampler.isSampled(context)
|
|
132
|
+
return rule.sampler.isSampled(context) && this._isSampledByRateLimit(context) ? USER_KEEP : USER_REJECT
|
|
116
133
|
}
|
|
117
134
|
|
|
118
135
|
_isSampledByRateLimit (context) {
|
|
@@ -123,13 +140,48 @@ class PrioritySampler {
|
|
|
123
140
|
return allowed
|
|
124
141
|
}
|
|
125
142
|
|
|
126
|
-
|
|
143
|
+
_getPriorityByAgent (context) {
|
|
127
144
|
const key = `service:${context._tags[SERVICE_NAME]},env:${this._env}`
|
|
128
145
|
const sampler = this._samplers[key] || this._samplers[DEFAULT_KEY]
|
|
129
146
|
|
|
130
147
|
context._trace[SAMPLING_AGENT_DECISION] = sampler.rate()
|
|
131
148
|
|
|
132
|
-
|
|
149
|
+
if (sampler === defaultSampler) {
|
|
150
|
+
context._sampling.mechanism = SAMPLING_MECHANISM_DEFAULT
|
|
151
|
+
} else {
|
|
152
|
+
context._sampling.mechanism = SAMPLING_MECHANISM_AGENT
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return sampler.isSampled(context) ? AUTO_KEEP : AUTO_REJECT
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
_addUpstreamService (span) {
|
|
159
|
+
const context = span.context()
|
|
160
|
+
const trace = context._trace
|
|
161
|
+
const service = this._toBase64(context._tags['service.name'])
|
|
162
|
+
const priority = context._sampling.priority
|
|
163
|
+
const mechanism = context._sampling.mechanism
|
|
164
|
+
const rate = Math.ceil(coalesce(
|
|
165
|
+
context._trace[SAMPLING_RULE_DECISION],
|
|
166
|
+
context._trace[SAMPLING_AGENT_DECISION]
|
|
167
|
+
) * 10000) / 10000
|
|
168
|
+
const group = `${service}|${priority}|${mechanism}|${rate}`
|
|
169
|
+
const groups = trace.tags[UPSTREAM_SERVICES_KEY]
|
|
170
|
+
? `${trace.tags[UPSTREAM_SERVICES_KEY]};${group}`
|
|
171
|
+
: group
|
|
172
|
+
|
|
173
|
+
trace.tags[UPSTREAM_SERVICES_KEY] = groups
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
_toBase64 (serviceName) {
|
|
177
|
+
let encoded = serviceNames.get(serviceName)
|
|
178
|
+
|
|
179
|
+
if (!encoded) {
|
|
180
|
+
encoded = Buffer.from(serviceName).toString('base64')
|
|
181
|
+
serviceNames.set(serviceName, encoded)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return encoded
|
|
133
185
|
}
|
|
134
186
|
|
|
135
187
|
_normalizeRules (rules, sampleRate) {
|
|
@@ -151,9 +203,9 @@ class PrioritySampler {
|
|
|
151
203
|
const service = context._tags['service.name']
|
|
152
204
|
|
|
153
205
|
if (rule.name instanceof RegExp && !rule.name.test(name)) return false
|
|
154
|
-
if (rule.name && rule.name !== name) return false
|
|
206
|
+
if (typeof rule.name === 'string' && rule.name !== name) return false
|
|
155
207
|
if (rule.service instanceof RegExp && !rule.service.test(service)) return false
|
|
156
|
-
if (rule.service && rule.service !== service) return false
|
|
208
|
+
if (typeof rule.service === 'string' && rule.service !== service) return false
|
|
157
209
|
|
|
158
210
|
return true
|
|
159
211
|
}
|
|
@@ -40,7 +40,7 @@ function computeRetries (uploadTimeout) {
|
|
|
40
40
|
tries++
|
|
41
41
|
uploadTimeout /= 2
|
|
42
42
|
}
|
|
43
|
-
return [tries, uploadTimeout]
|
|
43
|
+
return [tries, Math.floor(uploadTimeout)]
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
class AgentExporter {
|
|
@@ -55,7 +55,6 @@ class AgentExporter {
|
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
export ({ profiles, start, end, tags }) {
|
|
58
|
-
const form = new FormData()
|
|
59
58
|
const types = Object.keys(profiles)
|
|
60
59
|
|
|
61
60
|
const fields = [
|
|
@@ -75,10 +74,6 @@ class AgentExporter {
|
|
|
75
74
|
...Object.entries(tags).map(([key, value]) => ['tags[]', `${key}:${value}`])
|
|
76
75
|
]
|
|
77
76
|
|
|
78
|
-
for (const [key, value] of fields) {
|
|
79
|
-
form.append(key, value)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
77
|
this._logger.debug(() => {
|
|
83
78
|
const body = fields.map(([key, value]) => ` ${key}: ${value}`).join('\n')
|
|
84
79
|
return `Building agent export report: ${'\n' + body}`
|
|
@@ -93,36 +88,14 @@ class AgentExporter {
|
|
|
93
88
|
return `Adding ${type} profile to agent export: ` + bytes
|
|
94
89
|
})
|
|
95
90
|
|
|
96
|
-
|
|
97
|
-
|
|
91
|
+
fields.push([`types[${index}]`, type])
|
|
92
|
+
fields.push([`data[${index}]`, buffer, {
|
|
98
93
|
filename: `${type}.pb.gz`,
|
|
99
94
|
contentType: 'application/octet-stream',
|
|
100
95
|
knownLength: buffer.length
|
|
101
|
-
})
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const options = {
|
|
105
|
-
method: 'POST',
|
|
106
|
-
path: '/profiling/v1/input',
|
|
107
|
-
headers: form.getHeaders()
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
if (containerId) {
|
|
111
|
-
options.headers['Datadog-Container-ID'] = containerId
|
|
96
|
+
}])
|
|
112
97
|
}
|
|
113
98
|
|
|
114
|
-
if (this._url.protocol === 'unix:') {
|
|
115
|
-
options.socketPath = this._url.pathname
|
|
116
|
-
} else {
|
|
117
|
-
options.protocol = this._url.protocol
|
|
118
|
-
options.hostname = this._url.hostname
|
|
119
|
-
options.port = this._url.port
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
this._logger.debug(() => {
|
|
123
|
-
return `Submitting agent report to: ${JSON.stringify(options)}`
|
|
124
|
-
})
|
|
125
|
-
|
|
126
99
|
return new Promise((resolve, reject) => {
|
|
127
100
|
const operation = retry.operation({
|
|
128
101
|
randomize: true,
|
|
@@ -131,8 +104,36 @@ class AgentExporter {
|
|
|
131
104
|
})
|
|
132
105
|
|
|
133
106
|
operation.attempt((attempt) => {
|
|
134
|
-
const
|
|
135
|
-
|
|
107
|
+
const form = new FormData()
|
|
108
|
+
|
|
109
|
+
for (const [key, value, options] of fields) {
|
|
110
|
+
form.append(key, value, options)
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const options = {
|
|
114
|
+
method: 'POST',
|
|
115
|
+
path: '/profiling/v1/input',
|
|
116
|
+
headers: form.getHeaders(),
|
|
117
|
+
timeout: this._backoffTime * Math.pow(2, attempt)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (containerId) {
|
|
121
|
+
options.headers['Datadog-Container-ID'] = containerId
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (this._url.protocol === 'unix:') {
|
|
125
|
+
options.socketPath = this._url.pathname
|
|
126
|
+
} else {
|
|
127
|
+
options.protocol = this._url.protocol
|
|
128
|
+
options.hostname = this._url.hostname
|
|
129
|
+
options.port = this._url.port
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
this._logger.debug(() => {
|
|
133
|
+
return `Submitting profiler agent report attempt #${attempt} to: ${JSON.stringify(options)}`
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
sendRequest(options, form, (err, response) => {
|
|
136
137
|
if (operation.retry(err)) {
|
|
137
138
|
this._logger.error(`Error from the agent: ${err.message}`)
|
|
138
139
|
return
|
|
@@ -159,4 +160,4 @@ class AgentExporter {
|
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
|
|
162
|
-
module.exports = { AgentExporter }
|
|
163
|
+
module.exports = { AgentExporter, computeRetries }
|
|
@@ -5,8 +5,10 @@ const NoopTracer = require('./noop/tracer')
|
|
|
5
5
|
const DatadogTracer = require('./tracer')
|
|
6
6
|
const Config = require('./config')
|
|
7
7
|
const Instrumenter = require('./instrumenter')
|
|
8
|
+
const PluginManager = require('./plugin_manager')
|
|
8
9
|
const metrics = require('./metrics')
|
|
9
10
|
const log = require('./log')
|
|
11
|
+
const { isFalse } = require('./util')
|
|
10
12
|
const { setStartupLogInstrumenter } = require('./startup-log')
|
|
11
13
|
|
|
12
14
|
const noop = new NoopTracer()
|
|
@@ -14,8 +16,11 @@ const noop = new NoopTracer()
|
|
|
14
16
|
class Tracer extends BaseTracer {
|
|
15
17
|
constructor () {
|
|
16
18
|
super()
|
|
19
|
+
|
|
20
|
+
this._initialized = false
|
|
17
21
|
this._tracer = noop
|
|
18
22
|
this._instrumenter = new Instrumenter(this)
|
|
23
|
+
this._pluginManager = new PluginManager(this)
|
|
19
24
|
this._deprecate = method => log.deprecate(`tracer.${method}`, [
|
|
20
25
|
`tracer.${method}() is deprecated.`,
|
|
21
26
|
'Please use tracer.startSpan() and tracer.scope() instead.',
|
|
@@ -24,47 +29,51 @@ class Tracer extends BaseTracer {
|
|
|
24
29
|
}
|
|
25
30
|
|
|
26
31
|
init (options) {
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
log.use(config.logger)
|
|
32
|
-
log.toggle(config.debug, config.logLevel, this)
|
|
33
|
-
|
|
34
|
-
if (config.hasOwnProperty('profiling') && config.profiling.enabled) {
|
|
35
|
-
// do not stop tracer initialization if the profiler fails to be imported
|
|
36
|
-
try {
|
|
37
|
-
const profiler = require('./profiler')
|
|
38
|
-
profiler.start(config)
|
|
39
|
-
} catch (e) {
|
|
40
|
-
log.error(e)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
32
|
+
if (isFalse(process.env.DD_TRACE_ENABLED) || this._initialized) return this
|
|
33
|
+
|
|
34
|
+
this._initialized = true
|
|
43
35
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
metrics.start(config)
|
|
47
|
-
}
|
|
36
|
+
try {
|
|
37
|
+
const config = new Config(options) // TODO: support dynamic config
|
|
48
38
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
require('./appsec').enable(config)
|
|
52
|
-
}
|
|
39
|
+
log.use(config.logger)
|
|
40
|
+
log.toggle(config.debug, config.logLevel, this)
|
|
53
41
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
if (config.profiling.enabled) {
|
|
43
|
+
// do not stop tracer initialization if the profiler fails to be imported
|
|
44
|
+
try {
|
|
45
|
+
const profiler = require('./profiler')
|
|
46
|
+
profiler.start(config)
|
|
47
|
+
} catch (e) {
|
|
48
|
+
log.error(e)
|
|
57
49
|
}
|
|
58
|
-
} catch (e) {
|
|
59
|
-
log.error(e)
|
|
60
50
|
}
|
|
51
|
+
|
|
52
|
+
if (config.runtimeMetrics) {
|
|
53
|
+
metrics.start(config)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (config.tracing) {
|
|
57
|
+
// dirty require for now so zero appsec code is executed unless explicitly enabled
|
|
58
|
+
if (config.appsec.enabled) {
|
|
59
|
+
require('./appsec').enable(config)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this._tracer = new DatadogTracer(config)
|
|
63
|
+
this._instrumenter.enable(config)
|
|
64
|
+
this._pluginManager.configure(config)
|
|
65
|
+
setStartupLogInstrumenter(this._instrumenter)
|
|
66
|
+
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
log.error(e)
|
|
61
69
|
}
|
|
62
70
|
|
|
63
71
|
return this
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
use () {
|
|
67
|
-
this._instrumenter.use
|
|
75
|
+
this._instrumenter.use(...arguments)
|
|
76
|
+
this._pluginManager.configurePlugin(...arguments)
|
|
68
77
|
return this
|
|
69
78
|
}
|
|
70
79
|
|
|
@@ -111,11 +120,6 @@ class Tracer extends BaseTracer {
|
|
|
111
120
|
return this._tracer.extract.apply(this._tracer, arguments)
|
|
112
121
|
}
|
|
113
122
|
|
|
114
|
-
scopeManager () {
|
|
115
|
-
this._deprecate('scopeManager')
|
|
116
|
-
return this._tracer.scopeManager.apply(this._tracer, arguments)
|
|
117
|
-
}
|
|
118
|
-
|
|
119
123
|
scope () {
|
|
120
124
|
return this._tracer.scope.apply(this._tracer, arguments)
|
|
121
125
|
}
|
|
@@ -4,32 +4,56 @@ const path = require('path')
|
|
|
4
4
|
const Module = require('module')
|
|
5
5
|
const parse = require('module-details-from-path')
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
if (!hook.orig) {
|
|
9
|
-
hook.orig = Module.prototype.require
|
|
7
|
+
const origRequire = Module.prototype.require
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
// derived from require-in-the-middle@3 with tweaks
|
|
10
|
+
|
|
11
|
+
module.exports = Hook
|
|
12
|
+
|
|
13
|
+
Hook.reset = function () {
|
|
14
|
+
Module.prototype.require = origRequire
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function Hook (modules, options, onrequire) {
|
|
18
|
+
if (!(this instanceof Hook)) return new Hook(modules, options, onrequire)
|
|
19
|
+
if (typeof modules === 'function') {
|
|
20
|
+
onrequire = modules
|
|
21
|
+
modules = null
|
|
22
|
+
options = {}
|
|
23
|
+
} else if (typeof options === 'function') {
|
|
24
|
+
onrequire = options
|
|
25
|
+
options = {}
|
|
14
26
|
}
|
|
15
27
|
|
|
16
|
-
|
|
28
|
+
options = options || {}
|
|
29
|
+
|
|
30
|
+
this.cache = {}
|
|
31
|
+
this._unhooked = false
|
|
32
|
+
this._origRequire = Module.prototype.require
|
|
17
33
|
|
|
34
|
+
const self = this
|
|
18
35
|
const patching = {}
|
|
19
36
|
|
|
20
|
-
|
|
37
|
+
this._require = Module.prototype.require = function (request) {
|
|
38
|
+
if (self._unhooked) {
|
|
39
|
+
// if the patched require function could not be removed because
|
|
40
|
+
// someone else patched it after it was patched here, we just
|
|
41
|
+
// abort and pass the request onwards to the original require
|
|
42
|
+
return self._origRequire.apply(this, arguments)
|
|
43
|
+
}
|
|
44
|
+
|
|
21
45
|
const filename = Module._resolveFilename(request, this)
|
|
22
46
|
const core = filename.indexOf(path.sep) === -1
|
|
23
47
|
let name, basedir
|
|
24
48
|
|
|
25
49
|
// return known patched modules immediately
|
|
26
|
-
if (
|
|
50
|
+
if (self.cache.hasOwnProperty(filename)) {
|
|
27
51
|
// require.cache was potentially altered externally
|
|
28
|
-
if (require.cache[filename] && require.cache[filename].exports !==
|
|
52
|
+
if (require.cache[filename] && require.cache[filename].exports !== self.cache[filename].original) {
|
|
29
53
|
return require.cache[filename].exports
|
|
30
54
|
}
|
|
31
55
|
|
|
32
|
-
return
|
|
56
|
+
return self.cache[filename].exports
|
|
33
57
|
}
|
|
34
58
|
|
|
35
59
|
// Check if this module has a patcher in-progress already.
|
|
@@ -39,7 +63,7 @@ module.exports = function hook (modules, onrequire) {
|
|
|
39
63
|
patching[filename] = true
|
|
40
64
|
}
|
|
41
65
|
|
|
42
|
-
const exports =
|
|
66
|
+
const exports = self._origRequire.apply(this, arguments)
|
|
43
67
|
|
|
44
68
|
// If it's already patched, just return it as-is.
|
|
45
69
|
if (patched) return exports
|
|
@@ -75,10 +99,10 @@ module.exports = function hook (modules, onrequire) {
|
|
|
75
99
|
|
|
76
100
|
// ensure that the cache entry is assigned a value before calling
|
|
77
101
|
// onrequire, in case calling onrequire requires the same module.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
102
|
+
self.cache[filename] = { exports }
|
|
103
|
+
self.cache[filename].original = exports
|
|
104
|
+
self.cache[filename].exports = onrequire(exports, name, basedir)
|
|
81
105
|
|
|
82
|
-
return
|
|
106
|
+
return self.cache[filename].exports
|
|
83
107
|
}
|
|
84
108
|
}
|
|
@@ -16,13 +16,6 @@ class SpanProcessor {
|
|
|
16
16
|
|
|
17
17
|
if (trace.started.length === trace.finished.length) {
|
|
18
18
|
this._prioritySampler.sample(spanContext)
|
|
19
|
-
|
|
20
|
-
if (spanContext._traceFlags.sampled === false) {
|
|
21
|
-
log.debug(() => `Dropping trace due to user configured filtering: ${trace.started}`)
|
|
22
|
-
this._erase(trace)
|
|
23
|
-
return
|
|
24
|
-
}
|
|
25
|
-
|
|
26
19
|
const formattedSpans = trace.finished.map(format)
|
|
27
20
|
this._exporter.export(formattedSpans)
|
|
28
21
|
this._erase(trace)
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
const Tracer = require('./opentracing/tracer')
|
|
4
4
|
const tags = require('../../../ext/tags')
|
|
5
|
-
const ScopeManager = require('./scope/noop/scope_manager')
|
|
6
5
|
const Scope = require('./scope')
|
|
6
|
+
const { storage } = require('../../datadog-core')
|
|
7
7
|
const { isError } = require('./util')
|
|
8
8
|
const { setStartupLogConfig } = require('./startup-log')
|
|
9
9
|
|
|
@@ -16,7 +16,6 @@ class DatadogTracer extends Tracer {
|
|
|
16
16
|
constructor (config) {
|
|
17
17
|
super(config)
|
|
18
18
|
|
|
19
|
-
this._scopeManager = new ScopeManager()
|
|
20
19
|
this._scope = new Scope()
|
|
21
20
|
setStartupLogConfig(config)
|
|
22
21
|
}
|
|
@@ -68,6 +67,10 @@ class DatadogTracer extends Tracer {
|
|
|
68
67
|
const tracer = this
|
|
69
68
|
|
|
70
69
|
return function () {
|
|
70
|
+
const store = storage.getStore()
|
|
71
|
+
|
|
72
|
+
if (store && store.noop) return fn.apply(this, arguments)
|
|
73
|
+
|
|
71
74
|
let optionsObj = options
|
|
72
75
|
if (typeof optionsObj === 'function' && typeof fn === 'function') {
|
|
73
76
|
optionsObj = optionsObj.apply(this, arguments)
|
|
@@ -100,10 +103,6 @@ class DatadogTracer extends Tracer {
|
|
|
100
103
|
this._exporter.setUrl(url)
|
|
101
104
|
}
|
|
102
105
|
|
|
103
|
-
scopeManager () {
|
|
104
|
-
return this._scopeManager
|
|
105
|
-
}
|
|
106
|
-
|
|
107
106
|
scope () {
|
|
108
107
|
return this._scope
|
|
109
108
|
}
|
|
@@ -4,9 +4,11 @@ const fs = require('fs')
|
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const crypto = require('crypto')
|
|
6
6
|
const semver = require('semver')
|
|
7
|
+
const proxyquire = require('proxyquire')
|
|
7
8
|
const exec = require('./helpers/exec')
|
|
8
9
|
const childProcess = require('child_process')
|
|
9
10
|
const plugins = require('../packages/dd-trace/src/plugins')
|
|
11
|
+
const Plugin = require('../packages/dd-trace/src/plugins/plugin')
|
|
10
12
|
const externals = require('../packages/dd-trace/test/plugins/externals')
|
|
11
13
|
|
|
12
14
|
const requirePackageJsonPath = require.resolve('../packages/dd-trace/src/require-package-json')
|
|
@@ -23,6 +25,13 @@ Object.keys(externals).forEach(external => externals[external].forEach(thing =>
|
|
|
23
25
|
}
|
|
24
26
|
}))
|
|
25
27
|
|
|
28
|
+
fs.readdirSync(path.join(__dirname, '../packages/datadog-instrumentations/src'))
|
|
29
|
+
.filter(file => file.endsWith('js'))
|
|
30
|
+
.forEach(file => {
|
|
31
|
+
file = file.replace('.js', '')
|
|
32
|
+
plugins[file] = { name: file, prototype: Object.create(Plugin.prototype) }
|
|
33
|
+
})
|
|
34
|
+
|
|
26
35
|
run()
|
|
27
36
|
|
|
28
37
|
async function run () {
|
|
@@ -42,7 +51,27 @@ async function assertVersions () {
|
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
const internals = names
|
|
45
|
-
.map(key =>
|
|
54
|
+
.map(key => {
|
|
55
|
+
const plugin = plugins[key]
|
|
56
|
+
if (plugin.prototype instanceof Plugin) {
|
|
57
|
+
const instrumentations = []
|
|
58
|
+
const instrument = {
|
|
59
|
+
addHook (instrumentation) {
|
|
60
|
+
instrumentations.push(instrumentation)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const instPath = path.join(
|
|
64
|
+
__dirname,
|
|
65
|
+
`../packages/datadog-instrumentations/src/${plugin.name}.js`
|
|
66
|
+
)
|
|
67
|
+
proxyquire.noPreserveCache()(instPath, {
|
|
68
|
+
'./helpers/instrument': instrument
|
|
69
|
+
})
|
|
70
|
+
return instrumentations
|
|
71
|
+
} else {
|
|
72
|
+
return plugin
|
|
73
|
+
}
|
|
74
|
+
})
|
|
46
75
|
.reduce((prev, next) => prev.concat(next), [])
|
|
47
76
|
|
|
48
77
|
for (const inst of internals) {
|