dd-trace 4.18.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 (137) hide show
  1. package/LICENSE-3rdparty.csv +3 -2
  2. package/README.md +3 -3
  3. package/ext/kinds.d.ts +1 -0
  4. package/ext/kinds.js +2 -1
  5. package/ext/tags.d.ts +2 -1
  6. package/ext/tags.js +6 -1
  7. package/index.d.ts +29 -0
  8. package/package.json +12 -11
  9. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  10. package/packages/datadog-esbuild/index.js +1 -20
  11. package/packages/datadog-instrumentations/src/aerospike.js +47 -0
  12. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  13. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  14. package/packages/datadog-instrumentations/src/child-process.js +4 -5
  15. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  16. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  17. package/packages/datadog-instrumentations/src/dns.js +2 -1
  18. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  19. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  20. package/packages/datadog-instrumentations/src/helpers/hooks.js +10 -2
  21. package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
  22. package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
  23. package/packages/datadog-instrumentations/src/http/client.js +12 -2
  24. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  25. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  26. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  27. package/packages/datadog-instrumentations/src/jest.js +12 -6
  28. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  29. package/packages/datadog-instrumentations/src/net.js +10 -2
  30. package/packages/datadog-instrumentations/src/next.js +18 -6
  31. package/packages/datadog-instrumentations/src/restify.js +14 -1
  32. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  33. package/packages/datadog-plugin-aerospike/src/index.js +113 -0
  34. package/packages/datadog-plugin-cucumber/src/index.js +34 -2
  35. package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
  36. package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
  37. package/packages/datadog-plugin-http/src/client.js +19 -2
  38. package/packages/datadog-plugin-jest/src/index.js +38 -4
  39. package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
  40. package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
  41. package/packages/datadog-plugin-mocha/src/index.js +32 -1
  42. package/packages/datadog-plugin-next/src/index.js +40 -14
  43. package/packages/datadog-plugin-playwright/src/index.js +17 -1
  44. package/packages/dd-trace/src/appsec/activation.js +29 -0
  45. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  46. package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
  47. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  48. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  49. package/packages/dd-trace/src/appsec/channels.js +5 -2
  50. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  51. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  52. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
  53. package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
  54. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  55. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  56. package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
  57. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
  58. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
  59. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
  60. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
  61. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
  62. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
  63. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
  64. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
  65. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
  66. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  67. package/packages/dd-trace/src/appsec/index.js +33 -32
  68. package/packages/dd-trace/src/appsec/recommended.json +1737 -120
  69. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +6 -1
  70. package/packages/dd-trace/src/appsec/remote_config/index.js +40 -15
  71. package/packages/dd-trace/src/appsec/reporter.js +50 -34
  72. package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
  73. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  74. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
  75. package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
  76. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  77. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  78. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
  79. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +110 -59
  80. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +40 -7
  81. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
  82. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  83. package/packages/dd-trace/src/config.js +145 -63
  84. package/packages/dd-trace/src/datastreams/processor.js +166 -26
  85. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
  86. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  87. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  88. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  89. package/packages/dd-trace/src/format.js +6 -1
  90. package/packages/dd-trace/src/id.js +12 -0
  91. package/packages/dd-trace/src/iitm.js +1 -1
  92. package/packages/dd-trace/src/log/channels.js +1 -1
  93. package/packages/dd-trace/src/noop/proxy.js +4 -0
  94. package/packages/dd-trace/src/opentelemetry/span.js +95 -2
  95. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  96. package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
  97. package/packages/dd-trace/src/opentracing/span.js +6 -0
  98. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  99. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  100. package/packages/dd-trace/src/plugin_manager.js +1 -1
  101. package/packages/dd-trace/src/plugins/ci_plugin.js +46 -9
  102. package/packages/dd-trace/src/plugins/database.js +1 -1
  103. package/packages/dd-trace/src/plugins/index.js +6 -0
  104. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  105. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  106. package/packages/dd-trace/src/plugins/util/exec.js +23 -2
  107. package/packages/dd-trace/src/plugins/util/git.js +98 -22
  108. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  109. package/packages/dd-trace/src/plugins/util/test.js +3 -2
  110. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  111. package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
  112. package/packages/dd-trace/src/priority_sampler.js +30 -38
  113. package/packages/dd-trace/src/profiler.js +5 -3
  114. package/packages/dd-trace/src/profiling/config.js +26 -2
  115. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
  116. package/packages/dd-trace/src/profiling/profiler.js +17 -10
  117. package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
  118. package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
  119. package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
  120. package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
  121. package/packages/dd-trace/src/proxy.js +25 -1
  122. package/packages/dd-trace/src/ritm.js +1 -1
  123. package/packages/dd-trace/src/sampling_rule.js +130 -0
  124. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
  125. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  126. package/packages/dd-trace/src/span_processor.js +4 -0
  127. package/packages/dd-trace/src/span_sampler.js +6 -64
  128. package/packages/dd-trace/src/spanleak.js +98 -0
  129. package/packages/dd-trace/src/startup-log.js +7 -1
  130. package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
  131. package/packages/dd-trace/src/telemetry/index.js +171 -41
  132. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  133. package/packages/dd-trace/src/telemetry/send-data.js +47 -5
  134. package/packages/dd-trace/src/tracer.js +8 -2
  135. package/scripts/install_plugin_modules.js +11 -3
  136. package/packages/diagnostics_channel/index.js +0 -3
  137. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -3,8 +3,13 @@ const { truncateSpan, normalizeSpan } = require('./tags-processors')
3
3
  const { AgentEncoder } = require('./0.4')
4
4
  const { version: ddTraceVersion } = require('../../../../package.json')
5
5
  const id = require('../../../dd-trace/src/id')
6
- const ENCODING_VERSION = 1
6
+ const {
7
+ distributionMetric,
8
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
9
+ TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT
10
+ } = require('../ci-visibility/telemetry')
7
11
 
12
+ const ENCODING_VERSION = 1
8
13
  const ALLOWED_CONTENT_TYPES = ['test_session_end', 'test_module_end', 'test_suite_end', 'test']
9
14
 
10
15
  const TEST_SUITE_KEYS_LENGTH = 12
@@ -247,6 +252,8 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
247
252
  }
248
253
 
249
254
  _encode (bytes, trace) {
255
+ const startTime = Date.now()
256
+
250
257
  const rawEvents = trace.map(formatSpan)
251
258
 
252
259
  const testSessionEvents = rawEvents.filter(
@@ -261,9 +268,15 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
261
268
  for (const event of events) {
262
269
  this._encodeEvent(bytes, event)
263
270
  }
271
+ distributionMetric(
272
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
273
+ { endpoint: 'test_cycle' },
274
+ Date.now() - startTime
275
+ )
264
276
  }
265
277
 
266
278
  makePayload () {
279
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT, { endpoint: 'test_cycle' }, this._eventCount)
267
280
  const bytes = this._traceBytes
268
281
  const eventsOffset = this._eventsOffset
269
282
  const eventsCount = this._eventCount
@@ -2,6 +2,11 @@
2
2
  const { AgentEncoder } = require('./0.4')
3
3
  const Chunk = require('./chunk')
4
4
 
5
+ const {
6
+ distributionMetric,
7
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
8
+ TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT
9
+ } = require('../ci-visibility/telemetry')
5
10
  const FormData = require('../exporters/common/form-data')
6
11
 
7
12
  const COVERAGE_PAYLOAD_VERSION = 2
@@ -21,8 +26,16 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
21
26
  }
22
27
 
23
28
  encode (coverage) {
29
+ const startTime = Date.now()
30
+
24
31
  this._coveragesCount++
25
32
  this.encodeCodeCoverage(this._coverageBytes, coverage)
33
+
34
+ distributionMetric(
35
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
36
+ { endpoint: 'code_coverage' },
37
+ Date.now() - startTime
38
+ )
26
39
  }
27
40
 
28
41
  encodeCodeCoverage (bytes, coverage) {
@@ -73,6 +86,7 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
73
86
  }
74
87
 
75
88
  makePayload () {
89
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT, { endpoint: 'code_coverage' }, this._coveragesCount)
76
90
  const bytes = this._coverageBytes
77
91
 
78
92
  const coveragesOffset = this._coveragesOffset
@@ -1,6 +1,7 @@
1
1
  const { URL, format } = require('url')
2
2
 
3
3
  const request = require('./request')
4
+ const { incrementCountMetric, TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION } = require('../../ci-visibility/telemetry')
4
5
 
5
6
  function fetchAgentInfo (url, callback) {
6
7
  request('', {
@@ -49,6 +50,9 @@ class AgentInfoExporter {
49
50
  }
50
51
 
51
52
  _export (payload, writer = this._writer, timerKey = '_timer') {
53
+ if (this._config.isCiVisibility) {
54
+ incrementCountMetric(TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION, {}, payload.length)
55
+ }
52
56
  writer.append(payload)
53
57
 
54
58
  const { flushInterval } = this._config
@@ -21,6 +21,10 @@ class FormData extends Readable {
21
21
  }
22
22
  }
23
23
 
24
+ size () {
25
+ return this._data.reduce((size, chunk) => size + chunk.length, 0)
26
+ }
27
+
24
28
  getHeaders () {
25
29
  return { 'Content-Type': 'multipart/form-data; boundary=' + this._boundary }
26
30
  }
@@ -14,7 +14,7 @@ const SPAN_SAMPLING_MECHANISM = constants.SPAN_SAMPLING_MECHANISM
14
14
  const SPAN_SAMPLING_RULE_RATE = constants.SPAN_SAMPLING_RULE_RATE
15
15
  const SPAN_SAMPLING_MAX_PER_SECOND = constants.SPAN_SAMPLING_MAX_PER_SECOND
16
16
  const SAMPLING_MECHANISM_SPAN = constants.SAMPLING_MECHANISM_SPAN
17
- const { MEASURED, BASE_SERVICE } = tags
17
+ const { MEASURED, BASE_SERVICE, ANALYTICS } = tags
18
18
  const ORIGIN_KEY = constants.ORIGIN_KEY
19
19
  const HOSTNAME_KEY = constants.HOSTNAME_KEY
20
20
  const TOP_LEVEL_KEY = constants.TOP_LEVEL_KEY
@@ -24,6 +24,7 @@ const ERROR_STACK = constants.ERROR_STACK
24
24
  const ERROR_TYPE = constants.ERROR_TYPE
25
25
 
26
26
  const map = {
27
+ 'operation.name': 'name',
27
28
  'service.name': 'service',
28
29
  'span.type': 'type',
29
30
  'resource.name': 'resource'
@@ -83,6 +84,7 @@ function extractTags (trace, span) {
83
84
 
84
85
  for (const tag in tags) {
85
86
  switch (tag) {
87
+ case 'operation.name':
86
88
  case 'service.name':
87
89
  case 'span.type':
88
90
  case 'resource.name':
@@ -92,6 +94,9 @@ function extractTags (trace, span) {
92
94
  case 'http.status_code':
93
95
  addTag(trace.meta, {}, tag, tags[tag] && String(tags[tag]))
94
96
  break
97
+ case 'analytics.event':
98
+ addTag({}, trace.metrics, ANALYTICS, tags[tag] === undefined || tags[tag] ? 1 : 0)
99
+ break
95
100
  case HOSTNAME_KEY:
96
101
  case MEASURED:
97
102
  addTag({}, trace.metrics, tag, tags[tag] === undefined || tags[tag] ? 1 : 0)
@@ -42,6 +42,18 @@ class Identifier {
42
42
  toJSON () {
43
43
  return this.toString()
44
44
  }
45
+
46
+ equals (other) {
47
+ const length = this._buffer.length
48
+ const otherLength = other._buffer.length
49
+
50
+ // Only compare the bytes available in both IDs.
51
+ for (let i = length, j = otherLength; i >= 0 && j >= 0; i--, j--) {
52
+ if (this._buffer[i] !== other._buffer[j]) return false
53
+ }
54
+
55
+ return true
56
+ }
45
57
  }
46
58
 
47
59
  // Create a buffer, using an optional hexadecimal value if provided.
@@ -3,7 +3,7 @@
3
3
  const semver = require('semver')
4
4
  const logger = require('./log')
5
5
  const { addHook } = require('import-in-the-middle')
6
- const dc = require('../../diagnostics_channel')
6
+ const dc = require('dc-polyfill')
7
7
 
8
8
  if (semver.satisfies(process.versions.node, '>=14.13.1')) {
9
9
  const moduleLoadStartChannel = dc.channel('dd-trace:moduleLoadStart')
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
 
5
5
  const Level = {
6
6
  Debug: 'debug',
@@ -20,6 +20,10 @@ class Tracer {
20
20
  return this
21
21
  }
22
22
 
23
+ profilerStarted () {
24
+ return Promise.resolve(false)
25
+ }
26
+
23
27
  trace (name, options, fn) {
24
28
  if (!fn) {
25
29
  fn = options
@@ -11,6 +11,7 @@ const tracer = require('../../')
11
11
  const DatadogSpan = require('../opentracing/span')
12
12
  const { ERROR_MESSAGE, ERROR_TYPE, ERROR_STACK } = require('../constants')
13
13
  const { SERVICE_NAME, RESOURCE_NAME } = require('../../../../ext/tags')
14
+ const kinds = require('../../../../ext/kinds')
14
15
 
15
16
  const SpanContext = require('./span_context')
16
17
 
@@ -19,6 +20,93 @@ function hrTimeToMilliseconds (time) {
19
20
  return time[0] * 1e3 + time[1] / 1e6
20
21
  }
21
22
 
23
+ const spanKindNames = {
24
+ [api.SpanKind.INTERNAL]: kinds.INTERNAL,
25
+ [api.SpanKind.SERVER]: kinds.SERVER,
26
+ [api.SpanKind.CLIENT]: kinds.CLIENT,
27
+ [api.SpanKind.PRODUCER]: kinds.PRODUCER,
28
+ [api.SpanKind.CONSUMER]: kinds.CONSUMER
29
+ }
30
+
31
+ /**
32
+ * Several of these attributes are not yet supported by the Node.js OTel API.
33
+ * We check for old equivalents where we can, but not all had equivalents.
34
+ */
35
+ function spanNameMapper (spanName, kind, attributes) {
36
+ if (spanName) return spanName
37
+
38
+ const opName = attributes['operation.name']
39
+ if (opName) return opName
40
+
41
+ const { INTERNAL, SERVER, CLIENT } = api.SpanKind
42
+
43
+ // HTTP server and client requests
44
+ // TODO: Drop http.method when http.request.method is supported.
45
+ for (const key of ['http.method', 'http.request.method']) {
46
+ if (key in attributes) {
47
+ if (kind === SERVER) {
48
+ return 'http.server.request'
49
+ }
50
+ if (kind === CLIENT) {
51
+ return 'http.client.request'
52
+ }
53
+ }
54
+ }
55
+
56
+ // Databases
57
+ const dbSystem = attributes['db.system']
58
+ if (dbSystem && kind === CLIENT) {
59
+ return `${dbSystem}.query`
60
+ }
61
+
62
+ // Messaging
63
+ const msgSys = attributes['messaging.system']
64
+ const msgOp = attributes['messaging.operation']
65
+ if (msgSys && msgOp && kind !== INTERNAL) {
66
+ return `${msgSys}.${msgOp}`
67
+ }
68
+
69
+ // RPC (and AWS)
70
+ const rpcSystem = attributes['rpc.system']
71
+ if (rpcSystem) {
72
+ if (kind === CLIENT) {
73
+ return rpcSystem === 'aws-api'
74
+ ? `aws.${attributes['rpc.service'] || 'client'}.request`
75
+ : `${rpcSystem}.client.request`
76
+ }
77
+ if (kind === SERVER) {
78
+ return `${rpcSystem}.server.request`
79
+ }
80
+ }
81
+
82
+ // FaaS
83
+ const faasProvider = attributes['faas.invoked_provider']
84
+ const faasName = attributes['faas.invoked_name']
85
+ const faasTrigger = attributes['faas.trigger']
86
+ if (kind === CLIENT && faasProvider && faasName) {
87
+ return `${faasProvider}.${faasName}.invoke`
88
+ }
89
+ if (kind === SERVER && faasTrigger) {
90
+ return `${faasTrigger}.invoke`
91
+ }
92
+
93
+ // GraphQL
94
+ // NOTE: Not part of Semantic Convention spec yet, but is used in the GraphQL
95
+ // integration.
96
+ const isGraphQL = 'graphql.operation.type' in attributes
97
+ if (isGraphQL) return 'graphql.server.request'
98
+
99
+ // Network
100
+ // TODO: Doesn't exist yet. No equivalent.
101
+ const protocol = attributes['network.protocol.name']
102
+ const protocolPrefix = protocol ? `${protocol}.` : ''
103
+ if (kind === SERVER) return `${protocolPrefix}server.request`
104
+ if (kind === CLIENT) return `${protocolPrefix}client.request`
105
+
106
+ // If all else fails, default to stringified span.kind.
107
+ return spanKindNames[kind]
108
+ }
109
+
22
110
  class Span {
23
111
  constructor (
24
112
  parentTracer,
@@ -27,7 +115,8 @@ class Span {
27
115
  spanContext,
28
116
  kind,
29
117
  links = [],
30
- timeInput
118
+ timeInput,
119
+ attributes
31
120
  ) {
32
121
  const { _tracer } = tracer
33
122
 
@@ -35,7 +124,7 @@ class Span {
35
124
  const startTime = hrTimeToMilliseconds(hrStartTime)
36
125
 
37
126
  this._ddSpan = new DatadogSpan(_tracer, _tracer._processor, _tracer._prioritySampler, {
38
- operationName: spanName,
127
+ operationName: spanNameMapper(spanName, kind, attributes),
39
128
  context: spanContext._ddContext,
40
129
  startTime,
41
130
  hostname: _tracer._hostname,
@@ -46,6 +135,10 @@ class Span {
46
135
  }
47
136
  }, _tracer._debug)
48
137
 
138
+ if (attributes) {
139
+ this.setAttributes(attributes)
140
+ }
141
+
49
142
  this._parentTracer = parentTracer
50
143
  this._context = context
51
144
 
@@ -78,23 +78,22 @@ class Tracer {
78
78
  // return api.trace.wrapSpanContext(spanContext)
79
79
  // }
80
80
 
81
- const span = new Span(
81
+ return new Span(
82
82
  this,
83
83
  context,
84
84
  name,
85
85
  spanContext,
86
86
  spanKind,
87
87
  links,
88
- options.startTime
88
+ options.startTime,
89
+
90
+ // Set initial span attributes. The attributes object may have been mutated
91
+ // by the sampler, so we sanitize the merged attributes before setting them.
92
+ sanitizeAttributes(
93
+ // Object.assign(attributes, samplingResult.attributes)
94
+ attributes
95
+ )
89
96
  )
90
- // Set initial span attributes. The attributes object may have been mutated
91
- // by the sampler, so we sanitize the merged attributes before setting them.
92
- const initAttributes = sanitizeAttributes(
93
- // Object.assign(attributes, samplingResult.attributes)
94
- attributes
95
- )
96
- span.setAttributes(initAttributes)
97
- return span
98
97
  }
99
98
 
100
99
  startActiveSpan (name, options, context, fn) {
@@ -236,11 +236,20 @@ class TextMapPropagator {
236
236
  _extractDatadogContext (carrier) {
237
237
  const spanContext = this._extractGenericContext(carrier, traceKey, spanKey, 10)
238
238
 
239
- if (spanContext) {
240
- this._extractOrigin(carrier, spanContext)
241
- this._extractBaggageItems(carrier, spanContext)
242
- this._extractSamplingPriority(carrier, spanContext)
243
- this._extractTags(carrier, spanContext)
239
+ if (!spanContext) return spanContext
240
+
241
+ this._extractOrigin(carrier, spanContext)
242
+ this._extractBaggageItems(carrier, spanContext)
243
+ this._extractSamplingPriority(carrier, spanContext)
244
+ this._extractTags(carrier, spanContext)
245
+
246
+ if (this._config.tracePropagationExtractFirst) return spanContext
247
+
248
+ const tc = this._extractTraceparentContext(carrier)
249
+
250
+ if (tc && spanContext._traceId.equals(tc._traceId)) {
251
+ spanContext._traceparent = tc._traceparent
252
+ spanContext._tracestate = tc._tracestate
244
253
  }
245
254
 
246
255
  return spanContext
@@ -12,6 +12,8 @@ const runtimeMetrics = require('../runtime_metrics')
12
12
  const log = require('../log')
13
13
  const { storage } = require('../../../datadog-core')
14
14
  const telemetryMetrics = require('../telemetry/metrics')
15
+ const { channel } = require('dc-polyfill')
16
+ const spanleak = require('../spanleak')
15
17
 
16
18
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
17
19
 
@@ -30,6 +32,8 @@ const integrationCounters = {
30
32
  span_finished: {}
31
33
  }
32
34
 
35
+ const finishCh = channel('dd-trace:span:finish')
36
+
33
37
  function getIntegrationCounter (event, integration) {
34
38
  const counters = integrationCounters[event]
35
39
 
@@ -87,6 +91,7 @@ class DatadogSpan {
87
91
 
88
92
  unfinishedRegistry.register(this, operationName, this)
89
93
  }
94
+ spanleak.addSpan(this, operationName)
90
95
  }
91
96
 
92
97
  toString () {
@@ -176,6 +181,7 @@ class DatadogSpan {
176
181
  this._duration = finishTime - this._startTime
177
182
  this._spanContext._trace.finished.push(this)
178
183
  this._spanContext._isFinished = true
184
+ finishCh.publish(this)
179
185
  this._processor.process(this)
180
186
  }
181
187
 
@@ -2,6 +2,9 @@
2
2
 
3
3
  const { AUTO_KEEP } = require('../../../../ext/priority')
4
4
 
5
+ // the lowercase, hex encoded upper 64 bits of a 128-bit trace id, if present
6
+ const TRACE_ID_128 = '_dd.p.tid'
7
+
5
8
  class DatadogSpanContext {
6
9
  constructor (props) {
7
10
  props = props || {}
@@ -35,8 +38,8 @@ class DatadogSpanContext {
35
38
 
36
39
  toTraceparent () {
37
40
  const flags = this._sampling.priority >= AUTO_KEEP ? '01' : '00'
38
- const traceId = this._traceId.toBuffer().length <= 8 && this._trace.tags['_dd.p.tid']
39
- ? this._trace.tags['_dd.p.tid'] + this._traceId.toString(16).padStart(16, '0')
41
+ const traceId = this._traceId.toBuffer().length <= 8 && this._trace.tags[TRACE_ID_128]
42
+ ? this._trace.tags[TRACE_ID_128] + this._traceId.toString(16).padStart(16, '0')
40
43
  : this._traceId.toString(16).padStart(32, '0')
41
44
  const spanId = this._spanId.toString(16).padStart(16, '0')
42
45
  const version = (this._traceparent && this._traceparent.version) || '00'
@@ -22,10 +22,10 @@ class DatadogTracer {
22
22
  constructor (config) {
23
23
  const Exporter = getExporter(config.experimental.exporter)
24
24
 
25
+ this._config = config
25
26
  this._service = config.service
26
27
  this._version = config.version
27
28
  this._env = config.env
28
- this._tags = config.tags
29
29
  this._logInjection = config.logInjection
30
30
  this._debug = config.debug
31
31
  this._prioritySampler = new PrioritySampler(config.env, config.sampler)
@@ -64,7 +64,7 @@ class DatadogTracer {
64
64
  integrationName: options.integrationName
65
65
  }, this._debug)
66
66
 
67
- span.addTags(this._tags)
67
+ span.addTags(this._config.tags)
68
68
  span.addTags(options.tags)
69
69
 
70
70
  return span
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { channel } = require('../../diagnostics_channel')
3
+ const { channel } = require('dc-polyfill')
4
4
  const { isFalse } = require('./util')
5
5
  const plugins = require('./plugins')
6
6
  const log = require('./log')
@@ -20,6 +20,14 @@ const {
20
20
  const Plugin = require('./plugin')
21
21
  const { COMPONENT } = require('../constants')
22
22
  const log = require('../log')
23
+ const {
24
+ incrementCountMetric,
25
+ distributionMetric,
26
+ TELEMETRY_EVENT_CREATED,
27
+ TELEMETRY_ITR_SKIPPED
28
+ } = require('../ci-visibility/telemetry')
29
+ const { CI_PROVIDER_NAME, GIT_REPOSITORY_URL, GIT_COMMIT_SHA, GIT_BRANCH } = require('./util/tags')
30
+ const { OS_VERSION, OS_PLATFORM, OS_ARCHITECTURE, RUNTIME_NAME, RUNTIME_VERSION } = require('./util/env')
23
31
 
24
32
  module.exports = class CiPlugin extends Plugin {
25
33
  constructor (...args) {
@@ -71,6 +79,7 @@ module.exports = class CiPlugin extends Plugin {
71
79
  ...testSessionSpanMetadata
72
80
  }
73
81
  })
82
+ this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'session')
74
83
  this.testModuleSpan = this.tracer.startSpan(`${this.constructor.id}.test_module`, {
75
84
  childOf: this.testSessionSpan,
76
85
  tags: {
@@ -79,6 +88,7 @@ module.exports = class CiPlugin extends Plugin {
79
88
  ...testModuleSpanMetadata
80
89
  }
81
90
  })
91
+ this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'module')
82
92
  })
83
93
 
84
94
  this.addSub(`ci:${this.constructor.id}:itr:skipped-suites`, ({ skippedSuites, frameworkVersion }) => {
@@ -97,25 +107,49 @@ module.exports = class CiPlugin extends Plugin {
97
107
  }
98
108
  }).finish()
99
109
  })
110
+ this.telemetry.count(TELEMETRY_ITR_SKIPPED, { testLevel: 'suite' }, skippedSuites.length)
100
111
  })
101
112
  }
102
113
 
114
+ get telemetry () {
115
+ const testFramework = this.constructor.id
116
+ return {
117
+ ciVisEvent: function (name, testLevel, tags = {}) {
118
+ incrementCountMetric(name, {
119
+ testLevel,
120
+ testFramework,
121
+ isUnsupportedCIProvider: this.isUnsupportedCIProvider,
122
+ ...tags
123
+ })
124
+ },
125
+ count: function (name, tags, value = 1) {
126
+ incrementCountMetric(name, tags, value)
127
+ },
128
+ distribution: function (name, tags, measure) {
129
+ distributionMetric(name, tags, measure)
130
+ }
131
+ }
132
+ }
133
+
103
134
  configure (config) {
104
135
  super.configure(config)
105
136
  this.testEnvironmentMetadata = getTestEnvironmentMetadata(this.constructor.id, this.config)
106
137
  this.codeOwnersEntries = getCodeOwnersFileEntries()
107
138
 
108
139
  const {
109
- 'git.repository_url': repositoryUrl,
110
- 'git.commit.sha': sha,
111
- 'os.version': osVersion,
112
- 'os.platform': osPlatform,
113
- 'os.architecture': osArchitecture,
114
- 'runtime.name': runtimeName,
115
- 'runtime.version': runtimeVersion,
116
- 'git.branch': branch
140
+ [GIT_REPOSITORY_URL]: repositoryUrl,
141
+ [GIT_COMMIT_SHA]: sha,
142
+ [OS_VERSION]: osVersion,
143
+ [OS_PLATFORM]: osPlatform,
144
+ [OS_ARCHITECTURE]: osArchitecture,
145
+ [RUNTIME_NAME]: runtimeName,
146
+ [RUNTIME_VERSION]: runtimeVersion,
147
+ [GIT_BRANCH]: branch,
148
+ [CI_PROVIDER_NAME]: ciProviderName
117
149
  } = this.testEnvironmentMetadata
118
150
 
151
+ this.isUnsupportedCIProvider = !ciProviderName
152
+
119
153
  this.testConfiguration = {
120
154
  repositoryUrl,
121
155
  sha,
@@ -124,7 +158,8 @@ module.exports = class CiPlugin extends Plugin {
124
158
  osArchitecture,
125
159
  runtimeName,
126
160
  runtimeVersion,
127
- branch
161
+ branch,
162
+ testLevel: 'suite'
128
163
  }
129
164
  }
130
165
 
@@ -169,6 +204,8 @@ module.exports = class CiPlugin extends Plugin {
169
204
  }
170
205
  }
171
206
 
207
+ this.telemetry.ciVisEvent(TELEMETRY_EVENT_CREATED, 'test', { hasCodeOwners: !!codeOwners })
208
+
172
209
  const testSpan = this.tracer
173
210
  .startSpan(`${this.constructor.id}.test`, {
174
211
  childOf,
@@ -36,7 +36,7 @@ class DatabasePlugin extends StoragePlugin {
36
36
  const { encodedDddbs, encodedDde, encodedDdps, encodedDdpv } = this.serviceTags
37
37
 
38
38
  return `dddbs='${encodedDddbs}',dde='${encodedDde}',` +
39
- `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
39
+ `ddps='${encodedDdps}',ddpv='${encodedDdpv}'`
40
40
  }
41
41
 
42
42
  getDbmServiceName (span, tracerService) {
@@ -17,6 +17,7 @@ module.exports = {
17
17
  get '@opensearch-project/opensearch' () { return require('../../../datadog-plugin-opensearch/src') },
18
18
  get '@redis/client' () { return require('../../../datadog-plugin-redis/src') },
19
19
  get '@smithy/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
20
+ get 'aerospike' () { return require('../../../datadog-plugin-aerospike/src') },
20
21
  get 'amqp10' () { return require('../../../datadog-plugin-amqp10/src') },
21
22
  get 'amqplib' () { return require('../../../datadog-plugin-amqplib/src') },
22
23
  get 'aws-sdk' () { return require('../../../datadog-plugin-aws-sdk/src') },
@@ -58,6 +59,11 @@ module.exports = {
58
59
  get 'mysql2' () { return require('../../../datadog-plugin-mysql2/src') },
59
60
  get 'net' () { return require('../../../datadog-plugin-net/src') },
60
61
  get 'next' () { return require('../../../datadog-plugin-next/src') },
62
+ get 'node:dns' () { return require('../../../datadog-plugin-dns/src') },
63
+ get 'node:http' () { return require('../../../datadog-plugin-http/src') },
64
+ get 'node:http2' () { return require('../../../datadog-plugin-http2/src') },
65
+ get 'node:https' () { return require('../../../datadog-plugin-http/src') },
66
+ get 'node:net' () { return require('../../../datadog-plugin-net/src') },
61
67
  get 'oracledb' () { return require('../../../datadog-plugin-oracledb/src') },
62
68
  get 'openai' () { return require('../../../datadog-plugin-openai/src') },
63
69
  get 'paperplane' () { return require('../../../datadog-plugin-paperplane/src') },
@@ -2,7 +2,7 @@
2
2
 
3
3
  // TODO: move anything related to tracing to TracingPlugin instead
4
4
 
5
- const dc = require('../../../diagnostics_channel')
5
+ const dc = require('dc-polyfill')
6
6
  const { storage } = require('../../../datadog-core')
7
7
 
8
8
  class Subscription {
@@ -1,5 +1,3 @@
1
- const URL = require('url').URL
2
-
3
1
  const {
4
2
  GIT_BRANCH,
5
3
  GIT_COMMIT_SHA,
@@ -24,6 +22,7 @@ const {
24
22
  CI_NODE_LABELS,
25
23
  CI_NODE_NAME
26
24
  } = require('./tags')
25
+ const { filterSensitiveInfoFromRepository } = require('./url')
27
26
 
28
27
  // Receives a string with the form 'John Doe <john.doe@gmail.com>'
29
28
  // and returns { name: 'John Doe', email: 'john.doe@gmail.com' }
@@ -67,20 +66,6 @@ function normalizeRef (ref) {
67
66
  return ref.replace(/origin\/|refs\/heads\/|tags\//gm, '')
68
67
  }
69
68
 
70
- function filterSensitiveInfoFromRepository (repositoryUrl) {
71
- if (repositoryUrl.startsWith('git@')) {
72
- return repositoryUrl
73
- }
74
-
75
- try {
76
- const { protocol, hostname, pathname } = new URL(repositoryUrl)
77
-
78
- return `${protocol}//${hostname}${pathname}`
79
- } catch (e) {
80
- return ''
81
- }
82
- }
83
-
84
69
  function resolveTilde (filePath) {
85
70
  if (!filePath || typeof filePath !== 'string') {
86
71
  return ''
@@ -271,20 +256,22 @@ module.exports = {
271
256
  const ref = GITHUB_HEAD_REF || GITHUB_REF || ''
272
257
  const refKey = ref.includes('tags/') ? GIT_TAG : GIT_BRANCH
273
258
 
259
+ // Both pipeline URL and job URL include GITHUB_SERVER_URL, which can include user credentials,
260
+ // so we pass them through `filterSensitiveInfoFromRepository`.
274
261
  tags = {
275
262
  [CI_PIPELINE_ID]: GITHUB_RUN_ID,
276
263
  [CI_PIPELINE_NAME]: GITHUB_WORKFLOW,
277
264
  [CI_PIPELINE_NUMBER]: GITHUB_RUN_NUMBER,
278
- [CI_PIPELINE_URL]: pipelineURL,
265
+ [CI_PIPELINE_URL]: filterSensitiveInfoFromRepository(pipelineURL),
279
266
  [CI_PROVIDER_NAME]: 'github',
280
267
  [GIT_COMMIT_SHA]: GITHUB_SHA,
281
268
  [GIT_REPOSITORY_URL]: repositoryURL,
282
- [CI_JOB_URL]: jobUrl,
269
+ [CI_JOB_URL]: filterSensitiveInfoFromRepository(jobUrl),
283
270
  [CI_JOB_NAME]: GITHUB_JOB,
284
271
  [CI_WORKSPACE_PATH]: GITHUB_WORKSPACE,
285
272
  [refKey]: ref,
286
273
  [CI_ENV_VARS]: JSON.stringify({
287
- GITHUB_SERVER_URL,
274
+ GITHUB_SERVER_URL: filterSensitiveInfoFromRepository(GITHUB_SERVER_URL),
288
275
  GITHUB_REPOSITORY,
289
276
  GITHUB_RUN_ID,
290
277
  GITHUB_RUN_ATTEMPT