dd-trace 5.38.0 → 5.40.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.
Files changed (97) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/index.d.ts +30 -21
  3. package/package.json +4 -2
  4. package/packages/datadog-instrumentations/src/apollo-server-core.js +1 -1
  5. package/packages/datadog-instrumentations/src/apollo-server.js +1 -1
  6. package/packages/datadog-instrumentations/src/express-session.js +41 -0
  7. package/packages/datadog-instrumentations/src/fetch.js +27 -6
  8. package/packages/datadog-instrumentations/src/helpers/fetch.js +6 -1
  9. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  10. package/packages/datadog-instrumentations/src/jest.js +16 -10
  11. package/packages/datadog-instrumentations/src/mocha/main.js +2 -1
  12. package/packages/datadog-instrumentations/src/nyc.js +2 -1
  13. package/packages/datadog-instrumentations/src/vitest.js +4 -2
  14. package/packages/datadog-plugin-amqplib/src/consumer.js +1 -1
  15. package/packages/datadog-plugin-amqplib/src/producer.js +1 -2
  16. package/packages/datadog-plugin-avsc/src/schema_iterator.js +1 -1
  17. package/packages/datadog-plugin-aws-sdk/src/base.js +5 -1
  18. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +9 -8
  19. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -4
  20. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -2
  21. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -2
  22. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +1 -1
  23. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +1 -2
  24. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +1 -1
  25. package/packages/datadog-plugin-kafkajs/src/consumer.js +5 -2
  26. package/packages/datadog-plugin-kafkajs/src/producer.js +4 -3
  27. package/packages/datadog-plugin-mongodb-core/src/index.js +10 -13
  28. package/packages/datadog-plugin-protobufjs/src/schema_iterator.js +1 -1
  29. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  30. package/packages/datadog-plugin-rhea/src/producer.js +1 -2
  31. package/packages/datadog-shimmer/src/shimmer.js +95 -95
  32. package/packages/dd-trace/src/appsec/addresses.js +1 -0
  33. package/packages/dd-trace/src/appsec/channels.js +1 -0
  34. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
  35. package/packages/dd-trace/src/appsec/iast/iast-context.js +2 -2
  36. package/packages/dd-trace/src/appsec/iast/index.js +0 -1
  37. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/index.js +1 -2
  38. package/packages/dd-trace/src/appsec/iast/vulnerability-reporter.js +3 -5
  39. package/packages/dd-trace/src/appsec/index.js +23 -1
  40. package/packages/dd-trace/src/appsec/reporter.js +3 -8
  41. package/packages/dd-trace/src/appsec/rule_manager.js +1 -1
  42. package/packages/dd-trace/src/appsec/sdk/set_user.js +9 -5
  43. package/packages/dd-trace/src/appsec/sdk/track_event.js +2 -4
  44. package/packages/dd-trace/src/appsec/telemetry/common.js +24 -0
  45. package/packages/dd-trace/src/appsec/telemetry/index.js +126 -0
  46. package/packages/dd-trace/src/appsec/telemetry/rasp.js +35 -0
  47. package/packages/dd-trace/src/appsec/telemetry/user.js +24 -0
  48. package/packages/dd-trace/src/appsec/telemetry/waf.js +92 -0
  49. package/packages/dd-trace/src/appsec/user_tracking.js +2 -4
  50. package/packages/dd-trace/src/ci-visibility/dynamic-instrumentation/index.js +16 -4
  51. package/packages/dd-trace/src/config.js +31 -14
  52. package/packages/dd-trace/src/constants.js +1 -1
  53. package/packages/dd-trace/src/{data_streams.js → datastreams/checkpointer.js} +1 -1
  54. package/packages/dd-trace/src/{data_streams_context.js → datastreams/context.js} +2 -2
  55. package/packages/dd-trace/src/datastreams/index.js +104 -0
  56. package/packages/dd-trace/src/datastreams/manager.js +27 -0
  57. package/packages/dd-trace/src/datastreams/processor.js +1 -44
  58. package/packages/dd-trace/src/datastreams/size.js +53 -0
  59. package/packages/dd-trace/src/debugger/devtools_client/breakpoints.js +2 -2
  60. package/packages/dd-trace/src/debugger/devtools_client/snapshot/collector.js +1 -1
  61. package/packages/dd-trace/src/debugger/devtools_client/source-maps.js +22 -15
  62. package/packages/dd-trace/src/dogstatsd.js +23 -4
  63. package/packages/dd-trace/src/exporters/agent/index.js +2 -2
  64. package/packages/dd-trace/src/flare/index.js +3 -0
  65. package/packages/dd-trace/src/noop/dogstatsd.js +6 -0
  66. package/packages/dd-trace/src/opentelemetry/tracer.js +45 -1
  67. package/packages/dd-trace/src/opentracing/propagation/text_map.js +11 -47
  68. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +1 -1
  69. package/packages/dd-trace/src/opentracing/span.js +12 -2
  70. package/packages/dd-trace/src/payload-tagging/config/aws.json +8 -0
  71. package/packages/dd-trace/src/plugin_manager.js +4 -3
  72. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
  73. package/packages/dd-trace/src/priority_sampler.js +5 -3
  74. package/packages/dd-trace/src/profiling/profiler.js +1 -1
  75. package/packages/dd-trace/src/profiling/profilers/wall.js +15 -4
  76. package/packages/dd-trace/src/proxy.js +41 -22
  77. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/capabilities.js +1 -0
  78. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/index.js +8 -5
  79. package/packages/dd-trace/src/{appsec/remote_config → remote_config}/manager.js +5 -5
  80. package/packages/dd-trace/src/runtime_metrics/index.js +34 -0
  81. package/packages/dd-trace/src/{runtime_metrics.js → runtime_metrics/runtime_metrics.js} +4 -4
  82. package/packages/dd-trace/src/serverless.js +10 -1
  83. package/packages/dd-trace/src/service-naming/index.js +12 -4
  84. package/packages/dd-trace/src/span_processor.js +7 -4
  85. package/packages/dd-trace/src/span_stats.js +1 -2
  86. package/packages/dd-trace/src/standalone/index.js +70 -0
  87. package/packages/dd-trace/src/standalone/product.js +24 -0
  88. package/packages/dd-trace/src/standalone/tracesource.js +22 -0
  89. package/packages/dd-trace/src/standalone/tracesource_priority_sampler.js +47 -0
  90. package/packages/dd-trace/src/telemetry/index.js +16 -387
  91. package/packages/dd-trace/src/telemetry/telemetry.js +394 -0
  92. package/packages/dd-trace/src/tracer.js +7 -15
  93. package/packages/dd-trace/src/appsec/standalone.js +0 -130
  94. package/packages/dd-trace/src/appsec/telemetry.js +0 -218
  95. package/packages/dd-trace/src/service-naming/schemas/index.js +0 -6
  96. /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/apply_states.js +0 -0
  97. /package/packages/dd-trace/src/{appsec/remote_config → remote_config}/scheduler.js +0 -0
@@ -9,14 +9,7 @@ const DynamicInstrumentation = require('./debugger')
9
9
  const telemetry = require('./telemetry')
10
10
  const nomenclature = require('./service-naming')
11
11
  const PluginManager = require('./plugin_manager')
12
- const remoteConfig = require('./appsec/remote_config')
13
- const AppsecSdk = require('./appsec/sdk')
14
- const dogstatsd = require('./dogstatsd')
15
12
  const NoopDogStatsDClient = require('./noop/dogstatsd')
16
- const spanleak = require('./spanleak')
17
- const { SSIHeuristics } = require('./profiling/ssi-heuristics')
18
- const appsecStandalone = require('./appsec/standalone')
19
- const LLMObsSDK = require('./llmobs/sdk')
20
13
 
21
14
  class LazyModule {
22
15
  constructor (provider) {
@@ -33,6 +26,35 @@ class LazyModule {
33
26
  }
34
27
  }
35
28
 
29
+ function lazyProxy (obj, property, config, getClass, ...args) {
30
+ if (config?._isInServerlessEnvironment?.() === false) {
31
+ defineEagerly(obj, property, getClass, ...args)
32
+ } else {
33
+ defineLazily(obj, property, getClass, ...args)
34
+ }
35
+ }
36
+
37
+ function defineEagerly (obj, property, getClass, ...args) {
38
+ const RealClass = getClass()
39
+
40
+ obj[property] = new RealClass(...args)
41
+ }
42
+
43
+ function defineLazily (obj, property, getClass, ...args) {
44
+ Reflect.defineProperty(obj, property, {
45
+ get () {
46
+ const RealClass = getClass()
47
+ const value = new RealClass(...args)
48
+
49
+ Reflect.defineProperty(obj, property, { value, configurable: true, enumerable: true })
50
+
51
+ return value
52
+ },
53
+ configurable: true,
54
+ enumerable: true
55
+ })
56
+ }
57
+
36
58
  class Tracer extends NoopProxy {
37
59
  constructor () {
38
60
  super()
@@ -68,18 +90,11 @@ class Tracer extends NoopProxy {
68
90
 
69
91
  if (config.dogstatsd) {
70
92
  // Custom Metrics
71
- this.dogstatsd = new dogstatsd.CustomMetrics(config)
72
-
73
- setInterval(() => {
74
- this.dogstatsd.flush()
75
- }, 10 * 1000).unref()
76
-
77
- process.once('beforeExit', () => {
78
- this.dogstatsd.flush()
79
- })
93
+ lazyProxy(this, 'dogstatsd', config, () => require('./dogstatsd').CustomMetrics, config)
80
94
  }
81
95
 
82
96
  if (config.spanLeakDebug > 0) {
97
+ const spanleak = require('./spanleak')
83
98
  if (config.spanLeakDebug === spanleak.MODES.LOG) {
84
99
  spanleak.enableLogging()
85
100
  } else if (config.spanLeakDebug === spanleak.MODES.GC_AND_LOG) {
@@ -89,7 +104,7 @@ class Tracer extends NoopProxy {
89
104
  }
90
105
 
91
106
  if (config.remoteConfig.enabled && !config.isCiVisibility) {
92
- const rc = remoteConfig.enable(config, this._modules.appsec)
107
+ const rc = require('./remote_config').enable(config, this._modules.appsec)
93
108
 
94
109
  rc.setProductHandler('APM_TRACING', (action, conf) => {
95
110
  if (action === 'unapply') {
@@ -129,6 +144,7 @@ class Tracer extends NoopProxy {
129
144
  }
130
145
 
131
146
  if (config.profiling.enabled !== 'false') {
147
+ const { SSIHeuristics } = require('./profiling/ssi-heuristics')
132
148
  const ssiHeuristics = new SSIHeuristics(config)
133
149
  ssiHeuristics.start()
134
150
  let mockProfiler = null
@@ -186,8 +202,9 @@ class Tracer extends NoopProxy {
186
202
  }
187
203
 
188
204
  if (config.isTestDynamicInstrumentationEnabled) {
189
- const testVisibilityDynamicInstrumentation = require('./ci-visibility/dynamic-instrumentation')
190
- testVisibilityDynamicInstrumentation.start(config)
205
+ const getDynamicInstrumentationClient = require('./ci-visibility/dynamic-instrumentation')
206
+ // We instantiate the client but do not start the Worker here. The worker is started lazily
207
+ getDynamicInstrumentationClient(config)
191
208
  }
192
209
  } catch (e) {
193
210
  log.error('Error initialising tracer', e)
@@ -218,11 +235,13 @@ class Tracer extends NoopProxy {
218
235
  this._modules.llmobs.enable(config)
219
236
  }
220
237
  if (!this._tracingInitialized) {
221
- const prioritySampler = appsecStandalone.configure(config)
238
+ const prioritySampler = config.apmTracingEnabled === false
239
+ ? require('./standalone').configure(config)
240
+ : undefined
222
241
  this._tracer = new DatadogTracer(config, prioritySampler)
223
242
  this.dataStreamsCheckpointer = this._tracer.dataStreamsCheckpointer
224
- this.appsec = new AppsecSdk(this._tracer, config)
225
- this.llmobs = new LLMObsSDK(this._tracer, this._modules.llmobs, config)
243
+ lazyProxy(this, 'appsec', config, () => require('./appsec/sdk'), this._tracer, config)
244
+ lazyProxy(this, 'llmobs', config, () => require('./llmobs/sdk'), this._tracer, this._modules.llmobs, config)
226
245
  this._tracingInitialized = true
227
246
  }
228
247
  if (config.iast.enabled) {
@@ -24,6 +24,7 @@ module.exports = {
24
24
  APM_TRACING_SAMPLE_RULES: 1n << 29n,
25
25
  ASM_AUTO_USER_INSTRUM_MODE: 1n << 31n,
26
26
  ASM_ENDPOINT_FINGERPRINT: 1n << 32n,
27
+ ASM_SESSION_FINGERPRINT: 1n << 33n,
27
28
  ASM_NETWORK_FINGERPRINT: 1n << 34n,
28
29
  ASM_HEADER_FINGERPRINT: 1n << 35n,
29
30
  ASM_RASP_CMDI: 1n << 37n
@@ -1,11 +1,11 @@
1
1
  'use strict'
2
2
 
3
- const Activation = require('../activation')
3
+ const Activation = require('../appsec/activation')
4
4
 
5
5
  const RemoteConfigManager = require('./manager')
6
6
  const RemoteConfigCapabilities = require('./capabilities')
7
- const { setCollectionMode } = require('../user_tracking')
8
- const log = require('../../log')
7
+ const { setCollectionMode } = require('../appsec/user_tracking')
8
+ const log = require('../log')
9
9
 
10
10
  let rc
11
11
 
@@ -77,10 +77,11 @@ function enableOrDisableAppsec (action, rcConfig, config, appsec) {
77
77
  }
78
78
  }
79
79
 
80
+ // TODO: all appsec specific stuff should be moved back in the appsec folder
80
81
  function enableWafUpdate (appsecConfig) {
81
82
  if (rc && appsecConfig && !appsecConfig.rules) {
82
83
  // dirty require to make startup faster for serverless
83
- const RuleManager = require('../rule_manager')
84
+ const RuleManager = require('../appsec/rule_manager')
84
85
 
85
86
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, true)
86
87
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, true)
@@ -93,6 +94,7 @@ function enableWafUpdate (appsecConfig) {
93
94
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, true)
94
95
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, true)
95
96
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_ENDPOINT_FINGERPRINT, true)
97
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_SESSION_FINGERPRINT, true)
96
98
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, true)
97
99
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, true)
98
100
 
@@ -115,7 +117,7 @@ function enableWafUpdate (appsecConfig) {
115
117
 
116
118
  function disableWafUpdate () {
117
119
  if (rc) {
118
- const RuleManager = require('../rule_manager')
120
+ const RuleManager = require('../appsec/rule_manager')
119
121
 
120
122
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_IP_BLOCKING, false)
121
123
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_USER_BLOCKING, false)
@@ -127,6 +129,7 @@ function disableWafUpdate () {
127
129
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_CUSTOM_BLOCKING_RESPONSE, false)
128
130
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_TRUSTED_IPS, false)
129
131
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_ENDPOINT_FINGERPRINT, false)
132
+ rc.updateCapabilities(RemoteConfigCapabilities.ASM_SESSION_FINGERPRINT, false)
130
133
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_NETWORK_FINGERPRINT, false)
131
134
  rc.updateCapabilities(RemoteConfigCapabilities.ASM_HEADER_FINGERPRINT, false)
132
135
 
@@ -3,13 +3,13 @@
3
3
  const { URL, format } = require('url')
4
4
  const uuid = require('crypto-randomuuid')
5
5
  const { EventEmitter } = require('events')
6
- const tracerVersion = require('../../../../../package.json').version
7
- const request = require('../../exporters/common/request')
8
- const log = require('../../log')
9
- const { getExtraServices } = require('../../service-naming/extra-services')
6
+ const tracerVersion = require('../../../../package.json').version
7
+ const request = require('../exporters/common/request')
8
+ const log = require('../log')
9
+ const { getExtraServices } = require('../service-naming/extra-services')
10
10
  const { UNACKNOWLEDGED, ACKNOWLEDGED, ERROR } = require('./apply_states')
11
11
  const Scheduler = require('./scheduler')
12
- const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../../plugins/util/tags')
12
+ const { GIT_REPOSITORY_URL, GIT_COMMIT_SHA } = require('../plugins/util/tags')
13
13
 
14
14
  const clientId = uuid()
15
15
 
@@ -0,0 +1,34 @@
1
+ 'use strict'
2
+
3
+ let runtimeMetrics
4
+
5
+ const noop = runtimeMetrics = {
6
+ stop () {},
7
+ track () {},
8
+ boolean () {},
9
+ histogram () {},
10
+ count () {},
11
+ gauge () {},
12
+ increment () {},
13
+ decrement () {}
14
+ }
15
+
16
+ module.exports = {
17
+ start (config) {
18
+ if (!config?.runtimeMetrics) return
19
+
20
+ runtimeMetrics = require('./runtime_metrics')
21
+
22
+ Object.setPrototypeOf(module.exports, runtimeMetrics)
23
+
24
+ runtimeMetrics.start(config)
25
+ },
26
+
27
+ stop () {
28
+ runtimeMetrics.stop()
29
+
30
+ Object.setPrototypeOf(module.exports, runtimeMetrics = noop)
31
+ }
32
+ }
33
+
34
+ Object.setPrototypeOf(module.exports, noop)
@@ -4,12 +4,12 @@
4
4
 
5
5
  const v8 = require('v8')
6
6
  const os = require('os')
7
- const { DogStatsDClient } = require('./dogstatsd')
8
- const log = require('./log')
9
- const Histogram = require('./histogram')
7
+ const { DogStatsDClient } = require('../dogstatsd')
8
+ const log = require('../log')
9
+ const Histogram = require('../histogram')
10
10
  const { performance, PerformanceObserver } = require('perf_hooks')
11
11
 
12
- const { NODE_MAJOR, NODE_MINOR } = require('../../../version')
12
+ const { NODE_MAJOR, NODE_MINOR } = require('../../../../version')
13
13
  const INTERVAL = 10 * 1000
14
14
 
15
15
  // Node >=16 has PerformanceObserver with `gc` type, but <16.7 had a critical bug.
@@ -60,9 +60,18 @@ function getIsAzureFunction () {
60
60
  return isAzureFunction
61
61
  }
62
62
 
63
+ function isInServerlessEnvironment () {
64
+ const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
65
+ const isGCPFunction = getIsGCPFunction()
66
+ const isAzureFunction = getIsAzureFunction()
67
+
68
+ return inAWSLambda || isGCPFunction || isAzureFunction
69
+ }
70
+
63
71
  module.exports = {
64
72
  maybeStartServerlessMiniAgent,
65
73
  getIsGCPFunction,
66
74
  getIsAzureFunction,
67
- getRustBinaryPath
75
+ getRustBinaryPath,
76
+ isInServerlessEnvironment
68
77
  }
@@ -1,9 +1,7 @@
1
- const { schemaDefinitions } = require('./schemas')
2
-
3
1
  class SchemaManager {
4
2
  constructor () {
5
- this.schemas = schemaDefinitions
6
- this.config = { spanAttributeSchema: 'v0', spanRemoveIntegrationFromService: false }
3
+ this.schemas = {}
4
+ this.configure({ spanAttributeSchema: 'v0', spanRemoveIntegrationFromService: false })
7
5
  }
8
6
 
9
7
  get schema () {
@@ -31,6 +29,16 @@ class SchemaManager {
31
29
  }
32
30
 
33
31
  configure (config = {}) {
32
+ const { spanAttributeSchema, spanRemoveIntegrationFromService } = config
33
+
34
+ if (!this.schemas.v0 && spanAttributeSchema === 'v0') {
35
+ this.schemas.v0 = require('./schemas/v0')
36
+ }
37
+
38
+ if (!this.schemas.v1 && (spanAttributeSchema === 'v1' || spanRemoveIntegrationFromService)) {
39
+ this.schemas.v1 = require('./schemas/v1')
40
+ }
41
+
34
42
  this.config = config
35
43
  }
36
44
  }
@@ -5,8 +5,6 @@ const format = require('./format')
5
5
  const SpanSampler = require('./span_sampler')
6
6
  const GitMetadataTagger = require('./git_metadata_tagger')
7
7
 
8
- const { SpanStatsProcessor } = require('./span_stats')
9
-
10
8
  const startedSpans = new WeakSet()
11
9
  const finishedSpans = new WeakSet()
12
10
 
@@ -20,7 +18,12 @@ class SpanProcessor {
20
18
  this._config = config
21
19
  this._killAll = false
22
20
 
23
- this._stats = new SpanStatsProcessor(config)
21
+ // TODO: This should already have been calculated in `config.js`.
22
+ if (config.stats?.enabled && !config.appsec?.standalone?.enabled) {
23
+ const { SpanStatsProcessor } = require('./span_stats')
24
+ this._stats = new SpanStatsProcessor(config)
25
+ }
26
+
24
27
  this._spanSampler = new SpanSampler(config.sampler)
25
28
  this._gitMetadataTagger = new GitMetadataTagger(config)
26
29
  }
@@ -46,7 +49,7 @@ class SpanProcessor {
46
49
  for (const span of started) {
47
50
  if (span._duration !== undefined) {
48
51
  const formattedSpan = format(span)
49
- this._stats.onSpanFinished(formattedSpan)
52
+ this._stats?.onSpanFinished(formattedSpan)
50
53
  formatted.push(formattedSpan)
51
54
 
52
55
  spanProcessCh.publish({ span })
@@ -127,7 +127,6 @@ class SpanStatsProcessor {
127
127
  url,
128
128
  env,
129
129
  tags,
130
- appsec,
131
130
  version
132
131
  } = {}) {
133
132
  this.exporter = new SpanStatsExporter({
@@ -140,7 +139,7 @@ class SpanStatsProcessor {
140
139
  this.bucketSizeNs = interval * 1e9
141
140
  this.buckets = new TimeBuckets()
142
141
  this.hostname = os.hostname()
143
- this.enabled = enabled && !appsec?.standalone?.enabled
142
+ this.enabled = enabled
144
143
  this.env = env
145
144
  this.tags = tags || {}
146
145
  this.sequence = 0
@@ -0,0 +1,70 @@
1
+ 'use strict'
2
+
3
+ const { channel } = require('dc-polyfill')
4
+ const TraceSourcePrioritySampler = require('./tracesource_priority_sampler')
5
+ const { USER_KEEP } = require('../../../../ext/priority')
6
+ const TraceState = require('../opentracing/propagation/tracestate')
7
+ const { APM_TRACING_ENABLED_KEY } = require('../constants')
8
+ const { hasTraceSourcePropagationTag } = require('./tracesource')
9
+
10
+ const startCh = channel('dd-trace:span:start')
11
+ const injectCh = channel('dd-trace:span:inject')
12
+ const extractCh = channel('dd-trace:span:extract')
13
+
14
+ function configure (config) {
15
+ if (startCh.hasSubscribers) startCh.unsubscribe(onSpanStart)
16
+ if (injectCh.hasSubscribers) injectCh.unsubscribe(onSpanInject)
17
+ if (extractCh.hasSubscribers) extractCh.unsubscribe(onSpanExtract)
18
+
19
+ if (config.apmTracingEnabled !== false) return
20
+
21
+ startCh.subscribe(onSpanStart)
22
+ injectCh.subscribe(onSpanInject)
23
+ extractCh.subscribe(onSpanExtract)
24
+
25
+ return new TraceSourcePrioritySampler(config.env)
26
+ }
27
+
28
+ function onSpanStart ({ span, fields }) {
29
+ const tags = span.context?.()?._tags
30
+ if (!tags) return
31
+
32
+ const { parent } = fields
33
+ if (!parent || parent._isRemote) {
34
+ tags[APM_TRACING_ENABLED_KEY] = 0
35
+ }
36
+ }
37
+
38
+ function onSpanInject ({ spanContext, carrier }) {
39
+ if (!spanContext?._trace?.tags || !carrier) return
40
+
41
+ // do not inject trace and sampling if there is no _dd.p.ts
42
+ if (!hasTraceSourcePropagationTag(spanContext._trace.tags)) {
43
+ for (const key in carrier) {
44
+ const lKey = key.toLowerCase()
45
+ if (lKey.startsWith('x-datadog') || lKey.startsWith('x-b3') || lKey === 'traceparent') {
46
+ delete carrier[key]
47
+ } else if (lKey === 'tracestate') {
48
+ const tracestate = TraceState.fromString(carrier[key])
49
+ tracestate.forVendor('dd', state => state.clear())
50
+ carrier[key] = tracestate.toString()
51
+ }
52
+ }
53
+ }
54
+ }
55
+
56
+ function onSpanExtract ({ spanContext = {} }) {
57
+ if (!spanContext._trace?.tags || !spanContext._sampling) return
58
+
59
+ // reset upstream priority if _dd.p.ts is not found
60
+ if (!hasTraceSourcePropagationTag(spanContext._trace.tags)) {
61
+ spanContext._sampling.priority = undefined
62
+ } else if (spanContext._sampling.priority !== USER_KEEP) {
63
+ spanContext._sampling.priority = USER_KEEP
64
+ }
65
+ }
66
+
67
+ module.exports = {
68
+ configure,
69
+ hasTraceSourcePropagationTag
70
+ }
@@ -0,0 +1,24 @@
1
+ 'use strict'
2
+
3
+ const { SAMPLING_MECHANISM_APPSEC } = require('../constants')
4
+ const RateLimiter = require('../rate_limiter')
5
+
6
+ const dropAll = new RateLimiter(0)
7
+ const onePerMinute = new RateLimiter(1, 'minute')
8
+
9
+ function getProductRateLimiter (config) {
10
+ if (config?.appsec?.enabled || config?.iast?.enabled) {
11
+ return onePerMinute
12
+ }
13
+ return dropAll
14
+ }
15
+
16
+ module.exports = {
17
+ APM: { id: 1 << 0 },
18
+ ASM: { id: 1 << 1, mechanism: SAMPLING_MECHANISM_APPSEC },
19
+ DSM: { id: 1 << 2 },
20
+ DJM: { id: 1 << 3 },
21
+ DBM: { id: 1 << 4 },
22
+
23
+ getProductRateLimiter
24
+ }
@@ -0,0 +1,22 @@
1
+ 'use strict'
2
+
3
+ const { TRACE_SOURCE_PROPAGATION_KEY } = require('../constants')
4
+ const { hasOwn } = require('../util')
5
+
6
+ function addTraceSourceTag (tags, product) {
7
+ if (tags && product) {
8
+ const actual = tags[TRACE_SOURCE_PROPAGATION_KEY] ? parseInt(tags[TRACE_SOURCE_PROPAGATION_KEY], 16) : 0
9
+ tags[TRACE_SOURCE_PROPAGATION_KEY] = ((actual | product.id) >>> 0).toString(16).padStart(2, '0')
10
+ }
11
+
12
+ return tags
13
+ }
14
+
15
+ function hasTraceSourcePropagationTag (tags) {
16
+ return hasOwn(tags, TRACE_SOURCE_PROPAGATION_KEY)
17
+ }
18
+
19
+ module.exports = {
20
+ addTraceSourceTag,
21
+ hasTraceSourcePropagationTag
22
+ }
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ const { hasOwn } = require('../util')
4
+ const PrioritySampler = require('../priority_sampler')
5
+ const { MANUAL_KEEP } = require('../../../../ext/tags')
6
+ const { USER_KEEP, AUTO_KEEP, AUTO_REJECT } = require('../../../../ext/priority')
7
+ const { SAMPLING_MECHANISM_DEFAULT } = require('../constants')
8
+ const { addTraceSourceTag, hasTraceSourcePropagationTag } = require('./tracesource')
9
+ const { getProductRateLimiter } = require('./product')
10
+
11
+ class TraceSourcePrioritySampler extends PrioritySampler {
12
+ configure (env, sampler, config) {
13
+ // rules not supported
14
+ this._env = env
15
+ this._limiter = getProductRateLimiter(config)
16
+ }
17
+
18
+ _getPriorityFromTags (tags, context) {
19
+ if (hasOwn(tags, MANUAL_KEEP) &&
20
+ tags[MANUAL_KEEP] !== false &&
21
+ hasTraceSourcePropagationTag(context._trace.tags)
22
+ ) {
23
+ return USER_KEEP
24
+ }
25
+ }
26
+
27
+ _getPriorityFromAuto (span) {
28
+ const context = this._getContext(span)
29
+
30
+ context._sampling.mechanism = SAMPLING_MECHANISM_DEFAULT
31
+
32
+ if (hasTraceSourcePropagationTag(context._trace.tags)) {
33
+ return USER_KEEP
34
+ }
35
+
36
+ return this._isSampledByRateLimit(context) ? AUTO_KEEP : AUTO_REJECT
37
+ }
38
+
39
+ setPriority (span, samplingPriority, product) {
40
+ super.setPriority(span, samplingPriority, product)
41
+
42
+ const context = this._getContext(span)
43
+ addTraceSourceTag(context?._trace?.tags, product)
44
+ }
45
+ }
46
+
47
+ module.exports = TraceSourcePrioritySampler