dd-trace 4.21.0 → 4.23.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 (68) hide show
  1. package/index.d.ts +5 -0
  2. package/package.json +6 -6
  3. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  4. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  5. package/packages/datadog-instrumentations/src/child-process.js +4 -5
  6. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  7. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  8. package/packages/datadog-instrumentations/src/dns.js +2 -1
  9. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  10. package/packages/datadog-instrumentations/src/helpers/hooks.js +9 -2
  11. package/packages/datadog-instrumentations/src/helpers/instrument.js +8 -3
  12. package/packages/datadog-instrumentations/src/helpers/register.js +18 -2
  13. package/packages/datadog-instrumentations/src/http/client.js +4 -16
  14. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  15. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  16. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  17. package/packages/datadog-instrumentations/src/jest.js +1 -1
  18. package/packages/datadog-instrumentations/src/net.js +10 -2
  19. package/packages/datadog-instrumentations/src/next.js +15 -5
  20. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  21. package/packages/datadog-plugin-cucumber/src/index.js +34 -2
  22. package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
  23. package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
  24. package/packages/datadog-plugin-http/src/client.js +1 -1
  25. package/packages/datadog-plugin-jest/src/index.js +38 -4
  26. package/packages/datadog-plugin-mocha/src/index.js +32 -1
  27. package/packages/datadog-plugin-next/src/index.js +32 -6
  28. package/packages/datadog-plugin-playwright/src/index.js +17 -1
  29. package/packages/dd-trace/src/appsec/activation.js +29 -0
  30. package/packages/dd-trace/src/appsec/addresses.js +1 -0
  31. package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
  32. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  33. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  34. package/packages/dd-trace/src/appsec/channels.js +4 -1
  35. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  36. package/packages/dd-trace/src/appsec/index.js +29 -40
  37. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +6 -1
  38. package/packages/dd-trace/src/appsec/remote_config/index.js +40 -15
  39. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  40. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +25 -13
  41. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  42. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  43. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +36 -4
  44. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +18 -1
  45. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
  46. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  47. package/packages/dd-trace/src/config.js +104 -58
  48. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
  49. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  50. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  51. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  52. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  53. package/packages/dd-trace/src/plugins/ci_plugin.js +44 -8
  54. package/packages/dd-trace/src/plugins/index.js +5 -0
  55. package/packages/dd-trace/src/plugins/util/exec.js +23 -2
  56. package/packages/dd-trace/src/plugins/util/git.js +94 -19
  57. package/packages/dd-trace/src/plugins/util/user-provided-git.js +3 -2
  58. package/packages/dd-trace/src/priority_sampler.js +30 -38
  59. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
  60. package/packages/dd-trace/src/profiling/profiler.js +7 -6
  61. package/packages/dd-trace/src/profiling/profilers/events.js +18 -13
  62. package/packages/dd-trace/src/profiling/profilers/shared.js +34 -4
  63. package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
  64. package/packages/dd-trace/src/profiling/profilers/wall.js +17 -12
  65. package/packages/dd-trace/src/proxy.js +4 -0
  66. package/packages/dd-trace/src/sampling_rule.js +130 -0
  67. package/packages/dd-trace/src/span_sampler.js +6 -64
  68. package/packages/dd-trace/src/telemetry/index.js +43 -5
@@ -0,0 +1,130 @@
1
+ 'use strict'
2
+
3
+ const { globMatch } = require('../src/util')
4
+ const RateLimiter = require('./rate_limiter')
5
+ const Sampler = require('./sampler')
6
+
7
+ class AlwaysMatcher {
8
+ match () {
9
+ return true
10
+ }
11
+ }
12
+
13
+ class GlobMatcher {
14
+ constructor (pattern, locator) {
15
+ this.pattern = pattern
16
+ this.locator = locator
17
+ }
18
+
19
+ match (span) {
20
+ const subject = this.locator(span)
21
+ if (!subject) return false
22
+ return globMatch(this.pattern, subject)
23
+ }
24
+ }
25
+
26
+ class RegExpMatcher {
27
+ constructor (pattern, locator) {
28
+ this.pattern = pattern
29
+ this.locator = locator
30
+ }
31
+
32
+ match (span) {
33
+ const subject = this.locator(span)
34
+ if (!subject) return false
35
+ return this.pattern.test(subject)
36
+ }
37
+ }
38
+
39
+ function matcher (pattern, locator) {
40
+ if (pattern instanceof RegExp) {
41
+ return new RegExpMatcher(pattern, locator)
42
+ }
43
+
44
+ if (typeof pattern === 'string' && pattern !== '*') {
45
+ return new GlobMatcher(pattern, locator)
46
+ }
47
+
48
+ return new AlwaysMatcher()
49
+ }
50
+
51
+ function makeTagLocator (tag) {
52
+ return (span) => span.context()._tags[tag]
53
+ }
54
+
55
+ function nameLocator (span) {
56
+ return span.context()._name
57
+ }
58
+
59
+ function serviceLocator (span) {
60
+ const { _tags: tags } = span.context()
61
+ return tags.service ||
62
+ tags['service.name'] ||
63
+ span.tracer()._service
64
+ }
65
+
66
+ class SamplingRule {
67
+ constructor ({ name, service, resource, tags, sampleRate = 1.0, maxPerSecond } = {}) {
68
+ this.matchers = []
69
+
70
+ if (name) {
71
+ this.matchers.push(matcher(name, nameLocator))
72
+ }
73
+ if (service) {
74
+ this.matchers.push(matcher(service, serviceLocator))
75
+ }
76
+ if (resource) {
77
+ this.matchers.push(matcher(resource, makeTagLocator('resource.name')))
78
+ }
79
+ for (const [key, value] of Object.entries(tags || {})) {
80
+ this.matchers.push(matcher(value, makeTagLocator(key)))
81
+ }
82
+
83
+ this._sampler = new Sampler(sampleRate)
84
+ this._limiter = undefined
85
+
86
+ if (Number.isFinite(maxPerSecond)) {
87
+ this._limiter = new RateLimiter(maxPerSecond)
88
+ }
89
+ }
90
+
91
+ static from (config) {
92
+ return new SamplingRule(config)
93
+ }
94
+
95
+ get sampleRate () {
96
+ return this._sampler.rate()
97
+ }
98
+
99
+ get effectiveRate () {
100
+ return this._limiter && this._limiter.effectiveRate()
101
+ }
102
+
103
+ get maxPerSecond () {
104
+ return this._limiter && this._limiter._rateLimit
105
+ }
106
+
107
+ match (span) {
108
+ for (const matcher of this.matchers) {
109
+ if (!matcher.match(span)) {
110
+ return false
111
+ }
112
+ }
113
+
114
+ return true
115
+ }
116
+
117
+ sample () {
118
+ if (!this._sampler.isSampled()) {
119
+ return false
120
+ }
121
+
122
+ if (this._limiter) {
123
+ return this._limiter.isAllowed()
124
+ }
125
+
126
+ return true
127
+ }
128
+ }
129
+
130
+ module.exports = SamplingRule
@@ -1,67 +1,16 @@
1
1
  'use strict'
2
- const { globMatch } = require('../src/util')
3
- const { USER_KEEP, AUTO_KEEP } = require('../../../ext').priority
4
- const RateLimiter = require('./rate_limiter')
5
- const Sampler = require('./sampler')
6
-
7
- class SpanSamplingRule {
8
- constructor ({ service, name, sampleRate = 1.0, maxPerSecond } = {}) {
9
- this.service = service
10
- this.name = name
11
-
12
- this._sampler = new Sampler(sampleRate)
13
- this._limiter = undefined
14
-
15
- if (Number.isFinite(maxPerSecond)) {
16
- this._limiter = new RateLimiter(maxPerSecond)
17
- }
18
- }
19
-
20
- get sampleRate () {
21
- return this._sampler.rate()
22
- }
23
-
24
- get maxPerSecond () {
25
- return this._limiter && this._limiter._rateLimit
26
- }
27
-
28
- static from (config) {
29
- return new SpanSamplingRule(config)
30
- }
31
-
32
- match (service, name) {
33
- if (this.service && !globMatch(this.service, service)) {
34
- return false
35
- }
36
-
37
- if (this.name && !globMatch(this.name, name)) {
38
- return false
39
- }
40
-
41
- return true
42
- }
43
-
44
- sample () {
45
- if (!this._sampler.isSampled()) {
46
- return false
47
- }
48
2
 
49
- if (this._limiter) {
50
- return this._limiter.isAllowed()
51
- }
52
-
53
- return true
54
- }
55
- }
3
+ const { USER_KEEP, AUTO_KEEP } = require('../../../ext').priority
4
+ const SamplingRule = require('./sampling_rule')
56
5
 
57
6
  class SpanSampler {
58
7
  constructor ({ spanSamplingRules = [] } = {}) {
59
- this._rules = spanSamplingRules.map(SpanSamplingRule.from)
8
+ this._rules = spanSamplingRules.map(SamplingRule.from)
60
9
  }
61
10
 
62
- findRule (service, name) {
11
+ findRule (context) {
63
12
  for (const rule of this._rules) {
64
- if (rule.match(service, name)) {
13
+ if (rule.match(context)) {
65
14
  return rule
66
15
  }
67
16
  }
@@ -73,14 +22,7 @@ class SpanSampler {
73
22
 
74
23
  const { started } = spanContext._trace
75
24
  for (const span of started) {
76
- const context = span.context()
77
- const tags = context._tags || {}
78
- const name = context._name
79
- const service = tags.service ||
80
- tags['service.name'] ||
81
- span.tracer()._service
82
-
83
- const rule = this.findRule(service, name)
25
+ const rule = this.findRule(span)
84
26
  if (rule && rule.sample()) {
85
27
  span.context()._spanSampling = {
86
28
  sampleRate: rule.sampleRate,
@@ -112,11 +112,26 @@ function flatten (input, result = [], prefix = [], traversedObjects = null) {
112
112
  return result
113
113
  }
114
114
 
115
+ function getInstallSignature (config) {
116
+ const { installSignature: sig } = config
117
+ if (sig && (sig.id || sig.time || sig.type)) {
118
+ return {
119
+ install_id: sig.id,
120
+ install_time: sig.time,
121
+ install_type: sig.type
122
+ }
123
+ }
124
+ }
125
+
115
126
  function appStarted (config) {
116
127
  const app = {
117
128
  products: getProducts(config),
118
129
  configuration: flatten(config)
119
130
  }
131
+ const installSignature = getInstallSignature(config)
132
+ if (installSignature) {
133
+ app.install_signature = installSignature
134
+ }
120
135
  // TODO: add app.error with correct error codes
121
136
  // if (errors.agentError) {
122
137
  // app.error = errors.agentError
@@ -129,6 +144,10 @@ function onBeforeExit () {
129
144
  process.removeListener('beforeExit', onBeforeExit)
130
145
  const { reqType, payload } = createPayload('app-closing')
131
146
  sendData(config, application, host, reqType, payload)
147
+ // we flush before shutting down. Only in CI Visibility
148
+ if (config.isCiVisibility) {
149
+ metricsManager.send(config, application, host)
150
+ }
132
151
  }
133
152
 
134
153
  function createAppObject (config) {
@@ -286,11 +305,30 @@ function updateConfig (changes, config) {
286
305
  const application = createAppObject(config)
287
306
  const host = createHostObject()
288
307
 
289
- const configuration = changes.map(change => ({
290
- name: change.name,
291
- value: Array.isArray(change.value) ? change.value.join(',') : change.value,
292
- origin: change.origin
293
- }))
308
+ const names = {
309
+ sampleRate: 'DD_TRACE_SAMPLE_RATE',
310
+ logInjection: 'DD_LOG_INJECTION',
311
+ headerTags: 'DD_TRACE_HEADER_TAGS',
312
+ tags: 'DD_TAGS'
313
+ }
314
+
315
+ const configuration = []
316
+
317
+ for (const change of changes) {
318
+ if (!names.hasOwnProperty(change.name)) continue
319
+
320
+ const name = names[change.name]
321
+ const { origin, value } = change
322
+ const entry = { name, origin, value }
323
+
324
+ if (Array.isArray(value)) {
325
+ entry.value = value.join(',')
326
+ } else if (name === 'DD_TAGS') {
327
+ entry.value = Object.entries(value).map(([key, value]) => `${key}:${value}`)
328
+ }
329
+
330
+ configuration.push(entry)
331
+ }
294
332
 
295
333
  const { reqType, payload } = createPayload('app-client-configuration-change', { configuration })
296
334