dd-trace 5.98.0 → 5.99.1

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 (139) hide show
  1. package/LICENSE-3rdparty.csv +0 -1
  2. package/ext/tags.js +1 -0
  3. package/index.d.ts +9 -1
  4. package/package.json +68 -47
  5. package/packages/datadog-instrumentations/src/crypto.js +45 -0
  6. package/packages/datadog-instrumentations/src/cypress-config.js +122 -16
  7. package/packages/datadog-instrumentations/src/dns.js +24 -56
  8. package/packages/datadog-instrumentations/src/graphql.js +1 -1
  9. package/packages/datadog-instrumentations/src/helpers/callback-instrumentor.js +74 -0
  10. package/packages/datadog-instrumentations/src/helpers/check-require-cache.js +4 -1
  11. package/packages/datadog-instrumentations/src/helpers/hooks.js +2 -0
  12. package/packages/datadog-instrumentations/src/helpers/rewriter/compiler.js +10 -3
  13. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/index.js +1 -0
  14. package/packages/datadog-instrumentations/src/helpers/rewriter/instrumentations/modelcontextprotocol-sdk.js +59 -0
  15. package/packages/datadog-instrumentations/src/helpers/rewriter/transforms.js +11 -2
  16. package/packages/datadog-instrumentations/src/jest.js +5 -5
  17. package/packages/datadog-instrumentations/src/modelcontextprotocol-sdk.js +7 -0
  18. package/packages/datadog-instrumentations/src/pino.js +4 -28
  19. package/packages/datadog-instrumentations/src/playwright-browser-scripts.js +27 -0
  20. package/packages/datadog-instrumentations/src/playwright.js +5 -17
  21. package/packages/datadog-instrumentations/src/stripe.js +38 -24
  22. package/packages/datadog-instrumentations/src/vitest.js +32 -4
  23. package/packages/datadog-instrumentations/src/zlib.js +29 -0
  24. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -2
  25. package/packages/datadog-plugin-azure-event-hubs/src/producer.js +8 -15
  26. package/packages/datadog-plugin-azure-service-bus/src/producer.js +4 -9
  27. package/packages/datadog-plugin-cucumber/src/index.js +2 -2
  28. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +5 -5
  29. package/packages/datadog-plugin-cypress/src/source-map-utils.js +48 -1
  30. package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -1
  31. package/packages/datadog-plugin-graphql/src/utils.js +2 -2
  32. package/packages/datadog-plugin-http/src/server.js +11 -11
  33. package/packages/datadog-plugin-jest/src/index.js +2 -2
  34. package/packages/datadog-plugin-memcached/src/index.js +1 -1
  35. package/packages/datadog-plugin-mocha/src/index.js +1 -2
  36. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/index.js +24 -0
  37. package/packages/datadog-plugin-modelcontextprotocol-sdk/src/tracing.js +55 -0
  38. package/packages/datadog-plugin-mongodb-core/src/index.js +1 -6
  39. package/packages/datadog-plugin-playwright/src/index.js +2 -3
  40. package/packages/datadog-plugin-vitest/src/index.js +14 -6
  41. package/packages/datadog-plugin-ws/src/close.js +2 -0
  42. package/packages/datadog-plugin-ws/src/producer.js +2 -0
  43. package/packages/datadog-plugin-ws/src/receiver.js +1 -0
  44. package/packages/dd-trace/src/aiguard/channels.js +8 -0
  45. package/packages/dd-trace/src/aiguard/index.js +7 -3
  46. package/packages/dd-trace/src/aiguard/sdk.js +44 -0
  47. package/packages/dd-trace/src/aiguard/tags.js +1 -0
  48. package/packages/dd-trace/src/appsec/blocking.js +18 -6
  49. package/packages/dd-trace/src/appsec/graphql.js +7 -7
  50. package/packages/dd-trace/src/appsec/index.js +9 -11
  51. package/packages/dd-trace/src/appsec/rasp/command_injection.js +4 -5
  52. package/packages/dd-trace/src/appsec/rasp/lfi.js +8 -4
  53. package/packages/dd-trace/src/appsec/rasp/sql_injection.js +5 -10
  54. package/packages/dd-trace/src/appsec/rasp/ssrf.js +5 -6
  55. package/packages/dd-trace/src/appsec/recommended.json +2438 -13
  56. package/packages/dd-trace/src/appsec/reporter.js +6 -5
  57. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +4 -8
  58. package/packages/dd-trace/src/appsec/store.js +50 -0
  59. package/packages/dd-trace/src/appsec/waf/index.js +3 -5
  60. package/packages/dd-trace/src/baggage.js +16 -13
  61. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +2 -2
  62. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -2
  63. package/packages/dd-trace/src/ci-visibility/exporters/agentless/di-logs-writer.js +2 -2
  64. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -2
  65. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +1 -1
  66. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +3 -4
  67. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -2
  68. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +4 -5
  69. package/packages/dd-trace/src/ci-visibility/requests/fs-cache.js +3 -4
  70. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +6 -6
  71. package/packages/dd-trace/src/ci-visibility/requests/upload-coverage-report.js +2 -2
  72. package/packages/dd-trace/src/ci-visibility/test-management/get-test-management-tests.js +2 -2
  73. package/packages/dd-trace/src/config/config-types.d.ts +0 -4
  74. package/packages/dd-trace/src/config/defaults.js +10 -10
  75. package/packages/dd-trace/src/config/generated-config-types.d.ts +39 -38
  76. package/packages/dd-trace/src/config/index.js +29 -39
  77. package/packages/dd-trace/src/config/parsers.js +26 -9
  78. package/packages/dd-trace/src/config/supported-configurations.json +46 -78
  79. package/packages/dd-trace/src/debugger/config.js +2 -0
  80. package/packages/dd-trace/src/debugger/devtools_client/send.js +25 -5
  81. package/packages/dd-trace/src/dogstatsd.js +5 -8
  82. package/packages/dd-trace/src/encode/0.4.js +4 -5
  83. package/packages/dd-trace/src/exporter.js +1 -1
  84. package/packages/dd-trace/src/exporters/agent/index.js +0 -1
  85. package/packages/dd-trace/src/exporters/agent/writer.js +1 -2
  86. package/packages/dd-trace/src/exporters/agentless/writer.js +3 -3
  87. package/packages/dd-trace/src/exporters/common/util.js +2 -2
  88. package/packages/dd-trace/src/git_metadata_tagger.js +1 -1
  89. package/packages/dd-trace/src/id.js +2 -0
  90. package/packages/dd-trace/src/index.js +2 -5
  91. package/packages/dd-trace/src/lambda/handler.js +1 -3
  92. package/packages/dd-trace/src/llmobs/constants/tags.js +3 -0
  93. package/packages/dd-trace/src/llmobs/plugins/{anthropic.js → anthropic/index.js} +5 -63
  94. package/packages/dd-trace/src/llmobs/plugins/anthropic/util.js +106 -0
  95. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chain.js +3 -2
  96. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/chat_model.js +3 -2
  97. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/embedding.js +2 -1
  98. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/index.js +0 -49
  99. package/packages/dd-trace/src/llmobs/plugins/langchain/handlers/vectorstore.js +2 -1
  100. package/packages/dd-trace/src/llmobs/plugins/langchain/messages.js +76 -0
  101. package/packages/dd-trace/src/llmobs/plugins/langgraph/index.js +1 -26
  102. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/index.js +68 -0
  103. package/packages/dd-trace/src/llmobs/plugins/modelcontextprotocol-sdk/utils.js +57 -0
  104. package/packages/dd-trace/src/llmobs/sdk.js +23 -3
  105. package/packages/dd-trace/src/llmobs/span_processor.js +14 -1
  106. package/packages/dd-trace/src/llmobs/writers/base.js +7 -1
  107. package/packages/dd-trace/src/llmobs/writers/spans.js +1 -1
  108. package/packages/dd-trace/src/openfeature/eval-metrics-hook.js +103 -0
  109. package/packages/dd-trace/src/openfeature/flagging_provider.js +3 -0
  110. package/packages/dd-trace/src/opentelemetry/logs/index.js +6 -6
  111. package/packages/dd-trace/src/opentelemetry/logs/otlp_http_log_exporter.js +3 -2
  112. package/packages/dd-trace/src/opentelemetry/metrics/index.js +7 -7
  113. package/packages/dd-trace/src/opentelemetry/metrics/otlp_http_metric_exporter.js +3 -2
  114. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +19 -66
  115. package/packages/dd-trace/src/opentelemetry/trace/index.js +11 -16
  116. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +11 -3
  117. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +51 -41
  118. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -11
  119. package/packages/dd-trace/src/opentracing/propagation/text_map.js +30 -23
  120. package/packages/dd-trace/src/opentracing/span.js +2 -2
  121. package/packages/dd-trace/src/opentracing/tracer.js +12 -5
  122. package/packages/dd-trace/src/plugin_manager.js +6 -6
  123. package/packages/dd-trace/src/plugins/index.js +1 -0
  124. package/packages/dd-trace/src/plugins/log_plugin.js +1 -1
  125. package/packages/dd-trace/src/plugins/util/test.js +128 -7
  126. package/packages/dd-trace/src/plugins/util/url.js +2 -1
  127. package/packages/dd-trace/src/profiling/profilers/event_plugins/crypto.js +32 -0
  128. package/packages/dd-trace/src/profiling/profilers/event_plugins/zlib.js +19 -0
  129. package/packages/dd-trace/src/profiling/profilers/events.js +35 -0
  130. package/packages/dd-trace/src/proxy.js +8 -14
  131. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +2 -2
  132. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +4 -0
  133. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +4 -0
  134. package/packages/dd-trace/src/span_processor.js +1 -2
  135. package/packages/dd-trace/src/tagger.js +2 -2
  136. package/packages/dd-trace/src/telemetry/send-data.js +5 -7
  137. package/packages/dd-trace/src/tracer.js +2 -2
  138. package/vendor/dist/ignore/LICENSE +0 -21
  139. package/vendor/dist/ignore/index.js +0 -1
@@ -81,10 +81,10 @@ class Tracer {
81
81
  }
82
82
 
83
83
  _convertOtelContextToDatadog (traceId, spanId, traceFlag, ts, meta = {}) {
84
- const origin = null
84
+ let origin = null
85
85
  let samplingPriority = traceFlag
86
86
 
87
- ts = ts?.traceparent || null
87
+ ts = ts?.traceparent
88
88
 
89
89
  if (ts) {
90
90
  // Use TraceState.fromString to parse the tracestate header
@@ -101,19 +101,17 @@ class Tracer {
101
101
  // Assuming ddTraceStateData is now a Map or similar structure containing Datadog trace state data
102
102
  // Extract values as needed, similar to the original logic
103
103
  const samplingPriorityTs = ddTraceStateData.get('s')
104
- const origin = ddTraceStateData.get('o')
104
+ origin = ddTraceStateData.get('o') ?? null
105
105
  // Convert Map to object for meta
106
106
  const otherPropagatedTags = Object.fromEntries(ddTraceStateData.entries())
107
107
 
108
108
  // Update meta and samplingPriority based on extracted values
109
109
  Object.assign(meta, otherPropagatedTags)
110
- samplingPriority = TextMapPropagator._getSamplingPriority(
111
- traceFlag,
112
- Number.parseInt(samplingPriorityTs, 10),
113
- origin
114
- )
110
+ // Guard against an undefined/empty `s:` field that would result in NaN.
111
+ const tracestateSamplingPriority = samplingPriorityTs ? Math.trunc(samplingPriorityTs) : undefined
112
+ samplingPriority = TextMapPropagator._getSamplingPriority(traceFlag, tracestateSamplingPriority, origin)
115
113
  } else {
116
- log.debug('no dd list member in tracestate from incoming request:', ts)
114
+ log.debug('No dd list member in tracestate from incoming request:', ts)
117
115
  }
118
116
  }
119
117
 
@@ -121,8 +119,8 @@ class Tracer {
121
119
  traceId: id(traceId, 16), spanId: id(), tags: meta, parentId: id(spanId, 16),
122
120
  })
123
121
 
124
- spanContext._sampling = { priority: samplingPriority }
125
- spanContext._trace = { origin }
122
+ spanContext._ddContext._sampling = { priority: samplingPriority }
123
+ spanContext._ddContext._trace = { ...spanContext._ddContext._trace, origin }
126
124
  return spanContext
127
125
  }
128
126
 
@@ -64,6 +64,7 @@ const tracestateTagValueFilter = /[^\x20-\x2B\x2D-\x3A\x3C-\x7D]/g
64
64
  const invalidSegment = /^0+$/
65
65
  const zeroTraceId = '0000000000000000'
66
66
  const hex16 = /^[0-9A-Fa-f]{16}$/
67
+ const percentByte = /%([0-9A-Fa-f]{2})/g
67
68
 
68
69
  class TextMapPropagator {
69
70
  #extractB3Context
@@ -173,15 +174,15 @@ class TextMapPropagator {
173
174
  const baggageItems = getAllBaggageItems()
174
175
  if (!baggageItems) return
175
176
  for (const [key, value] of Object.entries(baggageItems)) {
176
- const baggageKey = String(key).trim()
177
- if (!baggageKey || !baggageTokenExpr.test(baggageKey)) continue
177
+ const baggageKey = key.trim()
178
+ if (!baggageTokenExpr.test(baggageKey)) continue
178
179
 
179
180
  // Do not trim values. If callers include leading/trailing whitespace, it must be percent-encoded.
180
181
  // W3C list-member allows optional properties after ';'.
181
182
  // https://www.w3.org/TR/baggage/#header-content
182
- const item = `${baggageKey}=${encodeURIComponent(String(value))},`
183
+ const item = `${baggageKey}=${encodeURIComponent(value)},`
183
184
  itemCounter += 1
184
- byteCounter += Buffer.byteLength(item)
185
+ byteCounter += item.length
185
186
 
186
187
  // Check for item count limit exceeded
187
188
  if (itemCounter > this._config.baggageMaxItems) {
@@ -209,7 +210,7 @@ class TextMapPropagator {
209
210
  _injectTags (spanContext, carrier) {
210
211
  const trace = spanContext._trace
211
212
 
212
- if (this._config.tagsHeaderMaxLength === 0) {
213
+ if (this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
213
214
  log.debug('Trace tag propagation is disabled, skipping injection.')
214
215
  return
215
216
  }
@@ -228,7 +229,7 @@ class TextMapPropagator {
228
229
 
229
230
  const header = tags.join(',')
230
231
 
231
- if (header.length > this._config.tagsHeaderMaxLength) {
232
+ if (header.length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
232
233
  log.error('Trace tags from span are too large, skipping injection.')
233
234
  } else if (header) {
234
235
  carrier[tagsKey] = header
@@ -387,7 +388,7 @@ class TextMapPropagator {
387
388
  if (context === null) {
388
389
  context = extractedContext
389
390
  style = extractor
390
- if (this._config.tracePropagationExtractFirst) {
391
+ if (this._config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) {
391
392
  break
392
393
  }
393
394
  } else {
@@ -436,7 +437,7 @@ class TextMapPropagator {
436
437
  this._extractSamplingPriority(carrier, spanContext)
437
438
  this._extractTags(carrier, spanContext)
438
439
 
439
- if (this._config.tracePropagationExtractFirst) return spanContext
440
+ if (this._config.DD_TRACE_PROPAGATION_EXTRACT_FIRST) return spanContext
440
441
 
441
442
  const tc = this._extractTraceparentContext(carrier)
442
443
 
@@ -706,9 +707,8 @@ class TextMapPropagator {
706
707
  try {
707
708
  value = decodeURIComponent(value)
708
709
  } catch {
709
- tracerMetrics.count('context_header_style.malformed', ['header_style:baggage']).inc()
710
- removeAllBaggageItems()
711
- return
710
+ const bytes = value.replaceAll(percentByte, (_, hex) => String.fromCharCode(Number.parseInt(hex, 16)))
711
+ value = Buffer.from(bytes, 'binary').toString('utf8')
712
712
  }
713
713
 
714
714
  if (spanContext && (tagAllKeys || baggageTagKeys.has(key))) {
@@ -734,9 +734,9 @@ class TextMapPropagator {
734
734
 
735
735
  const trace = spanContext._trace
736
736
 
737
- if (this._config.tagsHeaderMaxLength === 0) {
737
+ if (this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH === 0) {
738
738
  log.debug('Trace tag propagation is disabled, skipping extraction.')
739
- } else if (carrier[tagsKey].length > this._config.tagsHeaderMaxLength) {
739
+ } else if (carrier[tagsKey].length > this._config.DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH) {
740
740
  log.error('Trace tags from carrier are too large, skipping extraction.')
741
741
  } else {
742
742
  const pairs = carrier[tagsKey].split(',')
@@ -802,18 +802,25 @@ class TextMapPropagator {
802
802
  return spanContext._traceId.toString(16)
803
803
  }
804
804
 
805
- static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin = null) {
805
+ /**
806
+ * @param {number} traceparentSampled
807
+ * @param {number|undefined} tracestateSamplingPriority
808
+ * @param {string|null} origin
809
+ * @returns {import('../../priority_sampler').SamplingPriority}
810
+ */
811
+ static _getSamplingPriority (traceparentSampled, tracestateSamplingPriority, origin) {
806
812
  const fromRumWithoutPriority = !tracestateSamplingPriority && origin === 'rum'
807
813
 
808
- let samplingPriority
809
- if (!fromRumWithoutPriority && traceparentSampled === 0 &&
810
- (!tracestateSamplingPriority || tracestateSamplingPriority >= 0)) {
811
- samplingPriority = 0
812
- } else if (!fromRumWithoutPriority && traceparentSampled === 1 &&
813
- (!tracestateSamplingPriority || tracestateSamplingPriority < 0)) {
814
- samplingPriority = 1
815
- } else {
816
- samplingPriority = tracestateSamplingPriority
814
+ let samplingPriority =
815
+ /** @type {import('../../priority_sampler').SamplingPriority} */ (tracestateSamplingPriority ?? AUTO_KEEP)
816
+ if (!fromRumWithoutPriority) {
817
+ if (traceparentSampled === 0 &&
818
+ (!tracestateSamplingPriority || tracestateSamplingPriority >= 0)) {
819
+ samplingPriority = AUTO_REJECT
820
+ } else if (traceparentSampled === 1 &&
821
+ (!tracestateSamplingPriority || tracestateSamplingPriority < 0)) {
822
+ samplingPriority = AUTO_KEEP
823
+ }
817
824
  }
818
825
 
819
826
  return samplingPriority
@@ -112,7 +112,7 @@ class DatadogSpan {
112
112
  // even `Span` itself in this case.
113
113
  //
114
114
  // TODO: Refactor Tracer/Span + tests to avoid having to do nullish checks.
115
- if (tracer?._config?.spanLeakDebug > 0) {
115
+ if (tracer?._config?.DD_TRACE_SPAN_LEAK_DEBUG > 0) {
116
116
  require('../spanleak').addSpan(this, operationName)
117
117
  }
118
118
 
@@ -149,7 +149,7 @@ class DatadogSpan {
149
149
  }
150
150
 
151
151
  /**
152
- * @returns {import('../priority_sampler').DatadogSpanContext}
152
+ * @returns {import('./span_context')}
153
153
  */
154
154
  context () {
155
155
  return this._spanContext
@@ -20,7 +20,7 @@ const REFERENCE_CHILD_OF = 'child_of'
20
20
  const REFERENCE_FOLLOWS_FROM = 'follows_from'
21
21
 
22
22
  class DatadogTracer {
23
- constructor (config, prioritySampler, exporter) {
23
+ constructor (config, prioritySampler) {
24
24
  this._config = config
25
25
  this._service = config.service
26
26
  this._version = config.version
@@ -29,8 +29,15 @@ class DatadogTracer {
29
29
  this._debug = config.debug
30
30
  this._prioritySampler = prioritySampler ?? new PrioritySampler(config.env, config.sampler)
31
31
 
32
- if (exporter) {
33
- this._exporter = exporter
32
+ // OTEL_TRACES_EXPORTER=otlp should not replace the Test Optimization
33
+ // exporter when the tracer is running in Test Optimization mode. Test spans
34
+ // (test_session/test_module/ test_suite/test) belong on the citestcycle
35
+ // endpoint, not on an OTLP traces endpoint — otherwise users with OTEL_*
36
+ // vars set in their environment (e.g. for a separate telemetry integration)
37
+ // silently lose all test spans.
38
+ if (config.OTEL_TRACES_EXPORTER === 'otlp' && !config.isCiVisibility) {
39
+ const { createOtlpTraceExporter } = require('../opentelemetry/trace')
40
+ this._exporter = createOtlpTraceExporter(config)
34
41
  } else {
35
42
  const Exporter = getExporter(config.experimental.exporter)
36
43
  this._exporter = new Exporter(config, this._prioritySampler)
@@ -43,7 +50,7 @@ class DatadogTracer {
43
50
  this._propagators = {
44
51
  [formats.TEXT_MAP]: new TextMapPropagator(config),
45
52
  [formats.HTTP_HEADERS]: new HttpPropagator(config),
46
- [formats.BINARY]: new BinaryPropagator(config),
53
+ [formats.BINARY]: new BinaryPropagator(),
47
54
  [formats.LOG]: new LogPropagator(config),
48
55
  [formats.TEXT_MAP_DSM]: new DSMTextMapPropagator(config),
49
56
  }
@@ -116,7 +123,7 @@ class DatadogTracer {
116
123
  * Get the span context from a span or a span context.
117
124
  *
118
125
  * @param {Span|SpanContext} spanContext
119
- * @returns {SpanContext}
126
+ * @returns {SpanContext|null}
120
127
  */
121
128
  function getContext (spanContext) {
122
129
  if (spanContext instanceof Span) {
@@ -163,9 +163,9 @@ module.exports = class PluginManager {
163
163
  dsmEnabled,
164
164
  clientIpEnabled,
165
165
  clientIpHeader,
166
- memcachedCommandEnabled,
167
- ciVisibilityTestSessionName,
168
- ciVisAgentlessLogSubmissionEnabled,
166
+ DD_TRACE_MEMCACHED_COMMAND_ENABLED,
167
+ DD_TEST_SESSION_NAME,
168
+ DD_AGENTLESS_LOG_SUBMISSION_ENABLED,
169
169
  isTestDynamicInstrumentationEnabled,
170
170
  isServiceUserProvided,
171
171
  middlewareTracingEnabled,
@@ -180,13 +180,13 @@ module.exports = class PluginManager {
180
180
  codeOriginForSpans,
181
181
  dbmPropagationMode,
182
182
  dsmEnabled,
183
- memcachedCommandEnabled,
183
+ DD_TRACE_MEMCACHED_COMMAND_ENABLED,
184
184
  site,
185
185
  url,
186
186
  headers: headerTags || [],
187
187
  clientIpHeader,
188
- ciVisibilityTestSessionName,
189
- ciVisAgentlessLogSubmissionEnabled,
188
+ DD_TEST_SESSION_NAME,
189
+ DD_AGENTLESS_LOG_SUBMISSION_ENABLED,
190
190
  isTestDynamicInstrumentationEnabled,
191
191
  isServiceUserProvided,
192
192
  traceWebsocketMessagesEnabled,
@@ -6,6 +6,7 @@ const plugins = {
6
6
  get '@aws-sdk/smithy-client' () { return require('../../../datadog-plugin-aws-sdk/src') },
7
7
  get '@azure/event-hubs' () { return require('../../../datadog-plugin-azure-event-hubs/src') },
8
8
  get '@azure/functions' () { return require('../../../datadog-plugin-azure-functions/src') },
9
+ get '@modelcontextprotocol/sdk' () { return require('../../../datadog-plugin-modelcontextprotocol-sdk/src') },
9
10
  get 'durable-functions' () { return require('../../../datadog-plugin-azure-durable-functions/src') },
10
11
  get '@azure/service-bus' () { return require('../../../datadog-plugin-azure-service-bus/src') },
11
12
  get '@cucumber/cucumber' () { return require('../../../datadog-plugin-cucumber/src') },
@@ -51,7 +51,7 @@ module.exports = class LogPlugin extends Plugin {
51
51
  configure (config) {
52
52
  return super.configure({
53
53
  ...config,
54
- enabled: config.enabled && (config.logInjection || config.ciVisAgentlessLogSubmissionEnabled),
54
+ enabled: config.enabled && (config.logInjection || config.DD_AGENTLESS_LOG_SUBMISSION_ENABLED),
55
55
  })
56
56
  }
57
57
  }
@@ -9,7 +9,6 @@ const { getEnvironmentVariable } = require('../../config/helper')
9
9
  const satisfies = require('../../../../../vendor/dist/semifies')
10
10
 
11
11
  const istanbul = require('../../../../../vendor/dist/istanbul-lib-coverage')
12
- const ignore = require('../../../../../vendor/dist/ignore')
13
12
 
14
13
  const id = require('../../id')
15
14
  const {
@@ -671,24 +670,146 @@ function getCodeOwnersFileEntries (rootDir) {
671
670
  const trimmed = content.trim()
672
671
  if (trimmed === '') continue
673
672
  const [pattern, ...owners] = trimmed.split(/\s+/)
674
- entries.push({ pattern, owners })
673
+ entries.push(setCodeOwnersPatternRegex({ pattern, owners }))
675
674
  }
676
675
  // Reverse because rules defined last take precedence
677
676
  return entries.reverse()
678
677
  }
679
678
 
680
- const codeOwnersPerFileName = new Map()
679
+ const codeOwnersPerEntries = new WeakMap()
680
+
681
+ /**
682
+ * @param {string} character
683
+ * @returns {string}
684
+ */
685
+ function escapeRegexCharacter (character) {
686
+ return character.replaceAll(/[|\\{}()[\]^$+*?.]/g, String.raw`\$&`)
687
+ }
688
+
689
+ /**
690
+ * @param {string} pattern
691
+ * @returns {boolean}
692
+ */
693
+ function hasUnescapedWildcard (pattern) {
694
+ for (let i = 0; i < pattern.length; i++) {
695
+ const character = pattern[i]
696
+ if (character === '\\') {
697
+ i++
698
+ } else if (character === '*' || character === '?') {
699
+ return true
700
+ }
701
+ }
702
+ return false
703
+ }
704
+
705
+ /**
706
+ * @param {string} pattern
707
+ * @returns {string}
708
+ */
709
+ function codeOwnersPatternToRegexSource (pattern) {
710
+ let source = ''
711
+ for (let i = 0; i < pattern.length; i++) {
712
+ const character = pattern[i]
713
+
714
+ if (character === '\\') {
715
+ const escapedCharacter = pattern[i + 1]
716
+ source += escapedCharacter === undefined
717
+ ? escapeRegexCharacter(character)
718
+ : escapeRegexCharacter(escapedCharacter)
719
+ i++
720
+ } else if (character === '*') {
721
+ if (pattern[i + 1] === '*') {
722
+ if (pattern[i + 2] === '/') {
723
+ source += '(?:.*/)?'
724
+ i += 2
725
+ } else {
726
+ source += '.*'
727
+ i++
728
+ }
729
+ } else {
730
+ source += '[^/]*'
731
+ }
732
+ } else if (character === '?') {
733
+ source += '[^/]'
734
+ } else {
735
+ source += escapeRegexCharacter(character)
736
+ }
737
+ }
738
+ return source
739
+ }
740
+
741
+ /**
742
+ * @param {string} pattern
743
+ * @returns {RegExp|null}
744
+ */
745
+ function getCodeOwnersPatternRegex (pattern) {
746
+ if (!pattern || pattern[0] === '!') {
747
+ return null
748
+ }
749
+
750
+ const directoryOnly = pattern.endsWith('/')
751
+ const normalizedPattern = pattern.replace(/^\/+/, '').replace(/\/+$/, '')
752
+ const anchored = pattern.startsWith('/') || normalizedPattern.includes('/')
753
+
754
+ if (!normalizedPattern) {
755
+ return null
756
+ }
757
+
758
+ const lastSlashIndex = normalizedPattern.lastIndexOf('/')
759
+ const lastSegment = lastSlashIndex === -1 ? normalizedPattern : normalizedPattern.slice(lastSlashIndex + 1)
760
+ const descendantSuffix = directoryOnly || !hasUnescapedWildcard(lastSegment) ? '(?:/.*)?' : ''
761
+ const patternSource = codeOwnersPatternToRegexSource(normalizedPattern)
762
+ const regexSource = anchored
763
+ ? `^${patternSource}${descendantSuffix}$`
764
+ : `(?:^|/)${patternSource}${descendantSuffix}$`
765
+
766
+ return new RegExp(regexSource)
767
+ }
768
+
769
+ function setCodeOwnersPatternRegex (entry) {
770
+ Object.defineProperty(entry, 'regex', {
771
+ configurable: true,
772
+ value: getCodeOwnersPatternRegex(entry.pattern),
773
+ writable: true,
774
+ })
775
+ return entry
776
+ }
777
+
778
+ /**
779
+ * Match a repository-relative filename against a CODEOWNERS pattern.
780
+ * See GitHub's CODEOWNERS pattern rules:
781
+ * https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
782
+ *
783
+ * @param {RegExp|null} regex
784
+ * @param {string} filename
785
+ * @returns {boolean}
786
+ */
787
+ function isCodeOwnersPatternMatch (regex, filename) {
788
+ if (!regex || !filename) {
789
+ return false
790
+ }
791
+
792
+ const normalizedFilename = filename.replaceAll('\\', '/').replace(/^\/+/, '')
793
+ return regex.test(normalizedFilename)
794
+ }
681
795
 
682
796
  function getCodeOwnersForFilename (filename, entries) {
683
797
  if (!entries) {
684
798
  return null
685
799
  }
686
- if (codeOwnersPerFileName.has(filename)) {
800
+ let codeOwnersPerFileName = codeOwnersPerEntries.get(entries)
801
+
802
+ if (!codeOwnersPerFileName) {
803
+ codeOwnersPerFileName = new Map()
804
+ codeOwnersPerEntries.set(entries, codeOwnersPerFileName)
805
+ } else if (codeOwnersPerFileName.has(filename)) {
687
806
  return codeOwnersPerFileName.get(filename)
688
807
  }
808
+
689
809
  for (const entry of entries) {
690
810
  try {
691
- const isResponsible = ignore().add(entry.pattern).ignores(filename)
811
+ const regex = entry.regex === undefined ? setCodeOwnersPatternRegex(entry).regex : entry.regex
812
+ const isResponsible = isCodeOwnersPatternMatch(regex, filename)
692
813
  if (isResponsible) {
693
814
  const codeOwners = JSON.stringify(entry.owners)
694
815
  codeOwnersPerFileName.set(filename, codeOwners)
@@ -934,8 +1055,8 @@ function getIsFaultyEarlyFlakeDetection (projectSuites, testsBySuiteName, faulty
934
1055
  }
935
1056
 
936
1057
  function getTestSessionName (config, trimmedCommand, envTags) {
937
- if (config.ciVisibilityTestSessionName) {
938
- return config.ciVisibilityTestSessionName
1058
+ if (config.DD_TEST_SESSION_NAME) {
1059
+ return config.DD_TEST_SESSION_NAME
939
1060
  }
940
1061
  const lageTestSessionName = getLageTestSessionName()
941
1062
  if (lageTestSessionName) {
@@ -31,7 +31,8 @@ function extractURL (req) {
31
31
  }
32
32
 
33
33
  function getProtocol (req) {
34
- return (req.socket?.encrypted || req.connection?.encrypted) ? 'https' : 'http'
34
+ // Do not check deprecated `req.connection` property.
35
+ return req.socket?.encrypted ? 'https' : 'http'
35
36
  }
36
37
 
37
38
  /**
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+
3
+ const EventPlugin = require('./event')
4
+
5
+ // Params captured on the instrumentation context that are safe to forward as pprof labels. Must be
6
+ // a subset of the names declared in asyncParamsByMethod in datadog-instrumentations/src/crypto.js.
7
+ const allowedParams = new Set([
8
+ 'algorithm', 'digest', 'iterations', 'keylen', 'offset', 'operation', 'size', 'type',
9
+ ])
10
+
11
+ class CryptoPlugin extends EventPlugin {
12
+ static id = 'crypto'
13
+
14
+ static operation = 'operation'
15
+
16
+ static entryType = 'crypto'
17
+
18
+ extendEvent (event, ctx) {
19
+ const detail = {}
20
+ for (const name of allowedParams) {
21
+ const value = ctx[name]
22
+ if (typeof value === 'string' || typeof value === 'number') {
23
+ detail[name] = value
24
+ }
25
+ }
26
+ event.detail = detail
27
+
28
+ return event
29
+ }
30
+ }
31
+
32
+ module.exports = CryptoPlugin
@@ -0,0 +1,19 @@
1
+ 'use strict'
2
+
3
+ const EventPlugin = require('./event')
4
+
5
+ class ZlibPlugin extends EventPlugin {
6
+ static id = 'zlib'
7
+
8
+ static operation = 'operation'
9
+
10
+ static entryType = 'zlib'
11
+
12
+ extendEvent (event, ctx) {
13
+ event.detail = { operation: ctx.operation }
14
+
15
+ return event
16
+ }
17
+ }
18
+
19
+ module.exports = ZlibPlugin
@@ -194,13 +194,46 @@ class FilesystemDecorator {
194
194
  }
195
195
  }
196
196
 
197
+ class ZlibDecorator {
198
+ constructor (stringTable) {
199
+ this.stringTable = stringTable
200
+ this.operationNameLabelKey = stringTable.dedup('operation')
201
+ }
202
+
203
+ decorateSample (sampleInput, item) {
204
+ sampleInput.label.push(labelFromStr(this.stringTable, this.operationNameLabelKey, item.detail.operation))
205
+ }
206
+ }
207
+
208
+ class CryptoDecorator {
209
+ constructor (stringTable) {
210
+ this.stringTable = stringTable
211
+ }
212
+
213
+ decorateSample (sampleInput, item) {
214
+ const labels = sampleInput.label
215
+ const stringTable = this.stringTable
216
+ for (const [key, value] of Object.entries(item.detail)) {
217
+ switch (typeof value) {
218
+ case 'string':
219
+ labels.push(labelFromStrStr(stringTable, key, value))
220
+ break
221
+ case 'number':
222
+ labels.push(new Label({ key: stringTable.dedup(key), num: value }))
223
+ }
224
+ }
225
+ }
226
+ }
227
+
197
228
  // Keys correspond to PerformanceEntry.entryType, values are constructor
198
229
  // functions for type-specific decorators.
199
230
  const decoratorTypes = {
231
+ crypto: CryptoDecorator,
200
232
  fs: FilesystemDecorator,
201
233
  dns: DNSDecorator,
202
234
  gc: GCDecorator,
203
235
  net: NetDecorator,
236
+ zlib: ZlibDecorator,
204
237
  }
205
238
 
206
239
  // Translates performance entries into pprof samples.
@@ -348,12 +381,14 @@ class DatadogInstrumentationEventSource {
348
381
  constructor (eventHandler, eventFilter) {
349
382
  // List all entries explicitly for bundlers to pick up the require calls correctly.
350
383
  const plugins = [
384
+ require('./event_plugins/crypto'),
351
385
  require('./event_plugins/dns_lookup'),
352
386
  require('./event_plugins/dns_lookupservice'),
353
387
  require('./event_plugins/dns_resolve'),
354
388
  require('./event_plugins/dns_reverse'),
355
389
  require('./event_plugins/fs'),
356
390
  require('./event_plugins/net'),
391
+ require('./event_plugins/zlib'),
357
392
  ]
358
393
  this.plugins = plugins.map((Plugin) => {
359
394
  return new Plugin(eventHandler, eventFilter)
@@ -1,6 +1,5 @@
1
1
  'use strict'
2
2
 
3
- const { getValueFromEnvSources } = require('./config/helper')
4
3
  const NoopProxy = require('./noop/proxy')
5
4
  const DatadogTracer = require('./tracer')
6
5
  const getConfig = require('./config')
@@ -129,11 +128,11 @@ class Tracer extends NoopProxy {
129
128
  lazyProxy(this, 'dogstatsd', () => require('./dogstatsd').CustomMetrics, config)
130
129
  }
131
130
 
132
- if (config.spanLeakDebug > 0) {
131
+ if (config.DD_TRACE_SPAN_LEAK_DEBUG > 0) {
133
132
  const spanleak = require('./spanleak')
134
- if (config.spanLeakDebug === spanleak.MODES.LOG) {
133
+ if (config.DD_TRACE_SPAN_LEAK_DEBUG === spanleak.MODES.LOG) {
135
134
  spanleak.enableLogging()
136
- } else if (config.spanLeakDebug === spanleak.MODES.GC_AND_LOG) {
135
+ } else if (config.DD_TRACE_SPAN_LEAK_DEBUG === spanleak.MODES.GC_AND_LOG) {
137
136
  spanleak.enableGarbageCollection()
138
137
  }
139
138
  spanleak.startScrubber()
@@ -204,7 +203,7 @@ class Tracer extends NoopProxy {
204
203
 
205
204
  this._modules.rewriter.enable(config)
206
205
 
207
- if (config.tracing && config.isManualApiEnabled) {
206
+ if (config.tracing && config.DD_CIVISIBILITY_MANUAL_API_ENABLED) {
208
207
  const TestApiManualPlugin = require('./ci-visibility/test-api-manual/test-api-manual-plugin')
209
208
  this._testApiManualPlugin = new TestApiManualPlugin(this)
210
209
  // `shouldGetEnvironmentData` is passed as false so that we only lazily calculate it
@@ -212,8 +211,8 @@ class Tracer extends NoopProxy {
212
211
  // are lazily configured when the library is imported.
213
212
  this._testApiManualPlugin.configure({ ...config, enabled: true }, false)
214
213
  }
215
- if (config.ciVisAgentlessLogSubmissionEnabled) {
216
- if (getValueFromEnvSources('DD_API_KEY')) {
214
+ if (config.DD_AGENTLESS_LOG_SUBMISSION_ENABLED) {
215
+ if (config.apiKey) {
217
216
  const LogSubmissionPlugin = require('./ci-visibility/log-submission/log-submission-plugin')
218
217
  const automaticLogPlugin = new LogSubmissionPlugin(this)
219
218
  automaticLogPlugin.configure({ ...config, enabled: true })
@@ -225,7 +224,7 @@ class Tracer extends NoopProxy {
225
224
  }
226
225
  }
227
226
 
228
- if (config.otelLogsEnabled) {
227
+ if (config.DD_LOGS_OTEL_ENABLED) {
229
228
  const { initializeOpenTelemetryLogs } = require('./opentelemetry/logs')
230
229
  initializeOpenTelemetryLogs(config)
231
230
  }
@@ -279,12 +278,7 @@ class Tracer extends NoopProxy {
279
278
  const prioritySampler = config.apmTracingEnabled === false
280
279
  ? require('./standalone').configure(config)
281
280
  : undefined
282
- let otlpExporter
283
- if (config.otelTracesEnabled) {
284
- const { buildResourceAttributes, createOtlpTraceExporter } = require('./opentelemetry/trace')
285
- otlpExporter = createOtlpTraceExporter(config, buildResourceAttributes(config))
286
- }
287
- this._tracer = new DatadogTracer(config, prioritySampler, otlpExporter)
281
+ this._tracer = new DatadogTracer(config, prioritySampler)
288
282
  this.dataStreamsCheckpointer = this._tracer.dataStreamsCheckpointer
289
283
  lazyProxy(this, 'appsec', () => require('./appsec/sdk'), this._tracer, config)
290
284
  lazyProxy(this, 'llmobs', () => require('./llmobs/sdk'), this._tracer, this._modules.llmobs, config)
@@ -51,6 +51,8 @@ module.exports = {
51
51
  const trackEventLoop = config.runtimeMetrics.eventLoop !== false
52
52
  const trackGc = config.runtimeMetrics.gc !== false
53
53
 
54
+ client = new MetricsAggregationClient(new DogStatsDClient(clientConfig))
55
+
54
56
  if (trackGc) {
55
57
  startGCObserver()
56
58
  }
@@ -72,8 +74,6 @@ module.exports = {
72
74
  }
73
75
  }
74
76
 
75
- client = new MetricsAggregationClient(new DogStatsDClient(clientConfig))
76
-
77
77
  lastTime = performance.now()
78
78
 
79
79
  if (nativeMetrics) {