dd-trace 5.19.0 → 5.21.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 (67) hide show
  1. package/ext/formats.d.ts +1 -0
  2. package/ext/formats.js +2 -1
  3. package/index.d.ts +2 -1
  4. package/init.js +3 -15
  5. package/package.json +5 -4
  6. package/packages/datadog-instrumentations/src/body-parser.js +14 -2
  7. package/packages/datadog-instrumentations/src/cucumber.js +10 -0
  8. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -2
  9. package/packages/datadog-instrumentations/src/helpers/register.js +21 -12
  10. package/packages/datadog-instrumentations/src/http/client.js +7 -1
  11. package/packages/datadog-instrumentations/src/http/server.js +50 -13
  12. package/packages/datadog-instrumentations/src/mocha/main.js +111 -78
  13. package/packages/datadog-instrumentations/src/nyc.js +23 -0
  14. package/packages/datadog-instrumentations/src/process.js +29 -0
  15. package/packages/datadog-instrumentations/src/vitest.js +65 -25
  16. package/packages/datadog-plugin-aws-sdk/src/base.js +15 -1
  17. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -1
  18. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -1
  19. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +3 -3
  20. package/packages/datadog-plugin-cucumber/src/index.js +12 -2
  21. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +53 -12
  22. package/packages/datadog-plugin-jest/src/index.js +17 -4
  23. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  24. package/packages/datadog-plugin-nyc/src/index.js +35 -0
  25. package/packages/datadog-plugin-playwright/src/index.js +9 -4
  26. package/packages/datadog-plugin-vitest/src/index.js +32 -5
  27. package/packages/dd-trace/src/appsec/blocking.js +10 -1
  28. package/packages/dd-trace/src/appsec/channels.js +4 -1
  29. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  30. package/packages/dd-trace/src/appsec/iast/analyzers/code-injection-analyzer.js +16 -0
  31. package/packages/dd-trace/src/appsec/iast/analyzers/weak-hash-analyzer.js +2 -0
  32. package/packages/dd-trace/src/appsec/iast/taint-tracking/csi-methods.js +2 -1
  33. package/packages/dd-trace/src/appsec/iast/taint-tracking/taint-tracking-impl.js +11 -0
  34. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/code-injection-sensitive-analyzer.js +25 -0
  35. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +2 -0
  36. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-regex.js +2 -2
  37. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  38. package/packages/dd-trace/src/appsec/index.js +12 -7
  39. package/packages/dd-trace/src/appsec/rasp.js +121 -7
  40. package/packages/dd-trace/src/appsec/recommended.json +220 -2
  41. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +40 -1
  42. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -4
  43. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -4
  44. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +8 -7
  45. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -4
  46. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -4
  47. package/packages/dd-trace/src/ci-visibility/telemetry.js +29 -2
  48. package/packages/dd-trace/src/config.js +158 -153
  49. package/packages/dd-trace/src/data_streams.js +44 -0
  50. package/packages/dd-trace/src/datastreams/pathway.js +4 -2
  51. package/packages/dd-trace/src/log/index.js +32 -0
  52. package/packages/dd-trace/src/opentelemetry/context_manager.js +22 -39
  53. package/packages/dd-trace/src/opentelemetry/span_context.js +2 -2
  54. package/packages/dd-trace/src/opentelemetry/tracer.js +23 -14
  55. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +9 -1
  56. package/packages/dd-trace/src/opentracing/propagation/log.js +1 -1
  57. package/packages/dd-trace/src/opentracing/propagation/text_map.js +60 -0
  58. package/packages/dd-trace/src/opentracing/propagation/text_map_dsm.js +43 -0
  59. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  60. package/packages/dd-trace/src/opentracing/tracer.js +10 -6
  61. package/packages/dd-trace/src/plugins/ci_plugin.js +11 -4
  62. package/packages/dd-trace/src/plugins/index.js +1 -0
  63. package/packages/dd-trace/src/plugins/plugin.js +12 -1
  64. package/packages/dd-trace/src/plugins/util/git.js +14 -1
  65. package/packages/dd-trace/src/proxy.js +1 -0
  66. package/packages/dd-trace/src/telemetry/index.js +1 -1
  67. package/packages/dd-trace/src/tracer.js +2 -0
@@ -17,11 +17,13 @@ function shaHash (checkpointString) {
17
17
  }
18
18
 
19
19
  function computeHash (service, env, edgeTags, parentHash) {
20
- const key = `${service}${env}` + edgeTags.join('') + parentHash.toString()
20
+ const hashableEdgeTags = edgeTags.filter(item => item !== 'manual_checkpoint:true')
21
+
22
+ const key = `${service}${env}` + hashableEdgeTags.join('') + parentHash.toString()
21
23
  if (cache.get(key)) {
22
24
  return cache.get(key)
23
25
  }
24
- const currentHash = shaHash(`${service}${env}` + edgeTags.join(''))
26
+ const currentHash = shaHash(`${service}${env}` + hashableEdgeTags.join(''))
25
27
  const buf = Buffer.concat([currentHash, parentHash], 16)
26
28
  const val = shaHash(buf.toString())
27
29
  cache.set(key, val)
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const coalesce = require('koalas')
4
+ const { isTrue } = require('../util')
3
5
  const { debugChannel, infoChannel, warnChannel, errorChannel } = require('./channels')
4
6
  const logWriter = require('./writer')
5
7
 
@@ -20,13 +22,29 @@ function processMsg (msg) {
20
22
  return typeof msg === 'function' ? msg() : msg
21
23
  }
22
24
 
25
+ const config = {
26
+ enabled: false,
27
+ logger: undefined,
28
+ logLevel: 'debug'
29
+ }
30
+
23
31
  const log = {
32
+ /**
33
+ * @returns Read-only version of logging config. To modify config, call `log.use` and `log.toggle`
34
+ */
35
+ getConfig () {
36
+ return { ...config }
37
+ },
38
+
24
39
  use (logger) {
40
+ config.logger = logger
25
41
  logWriter.use(logger)
26
42
  return this
27
43
  },
28
44
 
29
45
  toggle (enabled, logLevel) {
46
+ config.enabled = enabled
47
+ config.logLevel = logLevel
30
48
  logWriter.toggle(enabled, logLevel)
31
49
  return this
32
50
  },
@@ -76,4 +94,18 @@ const log = {
76
94
 
77
95
  log.reset()
78
96
 
97
+ const enabled = isTrue(coalesce(
98
+ process.env.DD_TRACE_DEBUG,
99
+ process.env.OTEL_LOG_LEVEL === 'debug',
100
+ config.enabled
101
+ ))
102
+
103
+ const logLevel = coalesce(
104
+ process.env.DD_TRACE_LOG_LEVEL,
105
+ process.env.OTEL_LOG_LEVEL,
106
+ config.logLevel
107
+ )
108
+
109
+ log.toggle(enabled, logLevel)
110
+
79
111
  module.exports = log
@@ -2,61 +2,46 @@
2
2
 
3
3
  const { AsyncLocalStorage } = require('async_hooks')
4
4
  const { trace, ROOT_CONTEXT } = require('@opentelemetry/api')
5
+ const DataDogSpanContext = require('../opentracing/span_context')
5
6
 
6
7
  const SpanContext = require('./span_context')
7
8
  const tracer = require('../../')
8
9
 
9
- // Horrible hack to acquire the otherwise inaccessible SPAN_KEY so we can redirect it...
10
- // This is used for getting the current span context in OpenTelemetry, but the SPAN_KEY value is
11
- // not exposed as it's meant to be read-only from outside the module. We want to hijack this logic
12
- // so we can instead get the span context from the datadog context manager instead.
13
- let SPAN_KEY
14
- trace.getSpan({
15
- getValue (key) {
16
- SPAN_KEY = key
17
- }
18
- })
19
-
20
- // Whenever a value is acquired from the context map we should mostly delegate to the real getter,
21
- // but when accessing the current span we should hijack that access to instead provide a fake span
22
- // which we can use to get an OTel span context wrapping the datadog active scope span context.
23
- function wrappedGetValue (target) {
24
- return (key) => {
25
- if (key === SPAN_KEY) {
26
- return {
27
- spanContext () {
28
- const activeSpan = tracer.scope().active()
29
- const context = activeSpan && activeSpan.context()
30
- return new SpanContext(context)
31
- }
32
- }
33
- }
34
- return target.getValue(key)
35
- }
36
- }
37
-
38
10
  class ContextManager {
39
11
  constructor () {
40
12
  this._store = new AsyncLocalStorage()
41
13
  }
42
14
 
43
15
  active () {
44
- const active = this._store.getStore() || ROOT_CONTEXT
16
+ const activeSpan = tracer.scope().active()
17
+ const store = this._store.getStore()
18
+ const context = (activeSpan && activeSpan.context()) || store || ROOT_CONTEXT
45
19
 
46
- return new Proxy(active, {
47
- get (target, key) {
48
- return key === 'getValue' ? wrappedGetValue(target) : target[key]
49
- }
50
- })
20
+ if (!(context instanceof DataDogSpanContext)) {
21
+ return context
22
+ }
23
+
24
+ if (!context._otelSpanContext) {
25
+ const newSpanContext = new SpanContext(context)
26
+ context._otelSpanContext = newSpanContext
27
+ }
28
+ if (store && trace.getSpanContext(store) === context._otelSpanContext) {
29
+ return store
30
+ }
31
+ return trace.setSpanContext(store || ROOT_CONTEXT, context._otelSpanContext)
51
32
  }
52
33
 
53
34
  with (context, fn, thisArg, ...args) {
54
35
  const span = trace.getSpan(context)
55
36
  const ddScope = tracer.scope()
56
- return ddScope.activate(span._ddSpan, () => {
37
+ const run = () => {
57
38
  const cb = thisArg == null ? fn : fn.bind(thisArg)
58
39
  return this._store.run(context, cb, ...args)
59
- })
40
+ }
41
+ if (span && span._ddSpan) {
42
+ return ddScope.activate(span._ddSpan, run)
43
+ }
44
+ return run()
60
45
  }
61
46
 
62
47
  bind (context, target) {
@@ -66,9 +51,7 @@ class ContextManager {
66
51
  }
67
52
  }
68
53
 
69
- // Not part of the spec but the Node.js API expects these
70
54
  enable () {}
71
55
  disable () {}
72
56
  }
73
-
74
57
  module.exports = ContextManager
@@ -24,11 +24,11 @@ class SpanContext {
24
24
  }
25
25
 
26
26
  get traceId () {
27
- return this._ddContext._traceId.toString(16)
27
+ return this._ddContext.toTraceId(true)
28
28
  }
29
29
 
30
30
  get spanId () {
31
- return this._ddContext._spanId.toString(16)
31
+ return this._ddContext.toSpanId(true)
32
32
  }
33
33
 
34
34
  get traceFlags () {
@@ -7,6 +7,7 @@ const Sampler = require('./sampler')
7
7
  const Span = require('./span')
8
8
  const id = require('../id')
9
9
  const SpanContext = require('./span_context')
10
+ const TextMapPropagator = require('../opentracing/propagation/text_map')
10
11
 
11
12
  class Tracer {
12
13
  constructor (library, config, tracerProvider) {
@@ -22,6 +23,24 @@ class Tracer {
22
23
  return this._tracerProvider.resource
23
24
  }
24
25
 
26
+ _createSpanContextFromParent (parentSpanContext) {
27
+ return new SpanContext({
28
+ traceId: parentSpanContext._traceId,
29
+ spanId: id(),
30
+ parentId: parentSpanContext._spanId,
31
+ sampling: parentSpanContext._sampling,
32
+ baggageItems: Object.assign({}, parentSpanContext._baggageItems),
33
+ trace: parentSpanContext._trace,
34
+ tracestate: parentSpanContext._tracestate
35
+ })
36
+ }
37
+
38
+ // Extracted method to create span context for a new span
39
+ _createSpanContextForNewSpan (context) {
40
+ const { traceId, spanId, traceFlags, traceState } = context
41
+ return TextMapPropagator._convertOtelContextToDatadog(traceId, spanId, traceFlags, traceState)
42
+ }
43
+
25
44
  startSpan (name, options = {}, context = api.context.active()) {
26
45
  // remove span from context in case a root span is requested via options
27
46
  if (options.root) {
@@ -29,21 +48,11 @@ class Tracer {
29
48
  }
30
49
  const parentSpan = api.trace.getSpan(context)
31
50
  const parentSpanContext = parentSpan && parentSpan.spanContext()
32
-
33
51
  let spanContext
34
- // TODO: Need a way to get 128-bit trace IDs for the validity check API to work...
35
- // if (parent && api.trace.isSpanContextValid(parent)) {
36
- if (parentSpanContext && parentSpanContext.traceId) {
37
- const parent = parentSpanContext._ddContext
38
- spanContext = new SpanContext({
39
- traceId: parent._traceId,
40
- spanId: id(),
41
- parentId: parent._spanId,
42
- sampling: parent._sampling,
43
- baggageItems: Object.assign({}, parent._baggageItems),
44
- trace: parent._trace,
45
- tracestate: parent._tracestate
46
- })
52
+ if (parentSpanContext && api.trace.isSpanContextValid(parentSpanContext)) {
53
+ spanContext = parentSpanContext._ddContext
54
+ ? this._createSpanContextFromParent(parentSpanContext._ddContext)
55
+ : this._createSpanContextForNewSpan(parentSpanContext)
47
56
  } else {
48
57
  spanContext = new SpanContext()
49
58
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const { trace, context } = require('@opentelemetry/api')
3
+ const { trace, context, propagation } = require('@opentelemetry/api')
4
+ const { W3CTraceContextPropagator } = require('@opentelemetry/core')
4
5
 
5
6
  const tracer = require('../../')
6
7
 
@@ -52,6 +53,13 @@ class TracerProvider {
52
53
  if (!trace.setGlobalTracerProvider(this)) {
53
54
  trace.getTracerProvider().setDelegate(this)
54
55
  }
56
+ // The default propagator used is the W3C Trace Context propagator, users should be able to pass in others
57
+ // as needed
58
+ if (config.propagator) {
59
+ propagation.setGlobalPropagator(config.propagator)
60
+ } else {
61
+ propagation.setGlobalPropagator(new W3CTraceContextPropagator())
62
+ }
55
63
  }
56
64
 
57
65
  forceFlush () {
@@ -15,7 +15,7 @@ class LogPropagator {
15
15
 
16
16
  if (spanContext) {
17
17
  if (this._config.traceId128BitLoggingEnabled && spanContext._trace.tags['_dd.p.tid']) {
18
- carrier.dd.trace_id = spanContext._trace.tags['_dd.p.tid'] + spanContext._traceId.toString(16)
18
+ carrier.dd.trace_id = spanContext.toTraceId(true)
19
19
  } else {
20
20
  carrier.dd.trace_id = spanContext.toTraceId()
21
21
  }
@@ -3,6 +3,7 @@
3
3
  const pick = require('../../../../datadog-core/src/utils/src/pick')
4
4
  const id = require('../../id')
5
5
  const DatadogSpanContext = require('../span_context')
6
+ const OtelSpanContext = require('../../opentelemetry/span_context')
6
7
  const log = require('../../log')
7
8
  const TraceState = require('./tracestate')
8
9
  const tags = require('../../../../../ext/tags')
@@ -618,6 +619,65 @@ class TextMapPropagator {
618
619
 
619
620
  return spanContext._traceId.toString(16)
620
621
  }
622
+
623
+ static _convertOtelContextToDatadog (traceId, spanId, traceFlag, ts, meta = {}) {
624
+ const origin = null
625
+ let samplingPriority = traceFlag
626
+
627
+ ts = ts?.traceparent || null
628
+
629
+ if (ts) {
630
+ // Use TraceState.fromString to parse the tracestate header
631
+ const traceState = TraceState.fromString(ts)
632
+ let ddTraceStateData = null
633
+
634
+ // Extract Datadog specific trace state data
635
+ traceState.forVendor('dd', (state) => {
636
+ ddTraceStateData = state
637
+ return state // You might need to adjust this part based on actual logic needed
638
+ })
639
+
640
+ if (ddTraceStateData) {
641
+ // Assuming ddTraceStateData is now a Map or similar structure containing Datadog trace state data
642
+ // Extract values as needed, similar to the original logic
643
+ const samplingPriorityTs = ddTraceStateData.get('s')
644
+ const origin = ddTraceStateData.get('o')
645
+ // Convert Map to object for meta
646
+ const otherPropagatedTags = Object.fromEntries(ddTraceStateData.entries())
647
+
648
+ // Update meta and samplingPriority based on extracted values
649
+ Object.assign(meta, otherPropagatedTags)
650
+ samplingPriority = TextMapPropagator._getSamplingPriority(traceFlag, parseInt(samplingPriorityTs, 10), origin)
651
+ } else {
652
+ log.debug(`no dd list member in tracestate from incoming request: ${ts}`)
653
+ }
654
+ }
655
+
656
+ const spanContext = new OtelSpanContext({
657
+ traceId: id(traceId, 16), spanId: id(), tags: meta, parentId: id(spanId, 16)
658
+ })
659
+
660
+ spanContext._sampling = { priority: samplingPriority }
661
+ spanContext._trace = { origin }
662
+ return spanContext
663
+ }
664
+
665
+ static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin = null) {
666
+ const fromRumWithoutPriority = !tracestateSamplingPriority && origin === 'rum'
667
+
668
+ let samplingPriority
669
+ if (!fromRumWithoutPriority && traceparentSampled === 0 &&
670
+ (!tracestateSamplingPriority || tracestateSamplingPriority >= 0)) {
671
+ samplingPriority = 0
672
+ } else if (!fromRumWithoutPriority && traceparentSampled === 1 &&
673
+ (!tracestateSamplingPriority || tracestateSamplingPriority < 0)) {
674
+ samplingPriority = 1
675
+ } else {
676
+ samplingPriority = tracestateSamplingPriority
677
+ }
678
+
679
+ return samplingPriority
680
+ }
621
681
  }
622
682
 
623
683
  module.exports = TextMapPropagator
@@ -0,0 +1,43 @@
1
+ const pick = require('../../../../datadog-core/src/utils/src/pick')
2
+ const log = require('../../log')
3
+
4
+ const { DsmPathwayCodec } = require('../../datastreams/pathway')
5
+
6
+ const base64Key = 'dd-pathway-ctx-base64'
7
+ const logKeys = [base64Key]
8
+
9
+ class DSMTextMapPropagator {
10
+ constructor (config) {
11
+ this.config = config
12
+ }
13
+
14
+ inject (ctx, carrier) {
15
+ if (!this.config.dsmEnabled) return
16
+
17
+ this._injectDatadogDSMContext(ctx, carrier)
18
+
19
+ log.debug(() => `Inject into carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
20
+ }
21
+
22
+ extract (carrier) {
23
+ if (!this.config.dsmEnabled) return
24
+
25
+ const dsmContext = this._extractDatadogDSMContext(carrier)
26
+
27
+ if (!dsmContext) return dsmContext
28
+
29
+ log.debug(() => `Extract from carrier (DSM): ${JSON.stringify(pick(carrier, logKeys))}.`)
30
+ return dsmContext
31
+ }
32
+
33
+ _injectDatadogDSMContext (ctx, carrier) {
34
+ DsmPathwayCodec.encode(ctx, carrier)
35
+ }
36
+
37
+ _extractDatadogDSMContext (carrier) {
38
+ const ctx = DsmPathwayCodec.decode(carrier)
39
+ return ctx
40
+ }
41
+ }
42
+
43
+ module.exports = DSMTextMapPropagator
@@ -27,6 +27,7 @@ class DatadogSpanContext {
27
27
  finished: [],
28
28
  tags: {}
29
29
  }
30
+ this._otelSpanContext = undefined
30
31
  }
31
32
 
32
33
  toTraceId (get128bitId = false) {
@@ -5,6 +5,7 @@ const Span = require('./span')
5
5
  const SpanProcessor = require('../span_processor')
6
6
  const PrioritySampler = require('../priority_sampler')
7
7
  const TextMapPropagator = require('./propagation/text_map')
8
+ const DSMTextMapPropagator = require('./propagation/text_map_dsm')
8
9
  const HttpPropagator = require('./propagation/http')
9
10
  const BinaryPropagator = require('./propagation/binary')
10
11
  const LogPropagator = require('./propagation/log')
@@ -38,7 +39,8 @@ class DatadogTracer {
38
39
  [formats.TEXT_MAP]: new TextMapPropagator(config),
39
40
  [formats.HTTP_HEADERS]: new HttpPropagator(config),
40
41
  [formats.BINARY]: new BinaryPropagator(config),
41
- [formats.LOG]: new LogPropagator(config)
42
+ [formats.LOG]: new LogPropagator(config),
43
+ [formats.TEXT_MAP_DSM]: new DSMTextMapPropagator(config)
42
44
  }
43
45
  if (config.reportHostname) {
44
46
  this._hostname = os.hostname()
@@ -71,14 +73,16 @@ class DatadogTracer {
71
73
  return span
72
74
  }
73
75
 
74
- inject (spanContext, format, carrier) {
75
- if (spanContext instanceof Span) {
76
- spanContext = spanContext.context()
76
+ inject (context, format, carrier) {
77
+ if (context instanceof Span) {
78
+ context = context.context()
77
79
  }
78
80
 
79
81
  try {
80
- this._prioritySampler.sample(spanContext)
81
- this._propagators[format].inject(spanContext, carrier)
82
+ if (format !== 'text_map_dsm') {
83
+ this._prioritySampler.sample(context)
84
+ }
85
+ this._propagators[format].inject(context, carrier)
82
86
  } catch (e) {
83
87
  log.error(e)
84
88
  runtimeMetrics.increment('datadog.tracer.node.inject.errors', true)
@@ -16,7 +16,8 @@ const {
16
16
  getTestSuiteCommonTags,
17
17
  TEST_STATUS,
18
18
  TEST_SKIPPED_BY_ITR,
19
- ITR_CORRELATION_ID
19
+ ITR_CORRELATION_ID,
20
+ TEST_SOURCE_FILE
20
21
  } = require('./util/test')
21
22
  const Plugin = require('./plugin')
22
23
  const { COMPONENT } = require('../constants')
@@ -144,7 +145,7 @@ module.exports = class CiPlugin extends Plugin {
144
145
  incrementCountMetric(name, {
145
146
  testLevel,
146
147
  testFramework,
147
- isUnsupportedCIProvider: this.isUnsupportedCIProvider,
148
+ isUnsupportedCIProvider: !this.ciProviderName,
148
149
  ...tags
149
150
  })
150
151
  },
@@ -178,7 +179,7 @@ module.exports = class CiPlugin extends Plugin {
178
179
 
179
180
  this.codeOwnersEntries = getCodeOwnersFileEntries(repositoryRoot)
180
181
 
181
- this.isUnsupportedCIProvider = !ciProviderName
182
+ this.ciProviderName = ciProviderName
182
183
 
183
184
  this.testConfiguration = {
184
185
  repositoryUrl,
@@ -207,7 +208,13 @@ module.exports = class CiPlugin extends Plugin {
207
208
  ...extraTags
208
209
  }
209
210
 
210
- const codeOwners = getCodeOwnersForFilename(testSuite, this.codeOwnersEntries)
211
+ const { [TEST_SOURCE_FILE]: testSourceFile } = extraTags
212
+ // We'll try with the test source file if available (it could be different from the test suite)
213
+ let codeOwners = getCodeOwnersForFilename(testSourceFile, this.codeOwnersEntries)
214
+ if (!codeOwners) {
215
+ codeOwners = getCodeOwnersForFilename(testSuite, this.codeOwnersEntries)
216
+ }
217
+
211
218
  if (codeOwners) {
212
219
  testTags[TEST_CODE_OWNERS] = codeOwners
213
220
  }
@@ -69,6 +69,7 @@ module.exports = {
69
69
  get 'node:http2' () { return require('../../../datadog-plugin-http2/src') },
70
70
  get 'node:https' () { return require('../../../datadog-plugin-http/src') },
71
71
  get 'node:net' () { return require('../../../datadog-plugin-net/src') },
72
+ get nyc () { return require('../../../datadog-plugin-nyc/src') },
72
73
  get oracledb () { return require('../../../datadog-plugin-oracledb/src') },
73
74
  get openai () { return require('../../../datadog-plugin-openai/src') },
74
75
  get paperplane () { return require('../../../datadog-plugin-paperplane/src') },
@@ -3,6 +3,7 @@
3
3
  // TODO: move anything related to tracing to TracingPlugin instead
4
4
 
5
5
  const dc = require('dc-polyfill')
6
+ const logger = require('../log')
6
7
  const { storage } = require('../../../datadog-core')
7
8
 
8
9
  class Subscription {
@@ -72,7 +73,17 @@ module.exports = class Plugin {
72
73
  }
73
74
 
74
75
  addSub (channelName, handler) {
75
- this._subscriptions.push(new Subscription(channelName, handler))
76
+ const plugin = this
77
+ const wrappedHandler = function () {
78
+ try {
79
+ return handler.apply(this, arguments)
80
+ } catch (e) {
81
+ logger.error('Error in plugin handler:', e)
82
+ logger.info('Disabling plugin:', plugin.id)
83
+ plugin.configure(false)
84
+ }
85
+ }
86
+ this._subscriptions.push(new Subscription(channelName, wrappedHandler))
76
87
  }
77
88
 
78
89
  addBind (channelName, transform) {
@@ -77,6 +77,18 @@ function isDirectory (path) {
77
77
  }
78
78
  }
79
79
 
80
+ function isGitAvailable () {
81
+ const isWindows = os.platform() === 'win32'
82
+ const command = isWindows ? 'where' : 'which'
83
+ try {
84
+ cp.execFileSync(command, ['git'], { stdio: 'pipe' })
85
+ return true
86
+ } catch (e) {
87
+ incrementCountMetric(TELEMETRY_GIT_COMMAND_ERRORS, { command: 'check_git', exitCode: 'missing' })
88
+ return false
89
+ }
90
+ }
91
+
80
92
  function isShallowRepository () {
81
93
  return sanitizedExec(
82
94
  'git',
@@ -342,5 +354,6 @@ module.exports = {
342
354
  getCommitsRevList,
343
355
  GIT_REV_LIST_MAX_BUFFER,
344
356
  isShallowRepository,
345
- unshallowRepository
357
+ unshallowRepository,
358
+ isGitAvailable
346
359
  }
@@ -181,6 +181,7 @@ class Tracer extends NoopProxy {
181
181
  if (!this._tracingInitialized) {
182
182
  const prioritySampler = appsecStandalone.configure(config)
183
183
  this._tracer = new DatadogTracer(config, prioritySampler)
184
+ this.dataStreamsCheckpointer = this._tracer.dataStreamsCheckpointer
184
185
  this.appsec = new AppsecSdk(this._tracer, config)
185
186
  this._tracingInitialized = true
186
187
  }
@@ -317,7 +317,7 @@ function updateConfig (changes, config) {
317
317
  'sampler.rules': 'DD_TRACE_SAMPLING_RULES'
318
318
  }
319
319
 
320
- const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping'])
320
+ const namesNeedFormatting = new Set(['DD_TAGS', 'peerServiceMapping', 'serviceMapping'])
321
321
 
322
322
  const configuration = []
323
323
  const names = [] // list of config names whose values have been changed
@@ -11,6 +11,7 @@ const { DataStreamsProcessor } = require('./datastreams/processor')
11
11
  const { DsmPathwayCodec } = require('./datastreams/pathway')
12
12
  const { DD_MAJOR } = require('../../../version')
13
13
  const DataStreamsContext = require('./data_streams_context')
14
+ const { DataStreamsCheckpointer } = require('./data_streams')
14
15
  const { flushStartupLogs } = require('../../datadog-instrumentations/src/check_require_cache')
15
16
  const log = require('./log/writer')
16
17
 
@@ -23,6 +24,7 @@ class DatadogTracer extends Tracer {
23
24
  constructor (config, prioritySampler) {
24
25
  super(config, prioritySampler)
25
26
  this._dataStreamsProcessor = new DataStreamsProcessor(config)
27
+ this.dataStreamsCheckpointer = new DataStreamsCheckpointer(this)
26
28
  this._scope = new Scope()
27
29
  setStartupLogConfig(config)
28
30
  flushStartupLogs(log)