dd-trace 3.19.0 → 3.20.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 (35) hide show
  1. package/package.json +1 -1
  2. package/packages/datadog-instrumentations/src/mocha.js +8 -4
  3. package/packages/datadog-instrumentations/src/pg.js +3 -4
  4. package/packages/datadog-instrumentations/src/playwright.js +11 -1
  5. package/packages/datadog-plugin-amqp10/src/consumer.js +3 -1
  6. package/packages/datadog-plugin-amqp10/src/producer.js +3 -1
  7. package/packages/datadog-plugin-amqplib/src/client.js +3 -4
  8. package/packages/datadog-plugin-amqplib/src/consumer.js +3 -1
  9. package/packages/datadog-plugin-amqplib/src/producer.js +3 -1
  10. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +3 -4
  11. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +3 -1
  12. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +3 -1
  13. package/packages/datadog-plugin-kafkajs/src/consumer.js +6 -1
  14. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -1
  15. package/packages/datadog-plugin-pg/src/index.js +5 -5
  16. package/packages/datadog-plugin-rhea/src/consumer.js +3 -1
  17. package/packages/datadog-plugin-rhea/src/producer.js +5 -1
  18. package/packages/dd-trace/src/config.js +1 -17
  19. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -4
  20. package/packages/dd-trace/src/plugin_manager.js +0 -2
  21. package/packages/dd-trace/src/plugins/client.js +2 -3
  22. package/packages/dd-trace/src/plugins/consumer.js +2 -17
  23. package/packages/dd-trace/src/plugins/incoming.js +7 -0
  24. package/packages/dd-trace/src/plugins/{outbound.js → outgoing.js} +2 -2
  25. package/packages/dd-trace/src/plugins/producer.js +2 -17
  26. package/packages/dd-trace/src/plugins/server.js +2 -2
  27. package/packages/dd-trace/src/plugins/tracing.js +0 -11
  28. package/packages/dd-trace/src/plugins/util/test.js +34 -17
  29. package/packages/dd-trace/src/telemetry/send-data.js +13 -3
  30. package/packages/dd-trace/src/plugins/inbound.js +0 -7
  31. package/packages/dd-trace/src/service-naming/index.js +0 -41
  32. package/packages/dd-trace/src/service-naming/schemas/definition.js +0 -28
  33. package/packages/dd-trace/src/service-naming/schemas/index.js +0 -6
  34. package/packages/dd-trace/src/service-naming/schemas/v0.js +0 -66
  35. package/packages/dd-trace/src/service-naming/schemas/v1.js +0 -58
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "3.19.0",
3
+ "version": "3.20.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -10,7 +10,7 @@ const {
10
10
  mergeCoverage,
11
11
  getTestSuitePath,
12
12
  fromCoverageMapToCoverage,
13
- getTestLineStart
13
+ getCallSites
14
14
  } = require('../../dd-trace/src/plugins/util/test')
15
15
 
16
16
  const testStartCh = channel('ci:mocha:test:start')
@@ -393,9 +393,13 @@ addHook({
393
393
  file: 'lib/suite.js'
394
394
  }, (Suite) => {
395
395
  shimmer.wrap(Suite.prototype, 'addTest', addTest => function (test) {
396
- // In here, the test definition is in the stack, so we search for it.
397
- const startLine = getTestLineStart(new Error(), test.file)
398
- testToStartLine.set(test, startLine)
396
+ const callSites = getCallSites()
397
+ let startLine
398
+ const testCallSite = callSites.find(site => site.getFileName() === test.file)
399
+ if (testCallSite) {
400
+ startLine = testCallSite.getLineNumber()
401
+ testToStartLine.set(test, startLine)
402
+ }
399
403
  return addTest.apply(this, arguments)
400
404
  })
401
405
  return Suite
@@ -30,9 +30,8 @@ function wrapQuery (query) {
30
30
  const callbackResource = new AsyncResource('bound-anonymous-fn')
31
31
  const asyncResource = new AsyncResource('bound-anonymous-fn')
32
32
  const processId = this.processID
33
- let pgQuery = {
34
- text: arguments[0]
35
- }
33
+
34
+ let pgQuery = arguments[0] && typeof arguments[0] === 'object' ? arguments[0] : { text: arguments[0] }
36
35
 
37
36
  return asyncResource.runInAsyncScope(() => {
38
37
  startCh.publish({
@@ -41,7 +40,7 @@ function wrapQuery (query) {
41
40
  processId
42
41
  })
43
42
 
44
- arguments[0] = pgQuery.text
43
+ arguments[0] = pgQuery
45
44
 
46
45
  const finish = asyncResource.bind(function (error) {
47
46
  if (error) {
@@ -214,10 +214,20 @@ function runnerHook (runnerExport, playwrightVersion) {
214
214
  })
215
215
 
216
216
  const runAllTestsReturn = await runAllTests.apply(this, arguments)
217
+
218
+ Object.values(remainingTestsByFile).forEach(tests => {
219
+ // `tests` should normally be empty, but if it isn't,
220
+ // there were tests that did not go through `testBegin` or `testEnd`,
221
+ // because they were skipped
222
+ tests.forEach(test => {
223
+ testBeginHandler(test)
224
+ testEndHandler(test, 'skip')
225
+ })
226
+ })
227
+
217
228
  const sessionStatus = runAllTestsReturn.status || runAllTestsReturn
218
229
 
219
230
  let onDone
220
-
221
231
  const flushWait = new Promise(resolve => {
222
232
  onDone = resolve
223
233
  })
@@ -11,9 +11,11 @@ class Amqp10ConsumerPlugin extends ConsumerPlugin {
11
11
  const source = getShortName(link)
12
12
  const address = getAddress(link)
13
13
 
14
- this.startSpan({
14
+ this.startSpan('amqp.receive', {
15
+ service: this.config.service || `${this.tracer._service}-amqp`,
15
16
  resource: ['receive', source].filter(v => v).join(' '),
16
17
  type: 'worker',
18
+ kind: 'consumer',
17
19
  meta: {
18
20
  'amqp.link.source.address': source,
19
21
  'amqp.link.role': 'receiver',
@@ -13,8 +13,10 @@ class Amqp10ProducerPlugin extends ProducerPlugin {
13
13
  const address = getAddress(link)
14
14
  const target = getShortName(link)
15
15
 
16
- this.startSpan({
16
+ this.startSpan('amqp.send', {
17
+ service: this.config.service || `${this.tracer._service}-amqp`,
17
18
  resource: ['send', target].filter(v => v).join(' '),
19
+ kind: 'producer',
18
20
  meta: {
19
21
  'amqp.link.target.address': target,
20
22
  'amqp.link.role': 'sender',
@@ -7,7 +7,6 @@ const { getResourceName } = require('./util')
7
7
 
8
8
  class AmqplibClientPlugin extends ClientPlugin {
9
9
  static get id () { return 'amqplib' }
10
- static get type () { return 'messaging' }
11
10
  static get operation () { return 'command' }
12
11
 
13
12
  start ({ channel = {}, method, fields }) {
@@ -15,10 +14,10 @@ class AmqplibClientPlugin extends ClientPlugin {
15
14
  if (method === 'basic.publish') return
16
15
 
17
16
  const stream = (channel.connection && channel.connection.stream) || {}
18
- const span = this.startSpan(this.operationName(), {
19
- service: this.config.service || this.serviceName(),
17
+ const span = this.startSpan('amqp.command', {
18
+ service: this.config.service || `${this.tracer._service}-amqp`,
20
19
  resource: getResourceName(method, fields),
21
- kind: this.constructor.kind,
20
+ kind: 'client',
22
21
  meta: {
23
22
  'out.host': stream._host,
24
23
  [CLIENT_PORT_KEY]: stream.remotePort,
@@ -13,9 +13,11 @@ class AmqplibConsumerPlugin extends ConsumerPlugin {
13
13
 
14
14
  const childOf = extract(this.tracer, message)
15
15
 
16
- this.startSpan({
16
+ this.startSpan('amqp.command', {
17
17
  childOf,
18
+ service: this.config.service || `${this.tracer._service}-amqp`,
18
19
  resource: getResourceName(method, fields),
20
+ kind: 'consumer',
19
21
  type: 'worker',
20
22
  meta: {
21
23
  'amqp.queue': fields.queue,
@@ -13,8 +13,10 @@ class AmqplibProducerPlugin extends ProducerPlugin {
13
13
  if (method !== 'basic.publish') return
14
14
 
15
15
  const stream = (channel.connection && channel.connection.stream) || {}
16
- const span = this.startSpan({
16
+ const span = this.startSpan('amqp.command', {
17
+ service: this.config.service || `${this.tracer._service}-amqp`,
17
18
  resource: getResourceName(method, fields),
19
+ kind: 'producer',
18
20
  meta: {
19
21
  'out.host': stream._host,
20
22
  [CLIENT_PORT_KEY]: stream.remotePort,
@@ -4,16 +4,15 @@ const ClientPlugin = require('../../dd-trace/src/plugins/client')
4
4
 
5
5
  class GoogleCloudPubsubClientPlugin extends ClientPlugin {
6
6
  static get id () { return 'google-cloud-pubsub' }
7
- static get type () { return 'messaging' }
8
7
  static get operation () { return 'request' }
9
8
 
10
9
  start ({ request, api, projectId }) {
11
10
  if (api === 'publish') return
12
11
 
13
- this.startSpan(this.operationName(), {
14
- service: this.config.service || this.serviceName(),
12
+ this.startSpan('pubsub.request', {
13
+ service: this.config.service || `${this.tracer._service}-pubsub`,
15
14
  resource: [api, request.name].filter(x => x).join(' '),
16
- kind: this.constructor.kind,
15
+ kind: 'client',
17
16
  meta: {
18
17
  'pubsub.method': api,
19
18
  'gcloud.project_id': projectId
@@ -11,9 +11,11 @@ class GoogleCloudPubsubConsumerPlugin extends ConsumerPlugin {
11
11
  const topic = subscription.metadata && subscription.metadata.topic
12
12
  const childOf = this.tracer.extract('text_map', message.attributes) || null
13
13
 
14
- this.startSpan({
14
+ this.startSpan('pubsub.receive', {
15
15
  childOf,
16
+ service: this.config.service,
16
17
  resource: topic,
18
+ kind: 'consumer',
17
19
  type: 'worker',
18
20
  meta: {
19
21
  'gcloud.project_id': subscription.pubsub.projectId,
@@ -11,8 +11,10 @@ class GoogleCloudPubsubProducerPlugin extends ProducerPlugin {
11
11
 
12
12
  const messages = request.messages || []
13
13
  const topic = request.topic
14
- const span = this.startSpan({ // TODO: rename
14
+ const span = this.startSpan('pubsub.request', { // TODO: rename
15
+ service: this.config.service || `${this.tracer._service}-pubsub`,
15
16
  resource: `${api} ${topic}`,
17
+ kind: 'producer',
16
18
  meta: {
17
19
  'gcloud.project_id': projectId,
18
20
  'pubsub.method': api, // TODO: remove
@@ -8,9 +8,12 @@ class KafkajsConsumerPlugin extends ConsumerPlugin {
8
8
 
9
9
  start ({ topic, partition, message }) {
10
10
  const childOf = extract(this.tracer, message.headers)
11
- this.startSpan({
11
+
12
+ this.startSpan('kafka.consume', {
12
13
  childOf,
14
+ service: this.config.service || `${this.tracer._service}-kafka`,
13
15
  resource: topic,
16
+ kind: 'consumer',
14
17
  type: 'worker',
15
18
  meta: {
16
19
  'component': 'kafkajs',
@@ -30,6 +33,8 @@ function extract (tracer, bufferMap) {
30
33
  const textMap = {}
31
34
 
32
35
  for (const key of Object.keys(bufferMap)) {
36
+ if (bufferMap[key] === null || bufferMap[key] === undefined) continue
37
+
33
38
  textMap[key] = bufferMap[key].toString()
34
39
  }
35
40
 
@@ -7,8 +7,10 @@ class KafkajsProducerPlugin extends ProducerPlugin {
7
7
  static get operation () { return 'produce' }
8
8
 
9
9
  start ({ topic, messages }) {
10
- const span = this.startSpan({
10
+ const span = this.startSpan('kafka.produce', {
11
+ service: this.config.service || `${this.tracer._service}-kafka`,
11
12
  resource: topic,
13
+ kind: 'producer',
12
14
  meta: {
13
15
  'component': 'kafkajs',
14
16
  'kafka.topic': topic
@@ -9,7 +9,7 @@ class PGPlugin extends DatabasePlugin {
9
9
  static get system () { return 'postgres' }
10
10
 
11
11
  start ({ params = {}, query, processId }) {
12
- const service = getServiceName(this.config, params)
12
+ const service = getServiceName(this, params)
13
13
  const originalStatement = query.text
14
14
 
15
15
  this.startSpan('pg.query', {
@@ -31,12 +31,12 @@ class PGPlugin extends DatabasePlugin {
31
31
  }
32
32
  }
33
33
 
34
- function getServiceName (config, params) {
35
- if (typeof config.service === 'function') {
36
- return config.service(params)
34
+ function getServiceName (tracer, params) {
35
+ if (typeof tracer.config.service === 'function') {
36
+ return tracer.config.service(params)
37
37
  }
38
38
 
39
- return config.service
39
+ return tracer.config.service || `${tracer._tracer._tracer._service}-postgres`
40
40
  }
41
41
 
42
42
  module.exports = PGPlugin
@@ -19,10 +19,12 @@ class RheaConsumerPlugin extends ConsumerPlugin {
19
19
  const name = getResourceNameFromMessage(msgObj)
20
20
  const childOf = extractTextMap(msgObj, this.tracer)
21
21
 
22
- this.startSpan({
22
+ this.startSpan('amqp.receive', {
23
23
  childOf,
24
+ service: this.config.service,
24
25
  resource: name,
25
26
  type: 'worker',
27
+ kind: 'consumer',
26
28
  meta: {
27
29
  'component': 'rhea',
28
30
  'amqp.link.source.address': name,
@@ -9,13 +9,17 @@ class RheaProducerPlugin extends ProducerPlugin {
9
9
 
10
10
  constructor (...args) {
11
11
  super(...args)
12
+
12
13
  this.addTraceSub('encode', this.encode.bind(this))
13
14
  }
14
15
 
15
16
  start ({ targetAddress, host, port }) {
16
17
  const name = targetAddress || 'amq.topic'
17
- this.startSpan({
18
+
19
+ this.startSpan('amqp.send', {
20
+ service: this.config.service || `${this.tracer._service}-amqp-producer`,
18
21
  resource: name,
22
+ kind: 'producer',
19
23
  meta: {
20
24
  'component': 'rhea',
21
25
  'amqp.link.target.address': name,
@@ -34,19 +34,6 @@ function safeJsonParse (input) {
34
34
  }
35
35
  }
36
36
 
37
- const namingVersions = ['v0', 'v1']
38
- const defaultVersion = 'v0'
39
-
40
- function validateNamingVersion (versionString) {
41
- if (!namingVersions.includes(versionString)) {
42
- log.warn(
43
- `Unexpected input for config.spanAttributeSchema, picked default ${defaultVersion}`
44
- )
45
- return defaultVersion
46
- }
47
- return versionString
48
- }
49
-
50
37
  // Shallow clone with property name remapping
51
38
  function remapify (input, mappings) {
52
39
  if (!input) return
@@ -273,9 +260,7 @@ class Config {
273
260
  process.env.DD_TRACE_EXPERIMENTAL_GET_RUM_DATA_ENABLED,
274
261
  false
275
262
  )
276
- const DD_TRACE_SPAN_ATTRIBUTE_SCHEMA = validateNamingVersion(
277
- process.env.DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
278
- )
263
+
279
264
  const DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH = coalesce(
280
265
  process.env.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
281
266
  '512'
@@ -482,7 +467,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
482
467
  sourceMap: !isFalse(DD_PROFILING_SOURCE_MAP),
483
468
  exporters: DD_PROFILING_EXPORTERS
484
469
  }
485
- this.spanAttributeSchema = DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
486
470
  this.lookup = options.lookup
487
471
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
488
472
  // Disabled for CI Visibility's agentless
@@ -129,12 +129,17 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
129
129
  _encodeEventContent (bytes, content) {
130
130
  const keysLength = Object.keys(content).length
131
131
 
132
+ let totalKeysLength = keysLength
132
133
  if (content.meta.test_session_id) {
133
- this._encodeMapPrefix(bytes, keysLength + 3)
134
- } else {
135
- this._encodeMapPrefix(bytes, keysLength)
134
+ totalKeysLength = totalKeysLength + 1
136
135
  }
137
-
136
+ if (content.meta.test_module_id) {
137
+ totalKeysLength = totalKeysLength + 1
138
+ }
139
+ if (content.meta.test_suite_id) {
140
+ totalKeysLength = totalKeysLength + 1
141
+ }
142
+ this._encodeMapPrefix(bytes, totalKeysLength)
138
143
  if (content.type) {
139
144
  this._encodeString(bytes, 'type')
140
145
  this._encodeString(bytes, content.type)
@@ -170,15 +175,20 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
170
175
  this._encodeString(bytes, 'test_session_id')
171
176
  this._encodeId(bytes, id(content.meta.test_session_id, 10))
172
177
  delete content.meta.test_session_id
178
+ }
173
179
 
180
+ if (content.meta.test_module_id) {
174
181
  this._encodeString(bytes, 'test_module_id')
175
182
  this._encodeId(bytes, id(content.meta.test_module_id, 10))
176
183
  delete content.meta.test_module_id
184
+ }
177
185
 
186
+ if (content.meta.test_suite_id) {
178
187
  this._encodeString(bytes, 'test_suite_id')
179
188
  this._encodeId(bytes, id(content.meta.test_suite_id, 10))
180
189
  delete content.meta.test_suite_id
181
190
  }
191
+
182
192
  this._encodeString(bytes, 'meta')
183
193
  this._encodeMap(bytes, content.meta)
184
194
  this._encodeString(bytes, 'metrics')
@@ -4,7 +4,6 @@ const { channel } = require('../../diagnostics_channel')
4
4
  const { isFalse } = require('./util')
5
5
  const plugins = require('./plugins')
6
6
  const log = require('./log')
7
- const Nomenclature = require('./service-naming')
8
7
 
9
8
  const loadChannel = channel('dd-trace:instrumentation:load')
10
9
 
@@ -97,7 +96,6 @@ module.exports = class PluginManager {
97
96
  // like instrumenter.enable()
98
97
  configure (config = {}) {
99
98
  this._tracerConfig = config
100
- Nomenclature.configure(config)
101
99
 
102
100
  for (const name in pluginClasses) {
103
101
  this.loadPlugin(name)
@@ -1,10 +1,9 @@
1
1
  'use strict'
2
2
 
3
- const OutboundPlugin = require('./outbound')
3
+ const OutgoingPlugin = require('./outgoing')
4
4
 
5
- class ClientPlugin extends OutboundPlugin {
5
+ class ClientPlugin extends OutgoingPlugin {
6
6
  static get operation () { return 'request' }
7
- static get kind () { return 'client' }
8
7
  }
9
8
 
10
9
  module.exports = ClientPlugin
@@ -1,24 +1,9 @@
1
1
  'use strict'
2
2
 
3
- const InboundPlugin = require('./inbound')
3
+ const IncomingPlugin = require('./incoming')
4
4
 
5
- class ConsumerPlugin extends InboundPlugin {
5
+ class ConsumerPlugin extends IncomingPlugin {
6
6
  static get operation () { return 'receive' }
7
- static get kind () { return 'consumer' }
8
- static get type () { return 'messaging' }
9
-
10
- startSpan (options) {
11
- const spanDefaults = {
12
- service: this.config.service || this.serviceName(),
13
- kind: this.constructor.kind
14
- }
15
- Object.keys(spanDefaults).forEach(
16
- key => {
17
- if (!options[key]) options[key] = spanDefaults[key]
18
- }
19
- )
20
- return super.startSpan(this.operationName(), options)
21
- }
22
7
  }
23
8
 
24
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
@@ -4,7 +4,7 @@ const { CLIENT_PORT_KEY } = require('../constants')
4
4
  const TracingPlugin = require('./tracing')
5
5
 
6
6
  // TODO: Exit span on finish when AsyncResource instances are removed.
7
- class OutboundPlugin extends TracingPlugin {
7
+ class OutgoingPlugin extends TracingPlugin {
8
8
  constructor (...args) {
9
9
  super(...args)
10
10
 
@@ -29,4 +29,4 @@ class OutboundPlugin extends TracingPlugin {
29
29
  }
30
30
  }
31
31
 
32
- module.exports = OutboundPlugin
32
+ module.exports = OutgoingPlugin
@@ -1,24 +1,9 @@
1
1
  'use strict'
2
2
 
3
- const OutboundPlugin = require('./outbound')
3
+ const OutgoingPlugin = require('./outgoing')
4
4
 
5
- class ProducerPlugin extends OutboundPlugin {
5
+ class ProducerPlugin extends OutgoingPlugin {
6
6
  static get operation () { return 'publish' }
7
- static get kind () { return 'producer' }
8
- static get type () { return 'messaging' }
9
-
10
- startSpan (options) {
11
- const spanDefaults = {
12
- service: this.config.service || this.serviceName(),
13
- kind: this.constructor.kind
14
- }
15
- Object.keys(spanDefaults).forEach(
16
- key => {
17
- if (!options[key]) options[key] = spanDefaults[key]
18
- }
19
- )
20
- return super.startSpan(this.operationName(), options)
21
- }
22
7
  }
23
8
 
24
9
  module.exports = ProducerPlugin
@@ -1,8 +1,8 @@
1
1
  'use strict'
2
2
 
3
- const InboundPlugin = require('./inbound')
3
+ const IncomingPlugin = require('./incoming')
4
4
 
5
- class ServerPlugin extends InboundPlugin {
5
+ class ServerPlugin extends IncomingPlugin {
6
6
  static get operation () { return 'request' }
7
7
  }
8
8
 
@@ -4,7 +4,6 @@ const Plugin = require('./plugin')
4
4
  const { storage } = require('../../../datadog-core')
5
5
  const analyticsSampler = require('../analytics_sampler')
6
6
  const { COMPONENT } = require('../constants')
7
- const Nomenclature = require('../service-naming')
8
7
 
9
8
  class TracingPlugin extends Plugin {
10
9
  constructor (...args) {
@@ -32,16 +31,6 @@ class TracingPlugin extends Plugin {
32
31
  return store && store.span
33
32
  }
34
33
 
35
- serviceName (serviceArgs) {
36
- const { type, id, kind } = this.constructor
37
- return Nomenclature.serviceName(type, kind, id, serviceArgs)
38
- }
39
-
40
- operationName (opNameArgs) {
41
- const { type, id, kind } = this.constructor
42
- return Nomenclature.opName(type, kind, id, opNameArgs)
43
- }
44
-
45
34
  configure (config) {
46
35
  return super.configure({
47
36
  ...config,
@@ -50,12 +50,10 @@ const CI_APP_ORIGIN = 'ciapp-test'
50
50
  const JEST_TEST_RUNNER = 'test.jest.test_runner'
51
51
 
52
52
  const TEST_ITR_TESTS_SKIPPED = '_dd.ci.itr.tests_skipped'
53
- const TEST_SESSION_ITR_SKIPPING_ENABLED = 'test_session.itr.tests_skipping.enabled'
54
- const TEST_SESSION_CODE_COVERAGE_ENABLED = 'test_session.code_coverage.enabled'
55
- const TEST_MODULE_ITR_SKIPPING_ENABLED = 'test_module.itr.tests_skipping.enabled'
56
- const TEST_MODULE_CODE_COVERAGE_ENABLED = 'test_module.code_coverage.enabled'
53
+ const TEST_ITR_SKIPPING_ENABLED = 'test.itr.tests_skipping.enabled'
54
+ const TEST_CODE_COVERAGE_ENABLED = 'test.code_coverage.enabled'
57
55
 
58
- const TEST_CODE_COVERAGE_LINES_TOTAL = 'test.codecov_lines_total'
56
+ const TEST_CODE_COVERAGE_LINES_PCT = 'test.code_coverage.lines_pct'
59
57
 
60
58
  // jest worker variables
61
59
  const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
@@ -97,17 +95,16 @@ module.exports = {
97
95
  TEST_SUITE_ID,
98
96
  TEST_ITR_TESTS_SKIPPED,
99
97
  TEST_MODULE,
100
- TEST_SESSION_ITR_SKIPPING_ENABLED,
101
- TEST_SESSION_CODE_COVERAGE_ENABLED,
102
- TEST_MODULE_ITR_SKIPPING_ENABLED,
103
- TEST_MODULE_CODE_COVERAGE_ENABLED,
104
- TEST_CODE_COVERAGE_LINES_TOTAL,
98
+ TEST_ITR_SKIPPING_ENABLED,
99
+ TEST_CODE_COVERAGE_ENABLED,
100
+ TEST_CODE_COVERAGE_LINES_PCT,
105
101
  addIntelligentTestRunnerSpanTags,
106
102
  getCoveredFilenamesFromCoverage,
107
103
  resetCoverage,
108
104
  mergeCoverage,
109
105
  fromCoverageMapToCoverage,
110
- getTestLineStart
106
+ getTestLineStart,
107
+ getCallSites
111
108
  }
112
109
 
113
110
  // Returns pkg manager and its version, separated by '-', e.g. npm-8.15.0 or yarn-1.22.19
@@ -316,17 +313,17 @@ function addIntelligentTestRunnerSpanTags (
316
313
  { isSuitesSkipped, isSuitesSkippingEnabled, isCodeCoverageEnabled, testCodeCoverageLinesTotal }
317
314
  ) {
318
315
  testSessionSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false')
319
- testSessionSpan.setTag(TEST_SESSION_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
320
- testSessionSpan.setTag(TEST_SESSION_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
316
+ testSessionSpan.setTag(TEST_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
317
+ testSessionSpan.setTag(TEST_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
321
318
 
322
319
  testModuleSpan.setTag(TEST_ITR_TESTS_SKIPPED, isSuitesSkipped ? 'true' : 'false')
323
- testModuleSpan.setTag(TEST_MODULE_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
324
- testModuleSpan.setTag(TEST_MODULE_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
320
+ testModuleSpan.setTag(TEST_ITR_SKIPPING_ENABLED, isSuitesSkippingEnabled ? 'true' : 'false')
321
+ testModuleSpan.setTag(TEST_CODE_COVERAGE_ENABLED, isCodeCoverageEnabled ? 'true' : 'false')
325
322
 
326
323
  // If suites have been skipped we don't want to report the total coverage, as it will be wrong
327
324
  if (testCodeCoverageLinesTotal !== undefined && !isSuitesSkipped) {
328
- testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal)
329
- testModuleSpan.setTag(TEST_CODE_COVERAGE_LINES_TOTAL, testCodeCoverageLinesTotal)
325
+ testSessionSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
326
+ testModuleSpan.setTag(TEST_CODE_COVERAGE_LINES_PCT, testCodeCoverageLinesTotal)
330
327
  }
331
328
  }
332
329
 
@@ -399,3 +396,23 @@ function getTestLineStart (err, testSuitePath) {
399
396
  return null
400
397
  }
401
398
  }
399
+
400
+ // From https://github.com/felixge/node-stack-trace/blob/ba06dcdb50d465cd440d84a563836e293b360427/index.js#L1
401
+ function getCallSites () {
402
+ const oldLimit = Error.stackTraceLimit
403
+ Error.stackTraceLimit = Infinity
404
+
405
+ const dummy = {}
406
+
407
+ const v8Handler = Error.prepareStackTrace
408
+ Error.prepareStackTrace = function (_, v8StackTrace) {
409
+ return v8StackTrace
410
+ }
411
+ Error.captureStackTrace(dummy)
412
+
413
+ const v8StackTrace = dummy.stack
414
+ Error.prepareStackTrace = v8Handler
415
+ Error.stackTraceLimit = oldLimit
416
+
417
+ return v8StackTrace
418
+ }
@@ -1,5 +1,17 @@
1
1
  const request = require('../exporters/common/request')
2
2
  let seqId = 0
3
+
4
+ function getPayload (payload) {
5
+ // Some telemetry endpoints payloads accept collections of elements such as the 'logs' endpoint.
6
+ // 'logs' request type payload is meant to send library logs to Datadog’s backend.
7
+ if (Array.isArray(payload)) {
8
+ return payload
9
+ } else {
10
+ const { logger, tags, serviceMapping, ...trimmedPayload } = payload
11
+ return trimmedPayload
12
+ }
13
+ }
14
+
3
15
  function sendData (config, application, host, reqType, payload = {}) {
4
16
  const {
5
17
  hostname,
@@ -7,8 +19,6 @@ function sendData (config, application, host, reqType, payload = {}) {
7
19
  url
8
20
  } = config
9
21
 
10
- const { logger, tags, serviceMapping, ...trimmedPayload } = payload
11
-
12
22
  const options = {
13
23
  url,
14
24
  hostname,
@@ -27,7 +37,7 @@ function sendData (config, application, host, reqType, payload = {}) {
27
37
  tracer_time: Math.floor(Date.now() / 1000),
28
38
  runtime_id: config.tags['runtime-id'],
29
39
  seq_id: ++seqId,
30
- payload: trimmedPayload,
40
+ payload: getPayload(payload),
31
41
  application,
32
42
  host
33
43
  })
@@ -1,7 +0,0 @@
1
- 'use strict'
2
-
3
- const TracingPlugin = require('./tracing')
4
-
5
- class InboundPlugin extends TracingPlugin {}
6
-
7
- module.exports = InboundPlugin
@@ -1,41 +0,0 @@
1
- const { schemaDefinitions } = require('./schemas')
2
-
3
- const kindMap = {
4
- messaging: {
5
- client: 'controlPlane',
6
- consumer: 'inbound',
7
- producer: 'outbound'
8
- }
9
- }
10
-
11
- class SchemaManager {
12
- constructor () {
13
- this.schemas = schemaDefinitions
14
- this.config = { spanAttributeSchema: 'v0' }
15
- }
16
-
17
- get schema () {
18
- return this.schemas[this.version]
19
- }
20
-
21
- get version () {
22
- return this.config.spanAttributeSchema
23
- }
24
-
25
- opName (type, kind, plugin, opNameArgs) {
26
- return this.schema.getOpName(type, kindMap[type][kind], plugin, opNameArgs)
27
- }
28
-
29
- serviceName (type, kind, plugin, serviceNameArgs) {
30
- return this.schema.getServiceName(type, kindMap[type][kind], plugin, serviceNameArgs)
31
- }
32
-
33
- configure (config = {}) {
34
- this.config = config
35
- Object.values(this.schemas).forEach(schemaDef => {
36
- schemaDef.configure(config)
37
- })
38
- }
39
- }
40
-
41
- module.exports = new SchemaManager()
@@ -1,28 +0,0 @@
1
- class SchemaDefinition {
2
- constructor (schema) {
3
- this.schema = schema
4
- }
5
-
6
- getSchemaItem (type, subType, plugin) {
7
- const schema = this.schema
8
- if (schema && schema[type] && schema[type][subType] && schema[type][subType][plugin]) {
9
- return schema[type][subType][plugin]
10
- }
11
- }
12
-
13
- getOpName (type, subType, plugin, opNameArgs) {
14
- const item = this.getSchemaItem(type, subType, plugin)
15
- return item.opName(opNameArgs)
16
- }
17
-
18
- getServiceName (type, subType, plugin, serviceNameArgs) {
19
- const item = this.getSchemaItem(type, subType, plugin)
20
- return item.serviceName(this.service, serviceNameArgs)
21
- }
22
-
23
- configure ({ service }) {
24
- this.service = service
25
- }
26
- }
27
-
28
- module.exports = SchemaDefinition
@@ -1,6 +0,0 @@
1
- const v0 = require('./v0')
2
- const v1 = require('./v1')
3
-
4
- module.exports = {
5
- schemaDefinitions: { v0, v1 }
6
- }
@@ -1,66 +0,0 @@
1
- const SchemaDefinition = require('./definition')
2
-
3
- function amqpServiceName (service) {
4
- return `${service}-amqp`
5
- }
6
-
7
- const schema = {
8
- messaging: {
9
- outbound: {
10
- amqplib: {
11
- opName: () => 'amqp.command',
12
- serviceName: amqpServiceName
13
- },
14
- amqp10: {
15
- opName: () => 'amqp.send',
16
- serviceName: amqpServiceName
17
- },
18
- 'google-cloud-pubsub': {
19
- opName: () => 'pubsub.request',
20
- serviceName: service => `${service}-pubsub`
21
- },
22
- kafkajs: {
23
- opName: () => 'kafka.produce',
24
- serviceName: service => `${service}-kafka`
25
- },
26
- rhea: {
27
- opName: () => 'amqp.send',
28
- serviceName: service => `${service}-amqp-producer`
29
- }
30
- },
31
- inbound: {
32
- amqplib: {
33
- opName: () => 'amqp.command',
34
- serviceName: amqpServiceName
35
- },
36
- amqp10: {
37
- opName: () => 'amqp.receive',
38
- serviceName: amqpServiceName
39
- },
40
- 'google-cloud-pubsub': {
41
- opName: () => 'pubsub.receive',
42
- serviceName: service => service
43
- },
44
- kafkajs: {
45
- opName: () => 'kafka.consume',
46
- serviceName: service => `${service}-kafka`
47
- },
48
- rhea: {
49
- opName: () => 'amqp.receive',
50
- serviceName: service => service
51
- }
52
- },
53
- controlPlane: {
54
- amqplib: {
55
- opName: () => 'amqp.command',
56
- serviceName: amqpServiceName
57
- },
58
- 'google-cloud-pubsub': {
59
- opName: () => 'pubsub.request',
60
- serviceName: service => `${service}-pubsub`
61
- }
62
- }
63
- }
64
- }
65
-
66
- module.exports = new SchemaDefinition(schema)
@@ -1,58 +0,0 @@
1
- const SchemaDefinition = require('./definition')
2
-
3
- function identityService (service) {
4
- return service
5
- }
6
-
7
- const amqpInbound = {
8
- opName: () => 'amqp.process',
9
- serviceName: identityService
10
- }
11
-
12
- const amqpOutbound = {
13
- opName: () => 'amqp.send',
14
- serviceName: identityService
15
- }
16
-
17
- const schema = {
18
- messaging: {
19
- outbound: {
20
- amqplib: amqpOutbound,
21
- amqp10: amqpOutbound,
22
- 'google-cloud-pubsub': {
23
- opName: () => 'gcp.pubsub.send',
24
- serviceName: identityService
25
- },
26
- kafkajs: {
27
- opName: () => 'kafka.send',
28
- serviceName: identityService
29
- },
30
- rhea: amqpOutbound
31
- },
32
- inbound: {
33
- amqplib: amqpInbound,
34
- amqp10: amqpInbound,
35
- 'google-cloud-pubsub': {
36
- opName: () => 'gcp.pubsub.process',
37
- serviceName: identityService
38
- },
39
- kafkajs: {
40
- opName: () => 'kafka.process',
41
- serviceName: identityService
42
- },
43
- rhea: amqpInbound
44
- },
45
- controlPlane: {
46
- amqplib: {
47
- opName: () => 'amqp.command',
48
- serviceName: identityService
49
- },
50
- 'google-cloud-pubsub': {
51
- opName: () => 'gcp.pubsub.request',
52
- serviceName: identityService
53
- }
54
- }
55
- }
56
- }
57
-
58
- module.exports = new SchemaDefinition(schema)