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.
Files changed (82) hide show
  1. package/MIGRATING.md +65 -0
  2. package/ci/init.js +5 -1
  3. package/ci/jest/env.js +5 -1
  4. package/index.d.ts +31 -44
  5. package/package.json +5 -2
  6. package/packages/datadog-instrumentations/index.js +6 -0
  7. package/packages/datadog-instrumentations/src/bluebird.js +26 -0
  8. package/packages/datadog-instrumentations/src/dns.js +2 -2
  9. package/packages/datadog-instrumentations/src/helpers/instrument.js +24 -25
  10. package/packages/datadog-instrumentations/src/helpers/promise.js +29 -0
  11. package/packages/datadog-instrumentations/src/memcached.js +3 -5
  12. package/packages/datadog-instrumentations/src/mysql.js +67 -0
  13. package/packages/datadog-instrumentations/src/promise-js.js +15 -0
  14. package/packages/datadog-instrumentations/src/promise.js +14 -0
  15. package/packages/datadog-instrumentations/src/q.js +21 -0
  16. package/packages/datadog-instrumentations/src/when.js +14 -0
  17. package/packages/datadog-plugin-cucumber/src/index.js +4 -4
  18. package/packages/datadog-plugin-cypress/src/plugin.js +12 -2
  19. package/packages/datadog-plugin-cypress/src/support.js +21 -6
  20. package/packages/datadog-plugin-dns/src/index.js +1 -1
  21. package/packages/datadog-plugin-fs/src/index.js +7 -3
  22. package/packages/datadog-plugin-http/src/client.js +9 -24
  23. package/packages/datadog-plugin-http2/src/client.js +1 -24
  24. package/packages/datadog-plugin-http2/src/server.js +2 -2
  25. package/packages/datadog-plugin-jest/src/jest-environment.js +4 -4
  26. package/packages/datadog-plugin-jest/src/jest-jasmine2.js +2 -2
  27. package/packages/datadog-plugin-knex/src/index.js +3 -3
  28. package/packages/datadog-plugin-mocha/src/index.js +3 -2
  29. package/packages/datadog-plugin-moleculer/src/client.js +60 -0
  30. package/packages/datadog-plugin-moleculer/src/index.js +8 -0
  31. package/packages/datadog-plugin-moleculer/src/server.js +61 -0
  32. package/packages/datadog-plugin-moleculer/src/util.js +21 -0
  33. package/packages/datadog-plugin-mongoose/src/index.js +2 -2
  34. package/packages/datadog-plugin-mysql/src/index.js +37 -89
  35. package/packages/datadog-plugin-net/src/index.js +5 -0
  36. package/packages/datadog-plugin-pino/src/index.js +25 -1
  37. package/packages/datadog-plugin-router/src/index.js +28 -3
  38. package/packages/datadog-plugin-winston/src/index.js +30 -12
  39. package/packages/dd-trace/lib/version.js +1 -1
  40. package/packages/dd-trace/src/appsec/addresses.js +11 -4
  41. package/packages/dd-trace/src/appsec/callbacks/ddwaf.js +4 -7
  42. package/packages/dd-trace/src/appsec/gateway/als.js +1 -0
  43. package/packages/dd-trace/src/appsec/gateway/channels.js +3 -0
  44. package/packages/dd-trace/src/appsec/gateway/engine/engine.js +20 -30
  45. package/packages/dd-trace/src/appsec/gateway/engine/runner.js +2 -0
  46. package/packages/dd-trace/src/appsec/index.js +41 -25
  47. package/packages/dd-trace/src/appsec/recommended.json +5708 -1
  48. package/packages/dd-trace/src/appsec/reporter.js +27 -10
  49. package/packages/dd-trace/src/config.js +31 -27
  50. package/packages/dd-trace/src/constants.js +0 -2
  51. package/packages/dd-trace/src/exporters/agent/request.js +8 -0
  52. package/packages/dd-trace/src/format.js +14 -39
  53. package/packages/dd-trace/src/log.js +6 -15
  54. package/packages/dd-trace/src/noop/span_context.js +0 -1
  55. package/packages/dd-trace/src/noop/tracer.js +0 -6
  56. package/packages/dd-trace/src/opentracing/propagation/text_map.js +46 -47
  57. package/packages/dd-trace/src/opentracing/span.js +2 -7
  58. package/packages/dd-trace/src/opentracing/span_context.js +0 -3
  59. package/packages/dd-trace/src/opentracing/tracer.js +5 -23
  60. package/packages/dd-trace/src/plugins/index.js +1 -5
  61. package/packages/dd-trace/src/plugins/plugin.js +7 -1
  62. package/packages/dd-trace/src/plugins/util/test.js +9 -4
  63. package/packages/dd-trace/src/plugins/util/web.js +3 -3
  64. package/packages/dd-trace/src/profiling/config.js +5 -1
  65. package/packages/dd-trace/src/profiling/exporters/agent.js +33 -32
  66. package/packages/dd-trace/src/profiling/profiler.js +15 -6
  67. package/packages/dd-trace/src/profiling/profilers/cpu.js +1 -1
  68. package/packages/dd-trace/src/profiling/profilers/heap.js +3 -2
  69. package/packages/dd-trace/src/proxy.js +35 -35
  70. package/packages/dd-trace/src/span_processor.js +0 -7
  71. package/packages/dd-trace/src/tracer.js +5 -6
  72. package/scripts/install_plugin_modules.js +7 -0
  73. package/scripts/publish_docs.js +1 -1
  74. package/packages/datadog-plugin-bluebird/src/index.js +0 -69
  75. package/packages/datadog-plugin-promise/src/index.js +0 -17
  76. package/packages/datadog-plugin-promise-js/src/index.js +0 -20
  77. package/packages/datadog-plugin-q/src/index.js +0 -16
  78. package/packages/datadog-plugin-when/src/index.js +0 -17
  79. package/packages/dd-trace/src/appsec/gateway/dc_block.js +0 -68
  80. package/packages/dd-trace/src/plugins/util/promise.js +0 -31
  81. package/packages/dd-trace/src/profiling/mapper.js +0 -91
  82. 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].toString()
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
- 'manual.keep': undefined
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 resolvedReponse = resolveHTTPResponse(context)
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
- topSpan.addTags(resolvedReponse.headers)
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
- // Temporary disabled
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
- true
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
- const DD_TRACE_INTERNAL_ERRORS_ENABLED = coalesce(
125
- options.experimental && options.experimental.internalErrors,
126
- process.env.DD_TRACE_EXPERIMENTAL_INTERNAL_ERRORS_ENABLED,
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
- options.experimental &&
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
- options.experimental && options.experimental.appsec && options.experimental.appsec.rules,
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(ingestion.sampleRate, sampler.sampleRate, process.env.DD_TRACE_SAMPLE_RATE),
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.enabled = isTrue(DD_TRACE_ENABLED)
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(options.sampleRate, 0), 1), 1)
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: serialize(spanContext._name),
42
- resource: serialize(spanContext._name),
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' || internalErrors)) {
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' || internalErrors) {
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, seen) {
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
- break
155
- }
155
+ } else if (!Array.isArray(value) && !nested) {
156
+ for (const prop in value) {
157
+ if (!value.hasOwnProperty(prop)) continue
156
158
 
157
- if (!Array.isArray(value)) {
158
- addObjectTag(meta, metrics, key, value, seen)
159
- break
159
+ addTag(meta, metrics, `${key}.${prop}`, value[prop], true)
160
+ }
160
161
  }
161
162
 
162
- default: // eslint-disable-line no-fallthrough
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 NoopSpan = require('./noop/span')
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
- if (!log._tracer) {
49
- fn()
50
- } else {
51
- log._tracer.scope().activate(log._noopSpan(), fn)
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
@@ -9,7 +9,6 @@ class NoopSpanContext extends DatadogSpanContext {
9
9
  constructor (props) {
10
10
  super(props)
11
11
 
12
- this._traceFlags.sampled = false
13
12
  this._sampling.priority = USER_REJECT
14
13
  }
15
14
  }
@@ -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._traceFlags.sampled ? '1' : '0'
105
+ carrier[b3SampledKey] = spanContext._sampling.priority >= AUTO_KEEP ? '1' : '0'
112
106
 
113
- if (spanContext._traceFlags.debug) {
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 sampled = this._isSampled(carrier[sampleKey])
121
+ const spanContext = this._extractGenericContext(carrier, traceKey, spanKey, 10)
140
122
 
141
- return this._extractGenericContext(carrier, traceKey, spanKey, { sampled }, 10)
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 sampled = this._isSampled(b3[b3SampledKey], debug)
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 this._extractGenericContext(b3, b3TraceKey, b3SpanKey, { sampled, debug })
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, traceFlags, radix) {
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
- traceFlags
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] === 'd') {
233
- b3[b3FlagsKey] = '1'
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
- _isSampled (sampled, debug) {
279
- if (debug || sampled === '1') {
280
- return true
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 false
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, sampler, prioritySampler, fields, debug) {
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: [],