dd-trace 2.13.0 → 2.14.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 (31) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/package.json +2 -1
  3. package/packages/datadog-core/src/storage/async_resource.js +19 -1
  4. package/packages/datadog-instrumentations/src/cucumber.js +15 -0
  5. package/packages/datadog-instrumentations/src/fs.js +11 -0
  6. package/packages/datadog-instrumentations/src/helpers/hooks.js +1 -0
  7. package/packages/datadog-instrumentations/src/helpers/instrumentations.js +5 -1
  8. package/packages/datadog-instrumentations/src/jest.js +33 -11
  9. package/packages/datadog-plugin-cucumber/src/index.js +4 -0
  10. package/packages/datadog-plugin-fs/src/index.js +72 -38
  11. package/packages/datadog-plugin-jest/src/index.js +25 -4
  12. package/packages/datadog-plugin-mongodb-core/src/index.js +21 -6
  13. package/packages/datadog-plugin-oracledb/src/index.js +12 -4
  14. package/packages/dd-trace/index.js +1 -1
  15. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +50 -0
  16. package/packages/dd-trace/src/ci-visibility/exporters/agentless/index.js +53 -8
  17. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +23 -24
  18. package/packages/dd-trace/src/config.js +7 -0
  19. package/packages/dd-trace/src/encode/0.4.js +51 -58
  20. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +13 -34
  21. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +84 -0
  22. package/packages/dd-trace/src/exporters/agent/index.js +13 -7
  23. package/packages/dd-trace/src/exporters/agent/writer.js +1 -1
  24. package/packages/dd-trace/src/exporters/common/request.js +20 -9
  25. package/packages/dd-trace/src/exporters/common/writer.js +9 -6
  26. package/packages/dd-trace/src/index.js +10 -0
  27. package/packages/dd-trace/src/noop/proxy.js +87 -0
  28. package/packages/dd-trace/src/plugin_manager.js +6 -4
  29. package/packages/dd-trace/src/plugins/index.js +1 -0
  30. package/packages/dd-trace/src/proxy.js +5 -81
  31. package/packages/dd-trace/src/telemetry.js +1 -1
@@ -8,6 +8,7 @@ require,crypto-randomuuid,MIT,Copyright 2021 Node.js Foundation and contributors
8
8
  require,diagnostics_channel,MIT,Copyright 2021 Simon D.
9
9
  require,ignore,MIT,Copyright 2013 Kael Zhang and contributors
10
10
  require,import-in-the-middle,Apache license 2.0,Copyright 2021 Datadog Inc.
11
+ require,istanbul-lib-coverage,BSD-3-Clause,Copyright 2012-2015 Yahoo! Inc.
11
12
  require,koalas,MIT,Copyright 2013-2017 Brian Woodward
12
13
  require,limiter,MIT,Copyright 2011 John Hurliman
13
14
  require,lodash.kebabcase,MIT,Copyright JS Foundation and other contributors
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dd-trace",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "description": "Datadog APM tracing client for JavaScript",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
@@ -67,6 +67,7 @@
67
67
  "diagnostics_channel": "^1.1.0",
68
68
  "ignore": "^5.2.0",
69
69
  "import-in-the-middle": "^1.3.0",
70
+ "istanbul-lib-coverage": "3.2.0",
70
71
  "koalas": "^1.0.2",
71
72
  "limiter": "^1.1.4",
72
73
  "lodash.kebabcase": "^4.1.1",
@@ -6,9 +6,27 @@ const { channel } = require('diagnostics_channel')
6
6
  const beforeCh = channel('dd-trace:storage:before')
7
7
  const afterCh = channel('dd-trace:storage:after')
8
8
 
9
+ let PrivateSymbol = Symbol
10
+ function makePrivateSymbol () {
11
+ // eslint-disable-next-line no-new-func
12
+ PrivateSymbol = new Function('name', 'return %CreatePrivateSymbol(name)')
13
+ }
14
+
15
+ try {
16
+ makePrivateSymbol()
17
+ } catch (e) {
18
+ try {
19
+ const v8 = require('v8')
20
+ v8.setFlagsFromString('--allow-natives-syntax')
21
+ makePrivateSymbol()
22
+ v8.setFlagsFromString('--no-allow-natives-syntax')
23
+ // eslint-disable-next-line no-empty
24
+ } catch (e) {}
25
+ }
26
+
9
27
  class AsyncResourceStorage {
10
28
  constructor () {
11
- this._ddResourceStore = Symbol('ddResourceStore')
29
+ this._ddResourceStore = PrivateSymbol('ddResourceStore')
12
30
  this._enabled = false
13
31
  this._hook = createHook(this._createHook())
14
32
  }
@@ -7,6 +7,7 @@ const runStartCh = channel('ci:cucumber:run:start')
7
7
  const runFinishCh = channel('ci:cucumber:run:finish')
8
8
  const runStepStartCh = channel('ci:cucumber:run-step:start')
9
9
  const errorCh = channel('ci:cucumber:error')
10
+ const sessionFinishCh = channel('ci:cucumber:session:finish')
10
11
 
11
12
  // TODO: remove in a later major version
12
13
  const patched = new WeakSet()
@@ -128,4 +129,18 @@ addHook({
128
129
  file: 'lib/runtime/test_case_runner.js'
129
130
  }, testCaseHook)
130
131
 
132
+ addHook({
133
+ name: '@cucumber/cucumber',
134
+ versions: ['>=7.0.0'],
135
+ file: 'lib/runtime/index.js'
136
+ }, (Runtime) => {
137
+ shimmer.wrap(Runtime.default.prototype, 'start', start => async function () {
138
+ const result = await start.apply(this, arguments)
139
+ sessionFinishCh.publish(undefined)
140
+ return result
141
+ })
142
+
143
+ return Runtime
144
+ })
145
+
131
146
  module.exports = { pickleHook, testCaseHook }
@@ -0,0 +1,11 @@
1
+ 'use strict'
2
+
3
+ const { addHook, channel } = require('./helpers/instrument')
4
+
5
+ const hookChannel = channel('apm:fs:hook')
6
+
7
+ // HACK: trigger old style plugin
8
+ addHook({ name: 'fs' }, fs => {
9
+ hookChannel.publish(fs)
10
+ return fs
11
+ })
@@ -23,6 +23,7 @@ module.exports = {
23
23
  'express': () => require('../express'),
24
24
  'fastify': () => require('../fastify'),
25
25
  'find-my-way': () => require('../find-my-way'),
26
+ 'fs': () => require('../fs'),
26
27
  'graphql': () => require('../graphql'),
27
28
  'grpc': () => require('../grpc'),
28
29
  'hapi': () => require('../hapi'),
@@ -1,3 +1,7 @@
1
1
  'use strict'
2
2
 
3
- module.exports = {}
3
+ const sym = Symbol.for('_ddtrace_instrumentations')
4
+
5
+ global[sym] = global[sym] || {}
6
+
7
+ module.exports = global[sym]
@@ -1,5 +1,5 @@
1
1
  'use strict'
2
-
2
+ const istanbul = require('istanbul-lib-coverage')
3
3
  const { addHook, channel, AsyncResource } = require('./helpers/instrument')
4
4
  const shimmer = require('../../datadog-shimmer')
5
5
 
@@ -7,7 +7,8 @@ const testStartCh = channel('ci:jest:test:start')
7
7
  const testSkippedCh = channel('ci:jest:test:skip')
8
8
  const testRunFinishCh = channel('ci:jest:test:finish')
9
9
  const testErrCh = channel('ci:jest:test:err')
10
- const testSuiteFinish = channel('ci:jest:test-suite:finish')
10
+
11
+ const testCodeCoverageCh = channel('ci:jest:test:code-coverage')
11
12
 
12
13
  const {
13
14
  getTestSuitePath,
@@ -16,6 +17,24 @@ const {
16
17
 
17
18
  const { getFormattedJestTestParameters, getJestTestName } = require('../../datadog-plugin-jest/src/util')
18
19
 
20
+ // This function also resets the coverage counters
21
+ function extractCoverageInformation (coverage, rootDir) {
22
+ const coverageMap = istanbul.createCoverageMap(coverage)
23
+
24
+ return coverageMap
25
+ .files()
26
+ .filter(filename => {
27
+ const fileCoverage = coverageMap.fileCoverageFor(filename)
28
+ const lineCoverage = fileCoverage.getLineCoverage()
29
+ const isAnyLineExecuted = Object.entries(lineCoverage).some(([, numExecutions]) => !!numExecutions)
30
+
31
+ fileCoverage.resetHits()
32
+
33
+ return isAnyLineExecuted
34
+ })
35
+ .map(filename => filename.replace(`${rootDir}/`, ''))
36
+ }
37
+
19
38
  const specStatusToTestStatus = {
20
39
  'pending': 'skip',
21
40
  'disabled': 'skip',
@@ -49,15 +68,11 @@ function getWrappedEnvironment (BaseEnvironment) {
49
68
  constructor (config, context) {
50
69
  super(config, context)
51
70
  const rootDir = config.globalConfig ? config.globalConfig.rootDir : config.rootDir
71
+ this.rootDir = rootDir
52
72
  this.testSuite = getTestSuitePath(context.testPath, rootDir)
53
73
  this.nameToParams = {}
54
74
  this.global._ddtrace = global._ddtrace
55
75
  }
56
- async teardown () {
57
- super.teardown().finally(() => {
58
- testSuiteFinish.publish()
59
- })
60
- }
61
76
 
62
77
  async handleTestEvent (event, state) {
63
78
  if (super.handleTestEvent) {
@@ -99,6 +114,10 @@ function getWrappedEnvironment (BaseEnvironment) {
99
114
  if (event.name === 'test_done') {
100
115
  const asyncResource = asyncResources.get(event.test)
101
116
  asyncResource.runInAsyncScope(() => {
117
+ if (this.global.__coverage__) {
118
+ const coverageFiles = extractCoverageInformation(this.global.__coverage__, this.rootDir)
119
+ testCodeCoverageCh.publish(coverageFiles)
120
+ }
102
121
  let status = 'pass'
103
122
  if (event.test.errors && event.test.errors.length) {
104
123
  status = 'fail'
@@ -111,10 +130,13 @@ function getWrappedEnvironment (BaseEnvironment) {
111
130
  })
112
131
  }
113
132
  if (event.name === 'test_skip' || event.name === 'test_todo') {
114
- testSkippedCh.publish({
115
- name: getJestTestName(event.test),
116
- suite: this.testSuite,
117
- runner: 'jest-circus'
133
+ const asyncResource = new AsyncResource('bound-anonymous-fn')
134
+ asyncResource.runInAsyncScope(() => {
135
+ testSkippedCh.publish({
136
+ name: getJestTestName(event.test),
137
+ suite: this.testSuite,
138
+ runner: 'jest-circus'
139
+ })
118
140
  })
119
141
  }
120
142
  }
@@ -30,6 +30,10 @@ class CucumberPlugin extends Plugin {
30
30
  const sourceRoot = process.cwd()
31
31
  const codeOwnersEntries = getCodeOwnersFileEntries(sourceRoot)
32
32
 
33
+ this.addSub('ci:cucumber:session:finish', () => {
34
+ this.tracer._exporter._writer.flush()
35
+ })
36
+
33
37
  this.addSub('ci:cucumber:run:start', ({ pickleName, pickleUri }) => {
34
38
  const store = storage.getStore()
35
39
  const childOf = store ? store.span : store
@@ -1,10 +1,18 @@
1
1
  'use strict'
2
2
 
3
+ // The `fs` plugin is an old style plugin that has not been updated for the new
4
+ // plugin system and was hacked in for backward compatibility with 2.x.
5
+
3
6
  const { storage } = require('../../datadog-core')
7
+ const { channel } = require('../../datadog-instrumentations/src/helpers/instrument')
8
+ const shimmer = require('../../datadog-shimmer')
9
+ const Plugin = require('../../dd-trace/src/plugins/plugin')
4
10
 
5
11
  let kDirReadPromisified
6
12
  let kDirClosePromisified
7
13
  let kHandle
14
+ let fsConfig
15
+ let fsInstance
8
16
 
9
17
  const ddFhSym = Symbol('ddFileHandle')
10
18
 
@@ -144,8 +152,8 @@ function createWrapDirAsyncIterator (config, tracer, instrumenter) {
144
152
  }
145
153
  }
146
154
  }
147
- instrumenter.wrap(this, kDirReadPromisified, createWrapDirRead(config, tracer))
148
- instrumenter.wrap(this, kDirClosePromisified, createWrapKDirClose(config, tracer, instrumenter))
155
+ shimmer.wrap(this, kDirReadPromisified, createWrapDirRead(config, tracer))
156
+ shimmer.wrap(this, kDirClosePromisified, createWrapKDirClose(config, tracer, instrumenter))
149
157
  return asyncIterator.apply(this, arguments)
150
158
  }
151
159
  }
@@ -158,8 +166,8 @@ function createWrapKDirClose (config, tracer, instrumenter) {
158
166
  return tracer.trace('fs.operation', { tags, orphanable }, (span) => {
159
167
  const p = kDirClose.apply(this, arguments)
160
168
  const unwrapBoth = () => {
161
- instrumenter.unwrap(this, kDirReadPromisified)
162
- instrumenter.unwrap(this, kDirClosePromisified)
169
+ shimmer.unwrap(this, kDirReadPromisified)
170
+ shimmer.unwrap(this, kDirClosePromisified)
163
171
  }
164
172
  p.then(unwrapBoth, unwrapBoth)
165
173
  return p
@@ -339,7 +347,7 @@ function makeFSTags (resourceName, path, options, config, tracer) {
339
347
  'component': 'fs',
340
348
  'span.kind': 'internal',
341
349
  'resource.name': resourceName,
342
- 'service.name': config.service || tracer._service
350
+ 'service.name': fsConfig.service || tracer._service
343
351
  }
344
352
 
345
353
  switch (typeof path) {
@@ -399,9 +407,9 @@ function patchClassicFunctions (fs, tracer, config) {
399
407
  if (tagMakerName in tagMakers) {
400
408
  const tagMaker = tagMakers[tagMakerName]
401
409
  if (name.endsWith('Sync')) {
402
- this.wrap(fs, name, createWrap(tracer, config, name, tagMaker))
410
+ shimmer.wrap(fs, name, createWrap(tracer, config, name, tagMaker))
403
411
  } else {
404
- this.wrap(fs, name, createWrapCb(tracer, config, name, tagMaker))
412
+ shimmer.wrap(fs, name, createWrapCb(tracer, config, name, tagMaker))
405
413
  }
406
414
  if (name in promisifiable) {
407
415
  copySymbols(original, fs[name])
@@ -424,8 +432,6 @@ function patchFileHandle (fs, tracer, config) {
424
432
  tagMaker = createFDTags
425
433
  }
426
434
 
427
- const instrumenter = this
428
-
429
435
  const desc = Reflect.getOwnPropertyDescriptor(fileHandlePrototype, kHandle)
430
436
  if (!desc || !desc.get) {
431
437
  Reflect.defineProperty(fileHandlePrototype, kHandle, {
@@ -434,13 +440,13 @@ function patchFileHandle (fs, tracer, config) {
434
440
  },
435
441
  set (h) {
436
442
  this[ddFhSym] = h
437
- instrumenter.wrap(this, 'close', createWrap(tracer, config, 'filehandle.close', tagMakers.close))
443
+ shimmer.wrap(this, 'close', createWrap(tracer, config, 'filehandle.close', tagMakers.close))
438
444
  },
439
445
  configurable: true
440
446
  })
441
447
  }
442
448
 
443
- this.wrap(fileHandlePrototype, name, createWrap(tracer, config, 'filehandle.' + name, tagMaker))
449
+ shimmer.wrap(fileHandlePrototype, name, createWrap(tracer, config, 'filehandle.' + name, tagMaker))
444
450
  }
445
451
  })
446
452
  }
@@ -449,17 +455,17 @@ function patchPromiseFunctions (fs, tracer, config) {
449
455
  for (const name in fs.promises) {
450
456
  if (name in tagMakers) {
451
457
  const tagMaker = tagMakers[name]
452
- this.wrap(fs.promises, name, createWrap(tracer, config, 'promises.' + name, tagMaker))
458
+ shimmer.wrap(fs.promises, name, createWrap(tracer, config, 'promises.' + name, tagMaker))
453
459
  }
454
460
  }
455
461
  }
456
462
 
457
463
  function patchDirFunctions (fs, tracer, config) {
458
- this.wrap(fs.Dir.prototype, 'close', createWrapDirClose(config, tracer))
459
- this.wrap(fs.Dir.prototype, 'closeSync', createWrapDirClose(config, tracer, true))
460
- this.wrap(fs.Dir.prototype, 'read', createWrapDirRead(config, tracer))
461
- this.wrap(fs.Dir.prototype, 'readSync', createWrapDirRead(config, tracer, true))
462
- this.wrap(fs.Dir.prototype, Symbol.asyncIterator, createWrapDirAsyncIterator(config, tracer, this))
464
+ shimmer.wrap(fs.Dir.prototype, 'close', createWrapDirClose(config, tracer))
465
+ shimmer.wrap(fs.Dir.prototype, 'closeSync', createWrapDirClose(config, tracer, true))
466
+ shimmer.wrap(fs.Dir.prototype, 'read', createWrapDirRead(config, tracer))
467
+ shimmer.wrap(fs.Dir.prototype, 'readSync', createWrapDirRead(config, tracer, true))
468
+ shimmer.wrap(fs.Dir.prototype, Symbol.asyncIterator, createWrapDirAsyncIterator(config, tracer, this))
463
469
  }
464
470
 
465
471
  function unpatchClassicFunctions (fs) {
@@ -467,7 +473,7 @@ function unpatchClassicFunctions (fs) {
467
473
  if (!fs[name]) continue
468
474
  const tagMakerName = name.endsWith('Sync') ? name.substr(0, name.length - 4) : name
469
475
  if (tagMakerName in tagMakers) {
470
- this.unwrap(fs, name)
476
+ shimmer.unwrap(fs, name)
471
477
  }
472
478
  }
473
479
  }
@@ -478,7 +484,7 @@ function unpatchFileHandle (fs) {
478
484
  if (typeof name !== 'string' || name === 'constructor' || name === 'fd' || name === 'getAsyncId') {
479
485
  continue
480
486
  }
481
- this.unwrap(fileHandlePrototype, name)
487
+ shimmer.unwrap(fileHandlePrototype, name)
482
488
  }
483
489
  delete fileHandlePrototype[kHandle]
484
490
  })
@@ -487,22 +493,46 @@ function unpatchFileHandle (fs) {
487
493
  function unpatchPromiseFunctions (fs) {
488
494
  for (const name in fs.promises) {
489
495
  if (name in tagMakers) {
490
- this.unwrap(fs.promises, name)
496
+ shimmer.unwrap(fs.promises, name)
491
497
  }
492
498
  }
493
499
  }
494
500
 
495
501
  function unpatchDirFunctions (fs) {
496
- this.unwrap(fs.Dir.prototype, 'close')
497
- this.unwrap(fs.Dir.prototype, 'closeSync')
498
- this.unwrap(fs.Dir.prototype, 'read')
499
- this.unwrap(fs.Dir.prototype, 'readSync')
500
- this.unwrap(fs.Dir.prototype, Symbol.asyncIterator)
502
+ shimmer.unwrap(fs.Dir.prototype, 'close')
503
+ shimmer.unwrap(fs.Dir.prototype, 'closeSync')
504
+ shimmer.unwrap(fs.Dir.prototype, 'read')
505
+ shimmer.unwrap(fs.Dir.prototype, 'readSync')
506
+ shimmer.unwrap(fs.Dir.prototype, Symbol.asyncIterator)
501
507
  }
502
508
 
503
- module.exports = {
504
- name: 'fs',
505
- patch (fs, tracer, config) {
509
+ const hookChannel = channel('apm:fs:hook')
510
+
511
+ hookChannel.subscribe(fs => {
512
+ fsInstance = fs
513
+ })
514
+
515
+ class FsPlugin extends Plugin {
516
+ static get name () {
517
+ return 'fs'
518
+ }
519
+
520
+ configure (config) {
521
+ fsConfig = config
522
+
523
+ super.configure(config)
524
+
525
+ this._unpatch()
526
+
527
+ if (this._enabled) {
528
+ this._patch()
529
+ }
530
+ }
531
+
532
+ _patch () {
533
+ const fs = fsInstance
534
+ const tracer = this.tracer
535
+ const config = this.config
506
536
  const realpathNative = fs.realpath.native
507
537
  const realpathSyncNative = fs.realpathSync.native
508
538
  patchClassicFunctions.call(this, fs, tracer, config)
@@ -513,18 +543,20 @@ module.exports = {
513
543
  if (fs.Dir) {
514
544
  patchDirFunctions.call(this, fs, tracer, config)
515
545
  }
516
- this.wrap(fs, 'createReadStream', createWrapCreateReadStream(config, tracer))
517
- this.wrap(fs, 'createWriteStream', createWrapCreateWriteStream(config, tracer))
518
- this.wrap(fs, 'existsSync', createWrap(tracer, config, 'existsSync', createPathTags))
519
- this.wrap(fs, 'exists', createWrapExists(config, tracer))
546
+ shimmer.wrap(fs, 'createReadStream', createWrapCreateReadStream(config, tracer))
547
+ shimmer.wrap(fs, 'createWriteStream', createWrapCreateWriteStream(config, tracer))
548
+ shimmer.wrap(fs, 'existsSync', createWrap(tracer, config, 'existsSync', createPathTags))
549
+ shimmer.wrap(fs, 'exists', createWrapExists(config, tracer))
520
550
  if (realpathNative) {
521
551
  fs.realpath.native = createWrapCb(tracer, config, 'realpath.native', createPathTags)(realpathNative)
522
552
  }
523
553
  if (realpathSyncNative) {
524
554
  fs.realpathSync.native = createWrap(tracer, config, 'realpath.native', createPathTags)(realpathSyncNative)
525
555
  }
526
- },
527
- unpatch (fs) {
556
+ }
557
+
558
+ _unpatch () {
559
+ const fs = fsInstance
528
560
  unpatchClassicFunctions.call(this, fs)
529
561
  if (fs.promises) {
530
562
  unpatchFileHandle.call(this, fs)
@@ -533,13 +565,15 @@ module.exports = {
533
565
  if (fs.Dir) {
534
566
  unpatchDirFunctions.call(this, fs)
535
567
  }
536
- this.unwrap(fs, 'createReadStream')
537
- this.unwrap(fs, 'createWriteStream')
538
- this.unwrap(fs, 'existsSync')
539
- this.unwrap(fs, 'exists')
568
+ shimmer.unwrap(fs, 'createReadStream')
569
+ shimmer.unwrap(fs, 'createWriteStream')
570
+ shimmer.unwrap(fs, 'existsSync')
571
+ shimmer.unwrap(fs, 'exists')
540
572
  }
541
573
  }
542
574
 
575
+ module.exports = FsPlugin
576
+
543
577
  /** TODO fs functions:
544
578
 
545
579
  unwatchFile
@@ -15,6 +15,9 @@ const {
15
15
  TEST_CODE_OWNERS
16
16
  } = require('../../dd-trace/src/plugins/util/test')
17
17
 
18
+ // https://github.com/facebook/jest/blob/d6ad15b0f88a05816c2fe034dd6900d28315d570/packages/jest-worker/src/types.ts#L38
19
+ const CHILD_MESSAGE_END = 2
20
+
18
21
  function getTestSpanMetadata (tracer, test) {
19
22
  const childOf = getTestParentSpan(tracer)
20
23
 
@@ -38,9 +41,31 @@ class JestPlugin extends Plugin {
38
41
  constructor (...args) {
39
42
  super(...args)
40
43
 
44
+ // Used to handle the end of a jest worker to be able to flush
45
+ const handler = ([message]) => {
46
+ if (message === CHILD_MESSAGE_END) {
47
+ this.tracer._exporter._writer.flush(() => {
48
+ // eslint-disable-next-line
49
+ // https://github.com/facebook/jest/blob/24ed3b5ecb419c023ee6fdbc838f07cc028fc007/packages/jest-worker/src/workers/processChild.ts#L118-L133
50
+ // Only after the flush is done we clean up open handles
51
+ // so the worker process can hopefully exit gracefully
52
+ process.removeListener('message', handler)
53
+ })
54
+ }
55
+ }
56
+ process.on('message', handler)
57
+
41
58
  this.testEnvironmentMetadata = getTestEnvironmentMetadata('jest', this.config)
42
59
  this.codeOwnersEntries = getCodeOwnersFileEntries()
43
60
 
61
+ this.addSub('ci:jest:test:code-coverage', (coverageFiles) => {
62
+ if (!this.config.isAgentlessEnabled || !this.config.isIntelligentTestRunnerEnabled) {
63
+ return
64
+ }
65
+ const testSpan = storage.getStore().span
66
+ this.tracer._exporter.exportCoverage({ testSpan, coverageFiles })
67
+ })
68
+
44
69
  this.addSub('ci:jest:test:start', (test) => {
45
70
  const store = storage.getStore()
46
71
  const span = this.startTestSpan(test)
@@ -55,10 +80,6 @@ class JestPlugin extends Plugin {
55
80
  finishAllTraceSpans(span)
56
81
  })
57
82
 
58
- this.addSub('ci:jest:test-suite:finish', () => {
59
- this.tracer._exporter._writer.flush()
60
- })
61
-
62
83
  this.addSub('ci:jest:test:err', (error) => {
63
84
  if (error) {
64
85
  const span = storage.getStore().span
@@ -14,7 +14,7 @@ class MongodbCorePlugin extends Plugin {
14
14
 
15
15
  this.addSub(`apm:mongodb:query:start`, ({ ns, ops, options, name }) => {
16
16
  const query = getQuery(ops)
17
- const resource = getResource(ns, query, name)
17
+ const resource = truncate(getResource(ns, query, name))
18
18
  const store = storage.getStore()
19
19
  const childOf = store ? store.span : store
20
20
  const span = this.tracer.startSpan('mongodb.query', {
@@ -55,8 +55,8 @@ class MongodbCorePlugin extends Plugin {
55
55
 
56
56
  function getQuery (cmd) {
57
57
  if (!cmd || typeof cmd !== 'object' || Array.isArray(cmd)) return
58
- if (cmd.query) return JSON.stringify(sanitize(cmd.query))
59
- if (cmd.filter) return JSON.stringify(sanitize(cmd.filter))
58
+ if (cmd.query) return JSON.stringify(limitDepth(cmd.query))
59
+ if (cmd.filter) return JSON.stringify(limitDepth(cmd.filter))
60
60
  }
61
61
 
62
62
  function getResource (ns, query, operationName) {
@@ -69,12 +69,25 @@ function getResource (ns, query, operationName) {
69
69
  return parts.join(' ')
70
70
  }
71
71
 
72
+ function truncate (input) {
73
+ return input.slice(0, Math.min(input.length, 10000))
74
+ }
75
+
76
+ function simplify (input) {
77
+ return isBSON(input) ? input.toHexString() : input
78
+ }
79
+
80
+ function shouldSimplify (input) {
81
+ return !isObject(input) || isBSON(input)
82
+ }
83
+
72
84
  function shouldHide (input) {
73
- return !isObject(input) || Buffer.isBuffer(input) || isBSON(input)
85
+ return Buffer.isBuffer(input) || typeof input === 'function'
74
86
  }
75
87
 
76
- function sanitize (input) {
88
+ function limitDepth (input) {
77
89
  if (shouldHide(input)) return '?'
90
+ if (shouldSimplify(input)) return simplify(input)
78
91
 
79
92
  const output = {}
80
93
  const queue = [{
@@ -92,8 +105,10 @@ function sanitize (input) {
92
105
  if (typeof input[key] === 'function') continue
93
106
 
94
107
  const child = input[key]
95
- if (depth >= 20 || shouldHide(child)) {
108
+ if (depth >= 10 || shouldHide(child)) {
96
109
  output[key] = '?'
110
+ } else if (shouldSimplify(child)) {
111
+ output[key] = simplify(child)
97
112
  } else {
98
113
  queue.push({
99
114
  input: child,
@@ -3,6 +3,7 @@
3
3
  const Plugin = require('../../dd-trace/src/plugins/plugin')
4
4
  const { storage } = require('../../datadog-core')
5
5
  const analyticsSampler = require('../../dd-trace/src/analytics_sampler')
6
+ const log = require('../../dd-trace/src/log')
6
7
 
7
8
  class OracledbPlugin extends Plugin {
8
9
  static get name () {
@@ -14,18 +15,25 @@ class OracledbPlugin extends Plugin {
14
15
 
15
16
  this.addSub('apm:oracledb:execute:start', ({ query, connAttrs }) => {
16
17
  const service = getServiceName(this.tracer, this.config, connAttrs)
17
- const connectStringObj = new URL('http://' + connAttrs.connectString)
18
+ let connectStringObj
19
+ try {
20
+ connectStringObj = new URL(`http://${connAttrs.connectString}`)
21
+ } catch (e) {
22
+ log.error(e)
23
+ }
18
24
  const tags = {
19
25
  'span.kind': 'client',
20
26
  'span.type': 'sql',
21
27
  'sql.query': query,
22
- 'db.instance': connectStringObj.pathname.substring(1),
23
- 'db.hostname': connectStringObj.hostname,
24
28
  'db.user': this.config.user,
25
- 'db.port': connectStringObj.port,
26
29
  'resource.name': query,
27
30
  'service.name': service
28
31
  }
32
+ if (typeof connectStringObj !== 'undefined') {
33
+ tags['db.instance'] = connectStringObj.pathname.substring(1)
34
+ tags['db.hostname'] = connectStringObj.hostname
35
+ tags['db.port'] = connectStringObj.port
36
+ }
29
37
  const store = storage.getStore()
30
38
  const childOf = store ? store.span : store
31
39
  const span = this.tracer.startSpan('oracle.query', {
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
 
3
3
  if (!global._ddtrace) {
4
- const TracerProxy = require('./src/proxy')
4
+ const TracerProxy = require('./src')
5
5
 
6
6
  Object.defineProperty(global, '_ddtrace', {
7
7
  value: new TracerProxy(),
@@ -0,0 +1,50 @@
1
+ 'use strict'
2
+ const request = require('../../../exporters/common/request')
3
+ const log = require('../../../log')
4
+
5
+ const { CoverageCIVisibilityEncoder } = require('../../../encode/coverage-ci-visibility')
6
+ const BaseWriter = require('../../../exporters/common/writer')
7
+
8
+ function safeJSONStringify (value) {
9
+ return JSON.stringify(value, (key, value) =>
10
+ key !== 'dd-api-key' ? value : undefined
11
+ )
12
+ }
13
+
14
+ class Writer extends BaseWriter {
15
+ constructor ({ url }) {
16
+ super(...arguments)
17
+ this._url = url
18
+ this._encoder = new CoverageCIVisibilityEncoder()
19
+ }
20
+
21
+ _sendPayload (form, _, done) {
22
+ const options = {
23
+ path: '/api/v2/citestcov',
24
+ method: 'POST',
25
+ headers: {
26
+ 'dd-api-key': process.env.DATADOG_API_KEY || process.env.DD_API_KEY,
27
+ ...form.getHeaders()
28
+ },
29
+ timeout: 15000
30
+ }
31
+
32
+ options.protocol = this._url.protocol
33
+ options.hostname = this._url.hostname
34
+ options.port = this._url.port
35
+
36
+ log.debug(() => `Request to the intake: ${safeJSONStringify(options)}`)
37
+
38
+ request(form, options, (err, res) => {
39
+ if (err) {
40
+ log.error(err)
41
+ done()
42
+ return
43
+ }
44
+ log.debug(`Response from the intake: ${res}`)
45
+ done()
46
+ })
47
+ }
48
+ }
49
+
50
+ module.exports = Writer