dd-trace 2.17.0 → 2.19.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 (89) hide show
  1. package/index.d.ts +40 -2
  2. package/package.json +1 -1
  3. package/packages/datadog-instrumentations/src/cucumber.js +0 -2
  4. package/packages/datadog-instrumentations/src/elasticsearch.js +51 -47
  5. package/packages/datadog-instrumentations/src/google-cloud-pubsub.js +1 -1
  6. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  7. package/packages/datadog-instrumentations/src/mariadb.js +43 -69
  8. package/packages/datadog-instrumentations/src/mocha.js +14 -18
  9. package/packages/datadog-instrumentations/src/opensearch.js +10 -0
  10. package/packages/datadog-instrumentations/src/pg.js +2 -1
  11. package/packages/datadog-instrumentations/src/restify.js +1 -0
  12. package/packages/datadog-instrumentations/src/rhea.js +20 -17
  13. package/packages/datadog-plugin-amqp10/src/consumer.js +32 -0
  14. package/packages/datadog-plugin-amqp10/src/index.js +11 -101
  15. package/packages/datadog-plugin-amqp10/src/producer.js +34 -0
  16. package/packages/datadog-plugin-amqp10/src/util.js +15 -0
  17. package/packages/datadog-plugin-amqplib/src/client.js +38 -0
  18. package/packages/datadog-plugin-amqplib/src/consumer.js +40 -0
  19. package/packages/datadog-plugin-amqplib/src/index.js +14 -102
  20. package/packages/datadog-plugin-amqplib/src/producer.js +37 -0
  21. package/packages/datadog-plugin-amqplib/src/util.js +14 -0
  22. package/packages/datadog-plugin-dns/src/index.js +16 -91
  23. package/packages/datadog-plugin-dns/src/lookup.js +40 -0
  24. package/packages/datadog-plugin-dns/src/lookup_service.js +24 -0
  25. package/packages/datadog-plugin-dns/src/resolve.js +24 -0
  26. package/packages/datadog-plugin-dns/src/reverse.js +21 -0
  27. package/packages/datadog-plugin-elasticsearch/src/index.js +7 -7
  28. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +25 -0
  29. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +42 -0
  30. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +14 -99
  31. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +34 -0
  32. package/packages/datadog-plugin-graphql/src/execute.js +73 -0
  33. package/packages/datadog-plugin-graphql/src/index.js +14 -176
  34. package/packages/datadog-plugin-graphql/src/parse.js +32 -0
  35. package/packages/datadog-plugin-graphql/src/resolve.js +70 -76
  36. package/packages/datadog-plugin-graphql/src/validate.js +28 -0
  37. package/packages/datadog-plugin-grpc/src/client.js +46 -55
  38. package/packages/datadog-plugin-grpc/src/index.js +7 -24
  39. package/packages/datadog-plugin-grpc/src/server.js +50 -52
  40. package/packages/datadog-plugin-grpc/src/util.js +15 -14
  41. package/packages/datadog-plugin-http/src/index.js +7 -22
  42. package/packages/datadog-plugin-http2/src/index.js +8 -26
  43. package/packages/datadog-plugin-jest/src/index.js +3 -0
  44. package/packages/datadog-plugin-kafkajs/src/consumer.js +42 -0
  45. package/packages/datadog-plugin-kafkajs/src/index.js +11 -87
  46. package/packages/datadog-plugin-kafkajs/src/producer.js +31 -0
  47. package/packages/datadog-plugin-mocha/src/index.js +2 -2
  48. package/packages/datadog-plugin-moleculer/src/client.js +22 -36
  49. package/packages/datadog-plugin-moleculer/src/index.js +8 -26
  50. package/packages/datadog-plugin-moleculer/src/server.js +18 -30
  51. package/packages/datadog-plugin-net/src/ipc.js +21 -0
  52. package/packages/datadog-plugin-net/src/tcp.js +46 -0
  53. package/packages/datadog-plugin-opensearch/src/index.js +11 -0
  54. package/packages/datadog-plugin-pg/src/index.js +2 -1
  55. package/packages/datadog-plugin-rhea/src/consumer.js +55 -0
  56. package/packages/datadog-plugin-rhea/src/index.js +11 -99
  57. package/packages/datadog-plugin-rhea/src/producer.js +45 -0
  58. package/packages/datadog-plugin-sharedb/src/index.js +22 -39
  59. package/packages/dd-trace/src/appsec/iast/analyzers/vulnerability-analyzer.js +1 -1
  60. package/packages/dd-trace/src/appsec/iast/index.js +4 -6
  61. package/packages/dd-trace/src/appsec/iast/path-line.js +3 -0
  62. package/packages/dd-trace/src/appsec/recommended.json +60 -46
  63. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -5
  64. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -5
  65. package/packages/dd-trace/src/config.js +31 -6
  66. package/packages/dd-trace/src/constants.js +3 -0
  67. package/packages/dd-trace/src/dogstatsd.js +42 -10
  68. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +10 -2
  69. package/packages/dd-trace/src/exporters/agent/writer.js +2 -9
  70. package/packages/dd-trace/src/exporters/common/request.js +12 -0
  71. package/packages/dd-trace/src/format.js +13 -0
  72. package/packages/dd-trace/src/metrics.js +10 -2
  73. package/packages/dd-trace/src/plugin_manager.js +6 -1
  74. package/packages/dd-trace/src/plugins/client.js +3 -1
  75. package/packages/dd-trace/src/plugins/composite.js +26 -0
  76. package/packages/dd-trace/src/plugins/consumer.js +9 -0
  77. package/packages/dd-trace/src/plugins/incoming.js +7 -0
  78. package/packages/dd-trace/src/plugins/index.js +1 -0
  79. package/packages/dd-trace/src/plugins/outgoing.js +1 -1
  80. package/packages/dd-trace/src/plugins/producer.js +9 -0
  81. package/packages/dd-trace/src/plugins/server.js +9 -0
  82. package/packages/dd-trace/src/plugins/storage.js +0 -4
  83. package/packages/dd-trace/src/plugins/tracing.js +10 -9
  84. package/packages/dd-trace/src/plugins/util/web.js +49 -3
  85. package/packages/dd-trace/src/profiling/profiler.js +8 -1
  86. package/packages/dd-trace/src/span_processor.js +3 -0
  87. package/packages/dd-trace/src/span_sampler.js +80 -0
  88. package/packages/dd-trace/src/tracer.js +6 -2
  89. package/packages/dd-trace/src/util.js +43 -1
@@ -1,48 +1,31 @@
1
1
  'use strict'
2
2
 
3
- const Plugin = require('../../dd-trace/src/plugins/plugin')
4
- const { storage } = require('../../datadog-core')
5
-
6
- class SharedbPlugin extends Plugin {
7
- static get name () {
8
- return 'sharedb'
9
- }
10
-
11
- constructor (...args) {
12
- super(...args)
13
-
14
- this.addSub(`apm:sharedb:request:start`, ({ actionName, request }) => {
15
- const store = storage.getStore()
16
- const childOf = store ? store.span : store
17
- const span = this.tracer.startSpan('sharedb.request', {
18
- childOf,
19
- tags: {
20
- 'service.name': this.config.service || this.tracer._service,
21
- 'span.kind': 'server',
22
- 'sharedb.action': actionName,
23
- 'resource.name': getReadableResourceName(actionName, request.c, request.q)
24
- }
25
- })
26
-
27
- if (this.config.hooks && this.config.hooks.receive) {
28
- this.config.hooks.receive(span, request)
3
+ const ServerPlugin = require('../../dd-trace/src/plugins/server')
4
+
5
+ class SharedbPlugin extends ServerPlugin {
6
+ static get name () { return 'sharedb' }
7
+
8
+ start ({ actionName, request }) {
9
+ const span = this.startSpan('sharedb.request', {
10
+ service: this.config.service,
11
+ resource: getReadableResourceName(actionName, request.c, request.q),
12
+ kind: 'server',
13
+ meta: {
14
+ 'sharedb.action': actionName
29
15
  }
30
-
31
- this.enter(span, store)
32
16
  })
33
17
 
34
- this.addSub(`apm:sharedb:request:error`, err => {
35
- const span = storage.getStore().span
36
- span.setTag('error', err)
37
- })
18
+ if (this.config.hooks && this.config.hooks.receive) {
19
+ this.config.hooks.receive(span, request)
20
+ }
21
+ }
38
22
 
39
- this.addSub(`apm:sharedb:request:finish`, ({ request, res }) => {
40
- const span = storage.getStore().span
41
- if (this.config.hooks && this.config.hooks.reply) {
42
- this.config.hooks.reply(span, request, res)
43
- }
44
- span.finish()
45
- })
23
+ finish ({ request, res }) {
24
+ const span = this.activeSpan
25
+ if (this.config.hooks && this.config.hooks.reply) {
26
+ this.config.hooks.reply(span, request, res)
27
+ }
28
+ span.finish()
46
29
  }
47
30
  }
48
31
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  const Plugin = require('../../../../src/plugins/plugin')
4
4
  const { storage } = require('../../../../../datadog-core')
5
- const { getFirstNonDDPathAndLine } = require('./../path-line')
5
+ const { getFirstNonDDPathAndLine } = require('../path-line')
6
6
  const { createVulnerability, addVulnerability } = require('../vulnerability-reporter')
7
7
  const { getIastContext } = require('../iast-context')
8
8
  const overheadController = require('../overhead-controller')
@@ -4,8 +4,7 @@ const web = require('../../plugins/util/web')
4
4
  const { storage } = require('../../../../datadog-core')
5
5
  const overheadController = require('./overhead-controller')
6
6
  const dc = require('diagnostics_channel')
7
- const { saveIastContext, getIastContext, cleanIastContext } = require('./iast-context')
8
-
7
+ const iastContextFunctions = require('./iast-context')
9
8
  // TODO Change to `apm:http:server:request:[start|close]` when the subscription
10
9
  // order of the callbacks can be enforce
11
10
  const requestStart = dc.channel('dd-trace:incomingHttpRequestStart')
@@ -33,7 +32,7 @@ function onIncomingHttpRequestStart (data) {
33
32
  const rootSpan = topContext.span
34
33
  const isRequestAcquired = overheadController.acquireRequest(rootSpan)
35
34
  if (isRequestAcquired) {
36
- const iastContext = saveIastContext(store, topContext, { rootSpan, req: data.req })
35
+ const iastContext = iastContextFunctions.saveIastContext(store, topContext, { rootSpan, req: data.req })
37
36
  overheadController.initializeRequestContext(iastContext)
38
37
  }
39
38
  }
@@ -44,13 +43,12 @@ function onIncomingHttpRequestStart (data) {
44
43
  function onIncomingHttpRequestEnd (data) {
45
44
  if (data && data.req) {
46
45
  const store = storage.getStore()
47
- const iastContext = getIastContext(storage.getStore())
46
+ const iastContext = iastContextFunctions.getIastContext(storage.getStore())
48
47
  if (iastContext && iastContext.rootSpan) {
49
- overheadController.releaseRequest()
50
48
  sendVulnerabilities(iastContext, iastContext.rootSpan)
51
49
  }
52
50
  // TODO web.getContext(data.req) is required when the request is aborted
53
- if (cleanIastContext(store, web.getContext(data.req), iastContext)) {
51
+ if (iastContextFunctions.cleanIastContext(store, web.getContext(data.req), iastContext)) {
54
52
  overheadController.releaseRequest()
55
53
  }
56
54
  }
@@ -51,6 +51,9 @@ function getFirstNonDDPathAndLineFromCallsites (callsites) {
51
51
  function isExcluded (callsite) {
52
52
  if (callsite.isNative()) return true
53
53
  const filename = callsite.getFileName()
54
+ if (!filename) {
55
+ return true
56
+ }
54
57
  for (let i = 0; i < EXCLUDED_PATHS.length; i++) {
55
58
  if (filename.indexOf(EXCLUDED_PATHS[i]) > -1) {
56
59
  return true
@@ -1,9 +1,34 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.4.0"
4
+ "rules_version": "1.4.2"
5
5
  },
6
6
  "rules": [
7
+ {
8
+ "id": "blk-001-001",
9
+ "name": "Block IP Addresses",
10
+ "tags": {
11
+ "type": "block_ip",
12
+ "category": "security_response"
13
+ },
14
+ "conditions": [
15
+ {
16
+ "parameters": {
17
+ "inputs": [
18
+ {
19
+ "address": "http.client_ip"
20
+ }
21
+ ],
22
+ "data": "blocked_ips"
23
+ },
24
+ "operator": "ip_match"
25
+ }
26
+ ],
27
+ "transformers": [],
28
+ "on_match": [
29
+ "block"
30
+ ]
31
+ },
7
32
  {
8
33
  "id": "crs-913-110",
9
34
  "name": "Acunetix",
@@ -2828,51 +2853,6 @@
2828
2853
  ],
2829
2854
  "transformers": []
2830
2855
  },
2831
- {
2832
- "id": "crs-941-100",
2833
- "name": "XSS Attack Detected via libinjection",
2834
- "tags": {
2835
- "type": "xss",
2836
- "crs_id": "941100",
2837
- "category": "attack_attempt"
2838
- },
2839
- "conditions": [
2840
- {
2841
- "parameters": {
2842
- "inputs": [
2843
- {
2844
- "address": "server.request.headers.no_cookies",
2845
- "key_path": [
2846
- "user-agent"
2847
- ]
2848
- },
2849
- {
2850
- "address": "server.request.headers.no_cookies",
2851
- "key_path": [
2852
- "referer"
2853
- ]
2854
- },
2855
- {
2856
- "address": "server.request.query"
2857
- },
2858
- {
2859
- "address": "server.request.body"
2860
- },
2861
- {
2862
- "address": "server.request.path_params"
2863
- },
2864
- {
2865
- "address": "grpc.server.request.message"
2866
- }
2867
- ]
2868
- },
2869
- "operator": "is_xss"
2870
- }
2871
- ],
2872
- "transformers": [
2873
- "removeNulls"
2874
- ]
2875
- },
2876
2856
  {
2877
2857
  "id": "crs-941-110",
2878
2858
  "name": "XSS Filter - Category 1: Script Tag Vector",
@@ -4338,6 +4318,40 @@
4338
4318
  "keys_only"
4339
4319
  ]
4340
4320
  },
4321
+ {
4322
+ "id": "dog-000-007",
4323
+ "name": "Server side template injection: Velocity & Freemarker",
4324
+ "tags": {
4325
+ "type": "java_code_injection",
4326
+ "category": "attack_attempt"
4327
+ },
4328
+ "conditions": [
4329
+ {
4330
+ "parameters": {
4331
+ "inputs": [
4332
+ {
4333
+ "address": "server.request.query"
4334
+ },
4335
+ {
4336
+ "address": "server.request.body"
4337
+ },
4338
+ {
4339
+ "address": "server.request.path_params"
4340
+ },
4341
+ {
4342
+ "address": "server.request.headers.no_cookies"
4343
+ },
4344
+ {
4345
+ "address": "grpc.server.request.message"
4346
+ }
4347
+ ],
4348
+ "regex": "#(?:set|foreach|macro|parse|if)\\(.*\\)|<#assign.*>"
4349
+ },
4350
+ "operator": "match_regex"
4351
+ }
4352
+ ],
4353
+ "transformers": []
4354
+ },
4341
4355
  {
4342
4356
  "id": "nfd-000-001",
4343
4357
  "name": "Detect common directory discovery scans",
@@ -26,13 +26,10 @@ class Writer extends BaseWriter {
26
26
  'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
27
27
  ...form.getHeaders()
28
28
  },
29
- timeout: 15000
29
+ timeout: 15000,
30
+ url: this._url
30
31
  }
31
32
 
32
- options.protocol = this._url.protocol
33
- options.hostname = this._url.hostname
34
- options.port = this._url.port
35
-
36
33
  log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
37
34
 
38
35
  request(form, options, (err, res) => {
@@ -27,13 +27,10 @@ class Writer extends BaseWriter {
27
27
  'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
28
28
  'Content-Type': 'application/msgpack'
29
29
  },
30
- timeout: 15000
30
+ timeout: 15000,
31
+ url: this._url
31
32
  }
32
33
 
33
- options.protocol = this._url.protocol
34
- options.hostname = this._url.hostname
35
- options.port = this._url.port
36
-
37
34
  log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
38
35
  request(data, options, (err, res) => {
39
36
  if (err) {
@@ -13,6 +13,15 @@ const uuid = require('crypto-randomuuid')
13
13
  const fromEntries = Object.fromEntries || (entries =>
14
14
  entries.reduce((obj, [k, v]) => Object.assign(obj, { [k]: v }), {}))
15
15
 
16
+ function maybeFile (filepath) {
17
+ if (!filepath) return
18
+ try {
19
+ return fs.readFileSync(filepath, 'utf8')
20
+ } catch (e) {
21
+ return undefined
22
+ }
23
+ }
24
+
16
25
  function safeJsonParse (input) {
17
26
  try {
18
27
  return JSON.parse(input)
@@ -133,14 +142,14 @@ class Config {
133
142
  parseInt(process.env.DD_TRACE_PARTIAL_FLUSH_MIN_SPANS),
134
143
  1000
135
144
  )
136
- const DD_TRACE_CLIENT_IP_HEADER_DISABLED = coalesce(
137
- process.env.DD_TRACE_CLIENT_IP_HEADER_DISABLED,
138
- false
139
- )
140
145
  const DD_TRACE_CLIENT_IP_HEADER = coalesce(
141
146
  process.env.DD_TRACE_CLIENT_IP_HEADER,
142
147
  null
143
148
  )
149
+ const DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP = coalesce(
150
+ process.env.DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
151
+ '.*'
152
+ )
144
153
  const DD_TRACE_B3_ENABLED = coalesce(
145
154
  options.experimental && options.experimental.b3,
146
155
  process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
@@ -260,10 +269,25 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
260
269
  ingestion.sampleRate
261
270
  ),
262
271
  rateLimit: coalesce(options.rateLimit, process.env.DD_TRACE_RATE_LIMIT, ingestion.rateLimit),
263
- rules: coalesce(options.samplingRules, safeJsonParse(process.env.DD_TRACE_SAMPLING_RULES), []).map(rule => {
272
+ rules: coalesce(
273
+ options.samplingRules,
274
+ safeJsonParse(process.env.DD_TRACE_SAMPLING_RULES),
275
+ []
276
+ ).map(rule => {
264
277
  return remapify(rule, {
265
278
  sample_rate: 'sampleRate'
266
279
  })
280
+ }),
281
+ spanSamplingRules: coalesce(
282
+ options.spanSamplingRules,
283
+ safeJsonParse(maybeFile(process.env.DD_SPAN_SAMPLING_RULES_FILE)),
284
+ safeJsonParse(process.env.DD_SPAN_SAMPLING_RULES),
285
+ []
286
+ ).map(rule => {
287
+ return remapify(rule, {
288
+ sample_rate: 'sampleRate',
289
+ max_per_second: 'maxPerSecond'
290
+ })
267
291
  })
268
292
  }
269
293
 
@@ -282,8 +306,9 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
282
306
  this.flushInterval = coalesce(parseInt(options.flushInterval, 10), defaultFlushInterval)
283
307
  this.flushMinSpans = DD_TRACE_PARTIAL_FLUSH_MIN_SPANS
284
308
  this.sampleRate = coalesce(Math.min(Math.max(sampler.sampleRate, 0), 1), 1)
285
- this.clientIpHeaderDisabled = isTrue(DD_TRACE_CLIENT_IP_HEADER_DISABLED)
309
+ this.clientIpHeaderDisabled = !isTrue(DD_APPSEC_ENABLED)
286
310
  this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
311
+ this.queryStringObfuscation = DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP
287
312
  this.logger = options.logger
288
313
  this.plugins = !!coalesce(options.plugins, true)
289
314
  this.service = DD_SERVICE
@@ -15,6 +15,9 @@ module.exports = {
15
15
  SAMPLING_MECHANISM_MANUAL: 4,
16
16
  SAMPLING_MECHANISM_APPSEC: 5,
17
17
  SAMPLING_MECHANISM_SPAN: 8,
18
+ SPAN_SAMPLING_MECHANISM: '_dd.span_sampling.mechanism',
19
+ SPAN_SAMPLING_RULE_RATE: '_dd.span_sampling.rule_rate',
20
+ SPAN_SAMPLING_MAX_PER_SECOND: '_dd.span_sampling.max_per_second',
18
21
  DATADOG_LAMBDA_EXTENSION_PATH: '/opt/extensions/datadog-agent',
19
22
  DECISION_MAKER_KEY: '_dd.p.dm'
20
23
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  const lookup = require('dns').lookup // cache to avoid instrumentation
4
+ const request = require('./exporters/common/request')
4
5
  const dgram = require('dgram')
5
6
  const isIP = require('net').isIP
6
7
  const log = require('./log')
@@ -11,6 +12,13 @@ class Client {
11
12
  constructor (options) {
12
13
  options = options || {}
13
14
 
15
+ if (options.metricsProxyUrl) {
16
+ this._httpOptions = {
17
+ url: options.metricsProxyUrl.toString(),
18
+ path: '/dogstatsd/v2/proxy'
19
+ }
20
+ }
21
+
14
22
  this._host = options.host || 'localhost'
15
23
  this._family = isIP(this._host)
16
24
  this._port = options.port || 8125
@@ -38,26 +46,50 @@ class Client {
38
46
 
39
47
  this._queue = []
40
48
 
49
+ if (this._httpOptions) {
50
+ this._sendHttp(queue)
51
+ } else {
52
+ this._sendUdp(queue)
53
+ }
54
+ }
55
+
56
+ _sendHttp (queue) {
57
+ const buffer = Buffer.concat(queue)
58
+ request(buffer, this._httpOptions, (err) => {
59
+ if (err) {
60
+ log.error('HTTP error from agent: ' + err.stack)
61
+ if (err.status) {
62
+ // Inside this if-block, we have connectivity to the agent, but
63
+ // we're not getting a 200 from the proxy endpoint. If it's a 404,
64
+ // then we know we'll never have the endpoint, so just clear out the
65
+ // options. Either way, we can give UDP a try.
66
+ if (err.status === 404) {
67
+ this._httpOptions = null
68
+ }
69
+ this._sendUdp(queue)
70
+ }
71
+ }
72
+ })
73
+ }
74
+
75
+ _sendUdp (queue) {
41
76
  if (this._family !== 0) {
42
- this._sendAll(queue, this._host, this._family)
77
+ this._sendUdpFromQueue(queue, this._host, this._family)
43
78
  } else {
44
79
  lookup(this._host, (err, address, family) => {
45
80
  if (err) return log.error(err)
46
- this._sendAll(queue, address, family)
81
+ this._sendUdpFromQueue(queue, address, family)
47
82
  })
48
83
  }
49
84
  }
50
85
 
51
- _send (address, family, buffer) {
86
+ _sendUdpFromQueue (queue, address, family) {
52
87
  const socket = family === 6 ? this._udp6 : this._udp4
53
88
 
54
- log.debug(`Sending to DogStatsD: ${buffer}`)
55
-
56
- socket.send(buffer, 0, buffer.length, this._port, address)
57
- }
58
-
59
- _sendAll (queue, address, family) {
60
- queue.forEach((buffer) => this._send(address, family, buffer))
89
+ queue.forEach((buffer) => {
90
+ log.debug(`Sending to DogStatsD: ${buffer}`)
91
+ socket.send(buffer, 0, buffer.length, this._port, address)
92
+ })
61
93
  }
62
94
 
63
95
  _add (stat, value, type, tags) {
@@ -197,8 +197,16 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
197
197
  }
198
198
 
199
199
  _encode (bytes, trace) {
200
- this._eventCount += trace.length
201
- const events = trace.map(formatSpan)
200
+ const rawEvents = trace.map(formatSpan)
201
+
202
+ const testSessionEvents = rawEvents.filter(
203
+ event => event.type === 'test_session_end' || event.type === 'test_suite_end'
204
+ )
205
+
206
+ const isTestSessionTrace = !!testSessionEvents.length
207
+ const events = isTestSessionTrace ? testSessionEvents : rawEvents
208
+
209
+ this._eventCount += events.length
202
210
 
203
211
  for (const event of events) {
204
212
  this._encodeEvent(bytes, event)
@@ -85,21 +85,14 @@ function makeRequest (version, data, count, url, headers, lookup, needsStartupLo
85
85
  'Datadog-Meta-Tracer-Version': tracerVersion,
86
86
  'X-Datadog-Trace-Count': String(count)
87
87
  },
88
- lookup
88
+ lookup,
89
+ url
89
90
  }
90
91
 
91
92
  setHeader(options.headers, 'Datadog-Meta-Lang', 'nodejs')
92
93
  setHeader(options.headers, 'Datadog-Meta-Lang-Version', process.version)
93
94
  setHeader(options.headers, 'Datadog-Meta-Lang-Interpreter', process.jsEngine || 'v8')
94
95
 
95
- if (url.protocol === 'unix:') {
96
- options.socketPath = url.pathname
97
- } else {
98
- options.protocol = url.protocol
99
- options.hostname = url.hostname
100
- options.port = url.port
101
- }
102
-
103
96
  log.debug(() => `Request to the agent: ${JSON.stringify(options)}`)
104
97
 
105
98
  request(data, options, (err, res, status) => {
@@ -6,6 +6,7 @@
6
6
  const { Readable } = require('stream')
7
7
  const http = require('http')
8
8
  const https = require('https')
9
+ const { parse: urlParse } = require('url')
9
10
  const docker = require('./docker')
10
11
  const { storage } = require('../../../../datadog-core')
11
12
  const log = require('../../log')
@@ -24,6 +25,17 @@ function request (data, options, callback) {
24
25
  options.headers = {}
25
26
  }
26
27
 
28
+ if (options.url) {
29
+ const url = typeof options.url === 'object' ? options.url : urlParse(options.url)
30
+ if (url.protocol === 'unix:') {
31
+ options.socketPath = url.pathname
32
+ } else {
33
+ options.protocol = url.protocol
34
+ options.hostname = url.hostname
35
+ options.port = url.port
36
+ }
37
+ }
38
+
27
39
  const isReadable = data instanceof Readable
28
40
 
29
41
  // The timeout should be kept low to avoid excessive queueing.
@@ -9,6 +9,10 @@ const SAMPLING_PRIORITY_KEY = constants.SAMPLING_PRIORITY_KEY
9
9
  const SAMPLING_RULE_DECISION = constants.SAMPLING_RULE_DECISION
10
10
  const SAMPLING_LIMIT_DECISION = constants.SAMPLING_LIMIT_DECISION
11
11
  const SAMPLING_AGENT_DECISION = constants.SAMPLING_AGENT_DECISION
12
+ const SPAN_SAMPLING_MECHANISM = constants.SPAN_SAMPLING_MECHANISM
13
+ const SPAN_SAMPLING_RULE_RATE = constants.SPAN_SAMPLING_RULE_RATE
14
+ const SPAN_SAMPLING_MAX_PER_SECOND = constants.SPAN_SAMPLING_MAX_PER_SECOND
15
+ const SAMPLING_MECHANISM_SPAN = constants.SAMPLING_MECHANISM_SPAN
12
16
  const MEASURED = tags.MEASURED
13
17
  const ORIGIN_KEY = constants.ORIGIN_KEY
14
18
  const HOSTNAME_KEY = constants.HOSTNAME_KEY
@@ -47,6 +51,13 @@ function formatSpan (span) {
47
51
  }
48
52
  }
49
53
 
54
+ function setSingleSpanIngestionTags (span, options) {
55
+ if (!options) return
56
+ addTag({}, span.metrics, SPAN_SAMPLING_MECHANISM, SAMPLING_MECHANISM_SPAN)
57
+ addTag({}, span.metrics, SPAN_SAMPLING_RULE_RATE, options.sampleRate)
58
+ addTag({}, span.metrics, SPAN_SAMPLING_MAX_PER_SECOND, options.maxPerSecond)
59
+ }
60
+
50
61
  function extractTags (trace, span) {
51
62
  const context = span.context()
52
63
  const origin = context._trace.origin
@@ -96,6 +107,8 @@ function extractTags (trace, span) {
96
107
  addTag(trace.meta, trace.metrics, 'language', 'javascript')
97
108
  }
98
109
 
110
+ setSingleSpanIngestionTags(trace, context._sampling.spanSampling)
111
+
99
112
  addTag(trace.meta, trace.metrics, SAMPLING_PRIORITY_KEY, priority)
100
113
  addTag(trace.meta, trace.metrics, ORIGIN_KEY, origin)
101
114
  addTag(trace.meta, trace.metrics, HOSTNAME_KEY, hostname)
@@ -48,11 +48,19 @@ module.exports = {
48
48
  nativeMetrics = null
49
49
  }
50
50
 
51
- client = new Client({
51
+ const clientConfig = {
52
52
  host: config.dogstatsd.hostname,
53
53
  port: config.dogstatsd.port,
54
54
  tags
55
- })
55
+ }
56
+
57
+ if (config.url) {
58
+ clientConfig.metricsProxyUrl = config.url
59
+ } else if (config.port) {
60
+ clientConfig.metricsProxyUrl = new URL(`http://${config.hostname || 'localhost'}:${config.port}`)
61
+ }
62
+
63
+ client = new Client(clientConfig)
56
64
 
57
65
  time = process.hrtime()
58
66
 
@@ -123,7 +123,8 @@ module.exports = class PluginManager {
123
123
  clientIpHeader,
124
124
  isIntelligentTestRunnerEnabled,
125
125
  site,
126
- experimental
126
+ experimental,
127
+ queryStringObfuscation
127
128
  } = this._tracerConfig
128
129
 
129
130
  const sharedConfig = {}
@@ -132,6 +133,10 @@ module.exports = class PluginManager {
132
133
  sharedConfig.logInjection = logInjection
133
134
  }
134
135
 
136
+ if (queryStringObfuscation !== undefined) {
137
+ sharedConfig.queryStringObfuscation = queryStringObfuscation
138
+ }
139
+
135
140
  if (clientIpHeaderDisabled !== undefined) {
136
141
  sharedConfig.clientIpHeaderDisabled = clientIpHeaderDisabled
137
142
  }
@@ -2,6 +2,8 @@
2
2
 
3
3
  const OutgoingPlugin = require('./outgoing')
4
4
 
5
- class ClientPlugin extends OutgoingPlugin {}
5
+ class ClientPlugin extends OutgoingPlugin {
6
+ static get operation () { return 'request' }
7
+ }
6
8
 
7
9
  module.exports = ClientPlugin
@@ -0,0 +1,26 @@
1
+ 'use strict'
2
+
3
+ const Plugin = require('./plugin')
4
+
5
+ class CompositePlugin extends Plugin {
6
+ constructor (...args) {
7
+ super(...args)
8
+
9
+ for (const [name, PluginClass] of Object.entries(this.constructor.plugins)) {
10
+ this[name] = new PluginClass(...args)
11
+ }
12
+ }
13
+
14
+ configure (config) {
15
+ for (const name in this.constructor.plugins) {
16
+ const pluginConfig = config[name] === false ? false : {
17
+ ...config,
18
+ ...config[name]
19
+ }
20
+
21
+ this[name].configure(pluginConfig)
22
+ }
23
+ }
24
+ }
25
+
26
+ module.exports = CompositePlugin
@@ -0,0 +1,9 @@
1
+ 'use strict'
2
+
3
+ const IncomingPlugin = require('./incoming')
4
+
5
+ class ConsumerPlugin extends IncomingPlugin {
6
+ static get operation () { return 'receive' }
7
+ }
8
+
9
+ module.exports = ConsumerPlugin
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ const TracingPlugin = require('./tracing')
4
+
5
+ class IncomingPlugin extends TracingPlugin {}
6
+
7
+ module.exports = IncomingPlugin
@@ -10,6 +10,7 @@ module.exports = {
10
10
  get '@jest/core' () { return require('../../../datadog-plugin-jest/src') },
11
11
  get '@koa/router' () { return require('../../../datadog-plugin-koa/src') },
12
12
  get '@node-redis/client' () { return require('../../../datadog-plugin-redis/src') },
13
+ get '@opensearch-project/opensearch' () { return require('../../../datadog-plugin-opensearch/src') },
13
14
  get '@redis/client' () { return require('../../../datadog-plugin-redis/src') },
14
15
  get 'amqp10' () { return require('../../../datadog-plugin-amqp10/src') },
15
16
  get 'amqplib' () { return require('../../../datadog-plugin-amqplib/src') },