dd-trace 2.0.0-appsec-beta.4 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATING.md +65 -0
- package/ci/init.js +5 -1
- package/ci/jest/env.js +5 -1
- package/index.d.ts +31 -44
- package/package.json +5 -2
- package/packages/datadog-instrumentations/index.js +6 -0
- package/packages/datadog-instrumentations/src/bluebird.js +26 -0
- package/packages/datadog-instrumentations/src/dns.js +2 -2
- package/packages/datadog-instrumentations/src/helpers/instrument.js +24 -25
- package/packages/datadog-instrumentations/src/helpers/promise.js +29 -0
- package/packages/datadog-instrumentations/src/memcached.js +3 -5
- 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 +21 -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 +1 -1
- package/packages/datadog-plugin-fs/src/index.js +7 -3
- package/packages/datadog-plugin-http/src/client.js +9 -24
- 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-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-router/src/index.js +28 -3
- package/packages/datadog-plugin-winston/src/index.js +30 -12
- 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 +4 -7
- package/packages/dd-trace/src/appsec/gateway/als.js +1 -0
- package/packages/dd-trace/src/appsec/gateway/channels.js +3 -0
- package/packages/dd-trace/src/appsec/gateway/engine/engine.js +20 -30
- package/packages/dd-trace/src/appsec/gateway/engine/runner.js +2 -0
- package/packages/dd-trace/src/appsec/index.js +41 -25
- package/packages/dd-trace/src/appsec/recommended.json +5708 -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 +0 -2
- package/packages/dd-trace/src/exporters/agent/request.js +8 -0
- package/packages/dd-trace/src/format.js +14 -39
- 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 +46 -47
- package/packages/dd-trace/src/opentracing/span.js +2 -7
- package/packages/dd-trace/src/opentracing/span_context.js +0 -3
- package/packages/dd-trace/src/opentracing/tracer.js +5 -23
- package/packages/dd-trace/src/plugins/index.js +1 -5
- package/packages/dd-trace/src/plugins/plugin.js +7 -1
- package/packages/dd-trace/src/plugins/util/test.js +9 -4
- package/packages/dd-trace/src/plugins/util/web.js +3 -3
- package/packages/dd-trace/src/profiling/config.js +5 -1
- package/packages/dd-trace/src/profiling/exporters/agent.js +33 -32
- package/packages/dd-trace/src/profiling/profiler.js +15 -6
- package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -1
- package/packages/dd-trace/src/profiling/profilers/heap.js +3 -2
- package/packages/dd-trace/src/proxy.js +35 -35
- 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 +7 -0
- package/scripts/publish_docs.js +1 -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/appsec/gateway/dc_block.js +0 -68
- package/packages/dd-trace/src/plugins/util/promise.js +0 -31
- package/packages/dd-trace/src/profiling/mapper.js +0 -91
- package/packages/dd-trace/src/scope/noop/scope_manager.js +0 -28
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const addresses = require('./addresses')
|
|
4
|
+
const Limiter = require('../rate_limiter')
|
|
5
|
+
|
|
6
|
+
// default limiter, configurable with setRateLimit()
|
|
7
|
+
let limiter = new Limiter(100)
|
|
4
8
|
|
|
5
9
|
const REQUEST_HEADERS_PASSLIST = [
|
|
6
10
|
'accept',
|
|
@@ -36,7 +40,6 @@ function resolveHTTPRequest (context) {
|
|
|
36
40
|
const headers = context.resolve(addresses.HTTP_INCOMING_HEADERS)
|
|
37
41
|
|
|
38
42
|
return {
|
|
39
|
-
// route: context.resolve(addresses.HTTP_INCOMING_ROUTE),
|
|
40
43
|
remote_ip: context.resolve(addresses.HTTP_INCOMING_REMOTE_IP),
|
|
41
44
|
headers: filterHeaders(headers, REQUEST_HEADERS_PASSLIST, 'http.request.headers.')
|
|
42
45
|
}
|
|
@@ -48,6 +51,7 @@ function resolveHTTPResponse (context) {
|
|
|
48
51
|
const headers = context.resolve(addresses.HTTP_INCOMING_RESPONSE_HEADERS)
|
|
49
52
|
|
|
50
53
|
return {
|
|
54
|
+
endpoint: context.resolve(addresses.HTTP_INCOMING_ENDPOINT),
|
|
51
55
|
headers: filterHeaders(headers, RESPONSE_HEADERS_PASSLIST, 'http.response.headers.')
|
|
52
56
|
}
|
|
53
57
|
}
|
|
@@ -61,16 +65,16 @@ function filterHeaders (headers, passlist, prefix) {
|
|
|
61
65
|
const headerName = passlist[i]
|
|
62
66
|
|
|
63
67
|
if (headers[headerName]) {
|
|
64
|
-
result[`${prefix}${formatHeaderName(headerName)}`] = headers[headerName]
|
|
68
|
+
result[`${prefix}${formatHeaderName(headerName)}`] = headers[headerName] + ''
|
|
65
69
|
}
|
|
66
70
|
}
|
|
67
71
|
|
|
68
72
|
return result
|
|
69
73
|
}
|
|
70
74
|
|
|
75
|
+
// TODO: this can be precomputed at start time
|
|
71
76
|
function formatHeaderName (name) {
|
|
72
77
|
return name
|
|
73
|
-
.toString()
|
|
74
78
|
.trim()
|
|
75
79
|
.slice(0, 200)
|
|
76
80
|
.replace(/[^a-zA-Z0-9_\-:/]/g, '_')
|
|
@@ -85,10 +89,14 @@ function reportAttack (attackData, store) {
|
|
|
85
89
|
const currentTags = topSpan.context()._tags
|
|
86
90
|
|
|
87
91
|
const newTags = {
|
|
88
|
-
'appsec.event': true
|
|
89
|
-
|
|
92
|
+
'appsec.event': 'true'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (limiter.isAllowed()) {
|
|
96
|
+
newTags['manual.keep'] = 'true' // TODO: figure out how to keep appsec traces with sampling revamp
|
|
90
97
|
}
|
|
91
98
|
|
|
99
|
+
// TODO: maybe add this to format.js later (to take decision as late as possible)
|
|
92
100
|
if (!currentTags['_dd.origin']) {
|
|
93
101
|
newTags['_dd.origin'] = 'appsec'
|
|
94
102
|
}
|
|
@@ -115,8 +123,6 @@ function reportAttack (attackData, store) {
|
|
|
115
123
|
}
|
|
116
124
|
|
|
117
125
|
newTags['network.client.ip'] = resolvedRequest.remote_ip
|
|
118
|
-
|
|
119
|
-
// newTags['http.endpoint'] = resolvedRequest.route
|
|
120
126
|
}
|
|
121
127
|
|
|
122
128
|
topSpan.addTags(newTags)
|
|
@@ -126,9 +132,19 @@ function finishAttacks (req, context) {
|
|
|
126
132
|
const topSpan = req && req._datadog && req._datadog.span
|
|
127
133
|
if (!topSpan || !context) return false
|
|
128
134
|
|
|
129
|
-
const
|
|
135
|
+
const resolvedResponse = resolveHTTPResponse(context)
|
|
136
|
+
|
|
137
|
+
const newTags = resolvedResponse.headers
|
|
138
|
+
|
|
139
|
+
if (resolvedResponse.endpoint) {
|
|
140
|
+
newTags['http.endpoint'] = resolvedResponse.endpoint
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
topSpan.addTags(newTags)
|
|
144
|
+
}
|
|
130
145
|
|
|
131
|
-
|
|
146
|
+
function setRateLimit (rateLimit) {
|
|
147
|
+
limiter = new Limiter(rateLimit)
|
|
132
148
|
}
|
|
133
149
|
|
|
134
150
|
module.exports = {
|
|
@@ -137,5 +153,6 @@ module.exports = {
|
|
|
137
153
|
filterHeaders,
|
|
138
154
|
formatHeaderName,
|
|
139
155
|
reportAttack,
|
|
140
|
-
finishAttacks
|
|
156
|
+
finishAttacks,
|
|
157
|
+
setRateLimit
|
|
141
158
|
}
|
|
@@ -24,9 +24,12 @@ class Config {
|
|
|
24
24
|
tagger.add(this.tags, process.env.DD_TRACE_GLOBAL_TAGS)
|
|
25
25
|
tagger.add(this.tags, options.tags)
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
const DD_TRACING_ENABLED = coalesce(
|
|
28
|
+
process.env.DD_TRACING_ENABLED,
|
|
29
|
+
true
|
|
30
|
+
)
|
|
28
31
|
const DD_PROFILING_ENABLED = coalesce(
|
|
29
|
-
options.profiling,
|
|
32
|
+
options.profiling, // TODO: remove when enabled by default
|
|
30
33
|
process.env.DD_EXPERIMENTAL_PROFILING_ENABLED,
|
|
31
34
|
process.env.DD_PROFILING_ENABLED,
|
|
32
35
|
false
|
|
@@ -42,7 +45,7 @@ class Config {
|
|
|
42
45
|
false
|
|
43
46
|
)
|
|
44
47
|
const DD_RUNTIME_METRICS_ENABLED = coalesce(
|
|
45
|
-
options.runtimeMetrics,
|
|
48
|
+
options.runtimeMetrics, // TODO: remove when enabled by default
|
|
46
49
|
process.env.DD_RUNTIME_METRICS_ENABLED,
|
|
47
50
|
false
|
|
48
51
|
)
|
|
@@ -85,15 +88,9 @@ class Config {
|
|
|
85
88
|
const DD_TRACE_STARTUP_LOGS = coalesce(
|
|
86
89
|
options.startupLogs,
|
|
87
90
|
process.env.DD_TRACE_STARTUP_LOGS,
|
|
88
|
-
|
|
89
|
-
)
|
|
90
|
-
const DD_TRACE_ENABLED = coalesce(
|
|
91
|
-
options.enabled,
|
|
92
|
-
process.env.DD_TRACE_ENABLED,
|
|
93
|
-
true
|
|
91
|
+
false
|
|
94
92
|
)
|
|
95
93
|
const DD_TRACE_DEBUG = coalesce(
|
|
96
|
-
options.debug,
|
|
97
94
|
process.env.DD_TRACE_DEBUG,
|
|
98
95
|
false
|
|
99
96
|
)
|
|
@@ -121,39 +118,46 @@ class Config {
|
|
|
121
118
|
process.env.DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED,
|
|
122
119
|
false
|
|
123
120
|
)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
false
|
|
128
|
-
)
|
|
129
|
-
// TODO(simon-id): add documentation for appsec config when we release it in public beta
|
|
121
|
+
|
|
122
|
+
let appsec = options.appsec || (options.experimental && options.experimental.appsec)
|
|
123
|
+
|
|
130
124
|
const DD_APPSEC_ENABLED = coalesce(
|
|
131
|
-
|
|
132
|
-
options.experimental.appsec &&
|
|
133
|
-
(options.experimental.appsec === true || options.experimental.appsec.enabled === true),
|
|
134
|
-
process.env.DD_EXPERIMENTAL_APPSEC_ENABLED,
|
|
125
|
+
appsec && (appsec === true || appsec.enabled === true), // TODO: remove when enabled by default
|
|
135
126
|
process.env.DD_APPSEC_ENABLED,
|
|
136
127
|
false
|
|
137
128
|
)
|
|
129
|
+
|
|
130
|
+
appsec = appsec || {}
|
|
131
|
+
|
|
138
132
|
const DD_APPSEC_RULES = coalesce(
|
|
139
|
-
|
|
133
|
+
appsec.rules,
|
|
140
134
|
process.env.DD_APPSEC_RULES,
|
|
141
135
|
path.join(__dirname, 'appsec', 'recommended.json')
|
|
142
136
|
)
|
|
137
|
+
const DD_APPSEC_TRACE_RATE_LIMIT = coalesce(
|
|
138
|
+
appsec.rateLimit,
|
|
139
|
+
process.env.DD_APPSEC_TRACE_RATE_LIMIT,
|
|
140
|
+
100
|
|
141
|
+
)
|
|
143
142
|
|
|
144
143
|
const sampler = (options.experimental && options.experimental.sampler) || {}
|
|
145
144
|
const ingestion = options.ingestion || {}
|
|
146
145
|
const dogstatsd = coalesce(options.dogstatsd, {})
|
|
147
146
|
|
|
148
147
|
Object.assign(sampler, {
|
|
149
|
-
sampleRate: coalesce(
|
|
148
|
+
sampleRate: coalesce(
|
|
149
|
+
options.sampleRate,
|
|
150
|
+
ingestion.sampleRate,
|
|
151
|
+
sampler.sampleRate,
|
|
152
|
+
process.env.DD_TRACE_SAMPLE_RATE
|
|
153
|
+
),
|
|
150
154
|
rateLimit: coalesce(ingestion.rateLimit, sampler.rateLimit, process.env.DD_TRACE_RATE_LIMIT)
|
|
151
155
|
})
|
|
152
156
|
|
|
153
157
|
const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
|
|
154
158
|
const defaultFlushInterval = inAWSLambda ? 0 : 2000
|
|
155
159
|
|
|
156
|
-
this.
|
|
160
|
+
this.tracing = !isFalse(DD_TRACING_ENABLED)
|
|
157
161
|
this.debug = isTrue(DD_TRACE_DEBUG)
|
|
158
162
|
this.logInjection = isTrue(DD_LOGS_INJECTION)
|
|
159
163
|
this.env = DD_ENV
|
|
@@ -162,7 +166,7 @@ class Config {
|
|
|
162
166
|
this.hostname = DD_AGENT_HOST || (this.url && this.url.hostname)
|
|
163
167
|
this.port = String(DD_TRACE_AGENT_PORT || (this.url && this.url.port))
|
|
164
168
|
this.flushInterval = coalesce(parseInt(options.flushInterval, 10), defaultFlushInterval)
|
|
165
|
-
this.sampleRate = coalesce(Math.min(Math.max(
|
|
169
|
+
this.sampleRate = coalesce(Math.min(Math.max(sampler.sampleRate, 0), 1), 1)
|
|
166
170
|
this.logger = options.logger
|
|
167
171
|
this.plugins = !!coalesce(options.plugins, true)
|
|
168
172
|
this.service = DD_SERVICE
|
|
@@ -180,8 +184,7 @@ class Config {
|
|
|
180
184
|
runtimeId: isTrue(DD_TRACE_RUNTIME_ID_ENABLED),
|
|
181
185
|
exporter: DD_TRACE_EXPORTER,
|
|
182
186
|
enableGetRumData: isTrue(DD_TRACE_GET_RUM_DATA_ENABLED),
|
|
183
|
-
sampler
|
|
184
|
-
internalErrors: isTrue(DD_TRACE_INTERNAL_ERRORS_ENABLED)
|
|
187
|
+
sampler
|
|
185
188
|
}
|
|
186
189
|
this.reportHostname = isTrue(coalesce(options.reportHostname, process.env.DD_TRACE_REPORT_HOSTNAME, false))
|
|
187
190
|
this.scope = process.env.DD_TRACE_SCOPE
|
|
@@ -200,7 +203,8 @@ class Config {
|
|
|
200
203
|
this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
|
|
201
204
|
this.appsec = {
|
|
202
205
|
enabled: isTrue(DD_APPSEC_ENABLED),
|
|
203
|
-
rules: DD_APPSEC_RULES
|
|
206
|
+
rules: DD_APPSEC_RULES,
|
|
207
|
+
rateLimit: DD_APPSEC_TRACE_RATE_LIMIT
|
|
204
208
|
}
|
|
205
209
|
|
|
206
210
|
tagger.add(this.tags, {
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
-
SAMPLE_RATE_METRIC_KEY: '_sample_rate',
|
|
5
4
|
SAMPLING_PRIORITY_KEY: '_sampling_priority_v1',
|
|
6
5
|
ANALYTICS_KEY: '_dd1.sr.eausr',
|
|
7
6
|
ORIGIN_KEY: '_dd.origin',
|
|
8
7
|
HOSTNAME_KEY: '_dd.hostname',
|
|
9
|
-
REFERENCE_NOOP: 'noop',
|
|
10
8
|
SAMPLING_RULE_DECISION: '_dd.rule_psr',
|
|
11
9
|
SAMPLING_LIMIT_DECISION: '_dd.limit_psr',
|
|
12
10
|
SAMPLING_AGENT_DECISION: '_dd.agent_psr',
|
|
@@ -4,12 +4,17 @@ const http = require('http')
|
|
|
4
4
|
const https = require('https')
|
|
5
5
|
const docker = require('./docker')
|
|
6
6
|
const log = require('../../log')
|
|
7
|
+
const { storage } = require('../../../../datadog-core')
|
|
7
8
|
|
|
8
9
|
const httpAgent = new http.Agent({ keepAlive: true })
|
|
9
10
|
const httpsAgent = new https.Agent({ keepAlive: true })
|
|
10
11
|
const containerId = docker.id()
|
|
11
12
|
|
|
12
13
|
function retriableRequest (options, callback, client, data) {
|
|
14
|
+
const store = storage.getStore()
|
|
15
|
+
|
|
16
|
+
storage.enterWith({ noop: true })
|
|
17
|
+
|
|
13
18
|
const req = client.request(options, res => {
|
|
14
19
|
let data = ''
|
|
15
20
|
|
|
@@ -29,6 +34,9 @@ function retriableRequest (options, callback, client, data) {
|
|
|
29
34
|
})
|
|
30
35
|
req.setTimeout(options.timeout, req.abort)
|
|
31
36
|
data.forEach(buffer => req.write(buffer))
|
|
37
|
+
|
|
38
|
+
storage.enterWith(store)
|
|
39
|
+
|
|
32
40
|
return req
|
|
33
41
|
}
|
|
34
42
|
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
const constants = require('./constants')
|
|
4
4
|
const tags = require('../../../ext/tags')
|
|
5
|
-
const log = require('./log')
|
|
6
5
|
const id = require('./id')
|
|
7
6
|
const { isError } = require('./util')
|
|
8
7
|
|
|
@@ -38,8 +37,8 @@ function formatSpan (span) {
|
|
|
38
37
|
trace_id: spanContext._traceId,
|
|
39
38
|
span_id: spanContext._spanId,
|
|
40
39
|
parent_id: spanContext._parentId || id('0'),
|
|
41
|
-
name:
|
|
42
|
-
resource:
|
|
40
|
+
name: String(spanContext._name),
|
|
41
|
+
resource: String(spanContext._name),
|
|
43
42
|
error: 0,
|
|
44
43
|
meta: {},
|
|
45
44
|
metrics: {},
|
|
@@ -54,7 +53,6 @@ function extractTags (trace, span) {
|
|
|
54
53
|
const tags = context._tags
|
|
55
54
|
const hostname = context._hostname
|
|
56
55
|
const priority = context._sampling.priority
|
|
57
|
-
const internalErrors = span.tracer()._internalErrors
|
|
58
56
|
|
|
59
57
|
if (tags['span.kind'] && tags['span.kind'] !== 'internal') {
|
|
60
58
|
addTag({}, trace.metrics, MEASURED, 1)
|
|
@@ -76,7 +74,7 @@ function extractTags (trace, span) {
|
|
|
76
74
|
addTag({}, trace.metrics, tag, tags[tag] === undefined || tags[tag] ? 1 : 0)
|
|
77
75
|
break
|
|
78
76
|
case 'error':
|
|
79
|
-
if (tags[tag] && (context._name !== 'fs.operation'
|
|
77
|
+
if (tags[tag] && (context._name !== 'fs.operation')) {
|
|
80
78
|
trace.error = 1
|
|
81
79
|
}
|
|
82
80
|
break
|
|
@@ -84,7 +82,7 @@ function extractTags (trace, span) {
|
|
|
84
82
|
case 'error.msg':
|
|
85
83
|
case 'error.stack':
|
|
86
84
|
// HACK: remove when implemented in the backend
|
|
87
|
-
if (context._name !== 'fs.operation'
|
|
85
|
+
if (context._name !== 'fs.operation') {
|
|
88
86
|
trace.error = 1
|
|
89
87
|
}
|
|
90
88
|
default: // eslint-disable-line no-fallthrough
|
|
@@ -133,7 +131,7 @@ function extractError (trace, span) {
|
|
|
133
131
|
}
|
|
134
132
|
}
|
|
135
133
|
|
|
136
|
-
function addTag (meta, metrics, key, value,
|
|
134
|
+
function addTag (meta, metrics, key, value, nested) {
|
|
137
135
|
switch (typeof value) {
|
|
138
136
|
case 'string':
|
|
139
137
|
if (!value) break
|
|
@@ -143,6 +141,9 @@ function addTag (meta, metrics, key, value, seen) {
|
|
|
143
141
|
if (isNaN(value)) break
|
|
144
142
|
metrics[key] = value
|
|
145
143
|
break
|
|
144
|
+
case 'boolean':
|
|
145
|
+
metrics[key] = value ? 1 : 0
|
|
146
|
+
break
|
|
146
147
|
case 'undefined':
|
|
147
148
|
break
|
|
148
149
|
case 'object':
|
|
@@ -151,41 +152,15 @@ function addTag (meta, metrics, key, value, seen) {
|
|
|
151
152
|
// Special case for Node.js Buffer and URL
|
|
152
153
|
if (isNodeBuffer(value) || isUrl(value)) {
|
|
153
154
|
metrics[key] = value.toString()
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
} else if (!Array.isArray(value) && !nested) {
|
|
156
|
+
for (const prop in value) {
|
|
157
|
+
if (!value.hasOwnProperty(prop)) continue
|
|
156
158
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
break
|
|
159
|
+
addTag(meta, metrics, `${key}.${prop}`, value[prop], true)
|
|
160
|
+
}
|
|
160
161
|
}
|
|
161
162
|
|
|
162
|
-
|
|
163
|
-
addTag(meta, metrics, key, serialize(value))
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
function addObjectTag (meta, metrics, key, value, seen) {
|
|
168
|
-
seen = seen || []
|
|
169
|
-
|
|
170
|
-
if (~seen.indexOf(value)) {
|
|
171
|
-
meta[key] = '[Circular]'
|
|
172
|
-
return
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
seen.push(value)
|
|
176
|
-
|
|
177
|
-
for (const prop in value) {
|
|
178
|
-
addTag(meta, metrics, `${key}.${prop}`, value[prop], seen)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
seen.pop()
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function serialize (obj) {
|
|
185
|
-
try {
|
|
186
|
-
return obj && typeof obj.toString !== 'function' ? JSON.stringify(obj) : String(obj)
|
|
187
|
-
} catch (e) {
|
|
188
|
-
log.error(e)
|
|
163
|
+
break
|
|
189
164
|
}
|
|
190
165
|
}
|
|
191
166
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const { storage } = require('../../datadog-core')
|
|
4
4
|
|
|
5
5
|
const _default = {
|
|
6
6
|
debug: msg => console.debug(msg), /* eslint-disable-line no-console */
|
|
@@ -45,11 +45,11 @@ function processMsg (msg) {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
function withNoop (fn) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
48
|
+
const store = storage.getStore()
|
|
49
|
+
|
|
50
|
+
storage.enterWith({ noop: true })
|
|
51
|
+
fn()
|
|
52
|
+
storage.enterWith(store)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
const log = {
|
|
@@ -73,18 +73,9 @@ const log = {
|
|
|
73
73
|
return this
|
|
74
74
|
},
|
|
75
75
|
|
|
76
|
-
_noopSpan () {
|
|
77
|
-
if (!this.__noopSpan) {
|
|
78
|
-
this.__noopSpan = new NoopSpan(this._tracer)
|
|
79
|
-
}
|
|
80
|
-
return this.__noopSpan
|
|
81
|
-
},
|
|
82
|
-
|
|
83
76
|
reset () {
|
|
84
77
|
this._logger = _default
|
|
85
78
|
this._enabled = false
|
|
86
|
-
delete this._tracer
|
|
87
|
-
delete this.__noopSpan
|
|
88
79
|
this._deprecate = memoize((code, message) => {
|
|
89
80
|
withNoop(() => this._logger.error(message))
|
|
90
81
|
return this
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
const Tracer = require('opentracing').Tracer
|
|
4
|
-
const ScopeManager = require('../scope/noop/scope_manager')
|
|
5
4
|
const Scope = require('../noop/scope')
|
|
6
5
|
const Span = require('./span')
|
|
7
6
|
|
|
@@ -9,7 +8,6 @@ class NoopTracer extends Tracer {
|
|
|
9
8
|
constructor (config) {
|
|
10
9
|
super(config)
|
|
11
10
|
|
|
12
|
-
this._scopeManager = new ScopeManager()
|
|
13
11
|
this._scope = new Scope()
|
|
14
12
|
this._span = new Span(this)
|
|
15
13
|
}
|
|
@@ -22,10 +20,6 @@ class NoopTracer extends Tracer {
|
|
|
22
20
|
return fn
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
scopeManager () {
|
|
26
|
-
return this._scopeManager
|
|
27
|
-
}
|
|
28
|
-
|
|
29
23
|
scope () {
|
|
30
24
|
return this._scope
|
|
31
25
|
}
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
const pick = require('lodash.pick')
|
|
4
4
|
const id = require('../../id')
|
|
5
5
|
const DatadogSpanContext = require('../span_context')
|
|
6
|
-
const NoopSpanContext = require('../../noop/span_context')
|
|
7
6
|
const log = require('../../log')
|
|
8
7
|
|
|
8
|
+
const { AUTO_KEEP, AUTO_REJECT, USER_KEEP } = require('../../../../../ext/priority')
|
|
9
|
+
|
|
9
10
|
const traceKey = 'x-datadog-trace-id'
|
|
10
11
|
const spanKey = 'x-datadog-parent-id'
|
|
11
12
|
const originKey = 'x-datadog-origin'
|
|
12
13
|
const samplingKey = 'x-datadog-sampling-priority'
|
|
13
|
-
const sampleKey = 'x-datadog-sampled'
|
|
14
14
|
const tagsKey = 'x-datadog-tags'
|
|
15
15
|
const baggagePrefix = 'ot-baggage-'
|
|
16
16
|
const b3TraceKey = 'x-b3-traceid'
|
|
@@ -36,7 +36,6 @@ class TextMapPropagator {
|
|
|
36
36
|
inject (spanContext, carrier) {
|
|
37
37
|
carrier[traceKey] = spanContext.toTraceId()
|
|
38
38
|
carrier[spanKey] = spanContext.toSpanId()
|
|
39
|
-
carrier[sampleKey] = spanContext._traceFlags.sampled ? '1' : '0'
|
|
40
39
|
|
|
41
40
|
this._injectOrigin(spanContext, carrier)
|
|
42
41
|
this._injectSamplingPriority(spanContext, carrier)
|
|
@@ -52,11 +51,6 @@ class TextMapPropagator {
|
|
|
52
51
|
|
|
53
52
|
if (!spanContext) return spanContext
|
|
54
53
|
|
|
55
|
-
this._extractOrigin(carrier, spanContext)
|
|
56
|
-
this._extractBaggageItems(carrier, spanContext)
|
|
57
|
-
this._extractSamplingPriority(carrier, spanContext)
|
|
58
|
-
this._extractTags(carrier, spanContext)
|
|
59
|
-
|
|
60
54
|
log.debug(() => `Extract from carrier: ${JSON.stringify(pick(carrier, logKeys))}.`)
|
|
61
55
|
|
|
62
56
|
return spanContext
|
|
@@ -108,9 +102,9 @@ class TextMapPropagator {
|
|
|
108
102
|
|
|
109
103
|
carrier[b3TraceKey] = spanContext._traceId.toString('hex')
|
|
110
104
|
carrier[b3SpanKey] = spanContext._spanId.toString('hex')
|
|
111
|
-
carrier[b3SampledKey] = spanContext.
|
|
105
|
+
carrier[b3SampledKey] = spanContext._sampling.priority >= AUTO_KEEP ? '1' : '0'
|
|
112
106
|
|
|
113
|
-
if (spanContext.
|
|
107
|
+
if (spanContext._sampling.priority > AUTO_KEEP) {
|
|
114
108
|
carrier[b3FlagsKey] = '1'
|
|
115
109
|
}
|
|
116
110
|
|
|
@@ -120,25 +114,20 @@ class TextMapPropagator {
|
|
|
120
114
|
}
|
|
121
115
|
|
|
122
116
|
_extractSpanContext (carrier) {
|
|
123
|
-
const context = this._extractContext(carrier)
|
|
124
|
-
|
|
125
|
-
if (!context) return null
|
|
126
|
-
|
|
127
|
-
if (context.traceFlags.sampled !== false) {
|
|
128
|
-
return new DatadogSpanContext(context)
|
|
129
|
-
} else {
|
|
130
|
-
return new NoopSpanContext(context)
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
_extractContext (carrier) {
|
|
135
117
|
return this._extractDatadogContext(carrier) || this._extractB3Context(carrier) || this._extractSqsdContext(carrier)
|
|
136
118
|
}
|
|
137
119
|
|
|
138
120
|
_extractDatadogContext (carrier) {
|
|
139
|
-
const
|
|
121
|
+
const spanContext = this._extractGenericContext(carrier, traceKey, spanKey, 10)
|
|
140
122
|
|
|
141
|
-
|
|
123
|
+
if (spanContext) {
|
|
124
|
+
this._extractOrigin(carrier, spanContext)
|
|
125
|
+
this._extractBaggageItems(carrier, spanContext)
|
|
126
|
+
this._extractSamplingPriority(carrier, spanContext)
|
|
127
|
+
this._extractTags(carrier, spanContext)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return spanContext
|
|
142
131
|
}
|
|
143
132
|
|
|
144
133
|
_extractB3Context (carrier) {
|
|
@@ -146,9 +135,23 @@ class TextMapPropagator {
|
|
|
146
135
|
|
|
147
136
|
const b3 = this._extractB3Headers(carrier)
|
|
148
137
|
const debug = b3[b3FlagsKey] === '1'
|
|
149
|
-
const
|
|
138
|
+
const priority = this._getPriority(b3[b3SampledKey], debug)
|
|
139
|
+
const spanContext = this._extractGenericContext(b3, b3TraceKey, b3SpanKey)
|
|
140
|
+
|
|
141
|
+
if (priority !== undefined) {
|
|
142
|
+
if (!spanContext) {
|
|
143
|
+
// B3 can force a sampling decision without providing IDs
|
|
144
|
+
return new DatadogSpanContext({
|
|
145
|
+
traceId: id(),
|
|
146
|
+
spanId: null,
|
|
147
|
+
sampling: { priority }
|
|
148
|
+
})
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
spanContext._sampling.priority = priority
|
|
152
|
+
}
|
|
150
153
|
|
|
151
|
-
return
|
|
154
|
+
return spanContext
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
_extractSqsdContext (carrier) {
|
|
@@ -165,19 +168,12 @@ class TextMapPropagator {
|
|
|
165
168
|
return this._extractDatadogContext(parsed)
|
|
166
169
|
}
|
|
167
170
|
|
|
168
|
-
_extractGenericContext (carrier, traceKey, spanKey,
|
|
171
|
+
_extractGenericContext (carrier, traceKey, spanKey, radix) {
|
|
169
172
|
if (carrier[traceKey] && carrier[spanKey]) {
|
|
170
|
-
return {
|
|
173
|
+
return new DatadogSpanContext({
|
|
171
174
|
traceId: id(carrier[traceKey], radix),
|
|
172
|
-
spanId: id(carrier[spanKey], radix)
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
} else if (typeof traceFlags.sampled === 'boolean') {
|
|
176
|
-
return {
|
|
177
|
-
traceId: id(),
|
|
178
|
-
spanId: null,
|
|
179
|
-
traceFlags
|
|
180
|
-
}
|
|
175
|
+
spanId: id(carrier[spanKey], radix)
|
|
176
|
+
})
|
|
181
177
|
}
|
|
182
178
|
|
|
183
179
|
return null
|
|
@@ -225,12 +221,15 @@ class TextMapPropagator {
|
|
|
225
221
|
} else {
|
|
226
222
|
const b3 = {
|
|
227
223
|
[b3TraceKey]: parts[0],
|
|
228
|
-
[b3SpanKey]: parts[1]
|
|
229
|
-
[b3SampledKey]: parts[2] !== '0' ? '1' : '0'
|
|
224
|
+
[b3SpanKey]: parts[1]
|
|
230
225
|
}
|
|
231
226
|
|
|
232
|
-
if (parts[2]
|
|
233
|
-
b3[
|
|
227
|
+
if (parts[2]) {
|
|
228
|
+
b3[b3SampledKey] = parts[2] !== '0' ? '1' : '0'
|
|
229
|
+
|
|
230
|
+
if (parts[2] === 'd') {
|
|
231
|
+
b3[b3FlagsKey] = '1'
|
|
232
|
+
}
|
|
234
233
|
}
|
|
235
234
|
|
|
236
235
|
return b3
|
|
@@ -275,14 +274,14 @@ class TextMapPropagator {
|
|
|
275
274
|
}
|
|
276
275
|
}
|
|
277
276
|
|
|
278
|
-
|
|
279
|
-
if (debug
|
|
280
|
-
return
|
|
277
|
+
_getPriority (sampled, debug) {
|
|
278
|
+
if (debug) {
|
|
279
|
+
return USER_KEEP
|
|
280
|
+
} else if (sampled === '1') {
|
|
281
|
+
return AUTO_KEEP
|
|
281
282
|
} else if (sampled === '0') {
|
|
282
|
-
return
|
|
283
|
+
return AUTO_REJECT
|
|
283
284
|
}
|
|
284
|
-
|
|
285
|
-
return null
|
|
286
285
|
}
|
|
287
286
|
}
|
|
288
287
|
|
|
@@ -4,29 +4,24 @@ const opentracing = require('opentracing')
|
|
|
4
4
|
const now = require('performance-now')
|
|
5
5
|
const Span = opentracing.Span
|
|
6
6
|
const SpanContext = require('./span_context')
|
|
7
|
-
const constants = require('../constants')
|
|
8
7
|
const id = require('../id')
|
|
9
8
|
const tagger = require('../tagger')
|
|
10
9
|
const log = require('../log')
|
|
11
10
|
const { storage } = require('../../../datadog-core')
|
|
12
11
|
|
|
13
|
-
const SAMPLE_RATE_METRIC_KEY = constants.SAMPLE_RATE_METRIC_KEY
|
|
14
12
|
const { DD_TRACE_EXPERIMENTAL_STATE_TRACKING } = process.env
|
|
15
13
|
|
|
16
14
|
class DatadogSpan extends Span {
|
|
17
|
-
constructor (tracer, processor,
|
|
15
|
+
constructor (tracer, processor, prioritySampler, fields, debug) {
|
|
18
16
|
super()
|
|
19
17
|
|
|
20
18
|
const operationName = fields.operationName
|
|
21
19
|
const parent = fields.parent || null
|
|
22
|
-
const tags = Object.assign({
|
|
23
|
-
[SAMPLE_RATE_METRIC_KEY]: sampler.rate()
|
|
24
|
-
}, fields.tags)
|
|
20
|
+
const tags = Object.assign({}, fields.tags)
|
|
25
21
|
const hostname = fields.hostname
|
|
26
22
|
|
|
27
23
|
this._parentTracer = tracer
|
|
28
24
|
this._debug = debug
|
|
29
|
-
this._sampler = sampler
|
|
30
25
|
this._processor = processor
|
|
31
26
|
this._prioritySampler = prioritySampler
|
|
32
27
|
this._store = storage.getStore()
|
|
@@ -16,9 +16,6 @@ class DatadogSpanContext extends SpanContext {
|
|
|
16
16
|
this._tags = props.tags || {}
|
|
17
17
|
this._sampling = props.sampling || {}
|
|
18
18
|
this._baggageItems = props.baggageItems || {}
|
|
19
|
-
this._traceFlags = props.traceFlags || {}
|
|
20
|
-
this._traceFlags.sampled = this._traceFlags.sampled !== false
|
|
21
|
-
this._traceFlags.debug = this._traceFlags.debug === true
|
|
22
19
|
this._noop = props.noop || null
|
|
23
20
|
this._trace = props.trace || {
|
|
24
21
|
started: [],
|