dd-trace 5.97.0 → 5.98.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 (81) hide show
  1. package/index.d.ts +26 -2
  2. package/package.json +1 -1
  3. package/packages/datadog-instrumentations/src/cucumber.js +65 -3
  4. package/packages/datadog-instrumentations/src/cypress-config.js +31 -37
  5. package/packages/datadog-instrumentations/src/jest.js +104 -12
  6. package/packages/datadog-instrumentations/src/mocha/utils.js +8 -0
  7. package/packages/datadog-instrumentations/src/redis.js +12 -6
  8. package/packages/datadog-plugin-aws-sdk/src/base.js +1 -1
  9. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +1 -0
  10. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +1 -0
  11. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +1 -0
  12. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -0
  13. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +1 -0
  14. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +1 -0
  15. package/packages/datadog-plugin-cucumber/src/index.js +6 -0
  16. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +109 -1
  17. package/packages/datadog-plugin-cypress/src/index.js +59 -2
  18. package/packages/datadog-plugin-fs/src/index.js +1 -1
  19. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -1
  20. package/packages/datadog-plugin-google-cloud-pubsub/src/pubsub-push-subscription.js +2 -7
  21. package/packages/datadog-plugin-http/src/client.js +1 -1
  22. package/packages/datadog-plugin-http/src/server.js +10 -2
  23. package/packages/datadog-plugin-http2/src/client.js +1 -1
  24. package/packages/datadog-plugin-http2/src/server.js +10 -2
  25. package/packages/datadog-plugin-mongodb-core/src/index.js +3 -3
  26. package/packages/datadog-plugin-mysql/src/index.js +1 -1
  27. package/packages/datadog-plugin-next/src/index.js +8 -2
  28. package/packages/datadog-plugin-pg/src/index.js +1 -1
  29. package/packages/datadog-plugin-tedious/src/index.js +1 -1
  30. package/packages/datadog-plugin-ws/src/close.js +1 -1
  31. package/packages/datadog-plugin-ws/src/receiver.js +1 -1
  32. package/packages/dd-trace/src/aiguard/sdk.js +22 -22
  33. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -3
  34. package/packages/dd-trace/src/appsec/blocking.js +62 -34
  35. package/packages/dd-trace/src/appsec/sdk/set_user.js +1 -1
  36. package/packages/dd-trace/src/appsec/sdk/track_event.js +5 -5
  37. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +2 -2
  38. package/packages/dd-trace/src/appsec/sdk/utils.js +4 -2
  39. package/packages/dd-trace/src/config/defaults.js +0 -1
  40. package/packages/dd-trace/src/config/generated-config-types.d.ts +5 -0
  41. package/packages/dd-trace/src/config/index.js +55 -28
  42. package/packages/dd-trace/src/config/supported-configurations.json +61 -4
  43. package/packages/dd-trace/src/constants.js +1 -0
  44. package/packages/dd-trace/src/debugger/devtools_client/snapshot/processor.js +5 -2
  45. package/packages/dd-trace/src/encode/0.4.js +7 -6
  46. package/packages/dd-trace/src/encode/span-stats.js +4 -1
  47. package/packages/dd-trace/src/log/index.js +0 -10
  48. package/packages/dd-trace/src/openfeature/remote_config.js +6 -1
  49. package/packages/dd-trace/src/opentelemetry/context_manager.js +6 -4
  50. package/packages/dd-trace/src/opentelemetry/otlp/otlp_http_exporter_base.js +17 -2
  51. package/packages/dd-trace/src/opentelemetry/otlp/protobuf_loader.js +14 -2
  52. package/packages/dd-trace/src/opentelemetry/otlp/trace.proto +358 -0
  53. package/packages/dd-trace/src/opentelemetry/otlp/trace_service.proto +78 -0
  54. package/packages/dd-trace/src/opentelemetry/trace/index.js +75 -0
  55. package/packages/dd-trace/src/opentelemetry/trace/otlp_http_trace_exporter.js +66 -0
  56. package/packages/dd-trace/src/opentelemetry/trace/otlp_transformer.js +332 -0
  57. package/packages/dd-trace/src/opentracing/tracer.js +9 -4
  58. package/packages/dd-trace/src/plugins/log_plugin.js +3 -0
  59. package/packages/dd-trace/src/plugins/plugin.js +6 -11
  60. package/packages/dd-trace/src/plugins/storage.js +2 -2
  61. package/packages/dd-trace/src/plugins/tracing.js +22 -5
  62. package/packages/dd-trace/src/plugins/util/test.js +2 -0
  63. package/packages/dd-trace/src/plugins/util/web.js +6 -88
  64. package/packages/dd-trace/src/profiling/profiler.js +34 -77
  65. package/packages/dd-trace/src/proxy.js +8 -3
  66. package/packages/dd-trace/src/runtime_metrics/runtime_metrics.js +15 -11
  67. package/packages/dd-trace/src/service-naming/index.js +1 -1
  68. package/packages/dd-trace/src/service-naming/schemas/definition.js +4 -1
  69. package/packages/dd-trace/src/service-naming/schemas/util.js +15 -1
  70. package/packages/dd-trace/src/service-naming/schemas/v0/messaging.js +24 -1
  71. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +60 -0
  72. package/packages/dd-trace/src/service-naming/schemas/v0/web.js +17 -1
  73. package/packages/dd-trace/src/service-naming/schemas/v0/websocket.js +5 -0
  74. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +17 -0
  75. package/packages/dd-trace/src/service-naming/schemas/v1/web.js +11 -1
  76. package/packages/dd-trace/src/service-naming/schemas/v1/websocket.js +6 -0
  77. package/packages/dd-trace/src/span_stats.js +5 -1
  78. package/packages/dd-trace/src/tracer.js +2 -2
  79. package/vendor/dist/@apm-js-collab/code-transformer/index.js +28 -6
  80. package/vendor/dist/protobufjs/index.js +1 -1
  81. package/packages/dd-trace/src/log/utils.js +0 -16
@@ -0,0 +1,66 @@
1
+ 'use strict'
2
+
3
+ const OtlpHttpExporterBase = require('../otlp/otlp_http_exporter_base')
4
+ const { SAMPLING_PRIORITY_KEY } = require('../../constants')
5
+ const { AUTO_KEEP } = require('../../../../../ext/priority')
6
+ const OtlpTraceTransformer = require('./otlp_transformer')
7
+
8
+ /**
9
+ * OtlpHttpTraceExporter exports DD-formatted spans via OTLP over HTTP/JSON.
10
+ *
11
+ * This implementation follows the OTLP HTTP v1.7.0 specification:
12
+ * https://opentelemetry.io/docs/specs/otlp/#otlphttp
13
+ *
14
+ * It receives DD-formatted spans (from span_format.js), transforms them
15
+ * to OTLP ExportTraceServiceRequest JSON format, and sends them to the
16
+ * configured OTLP endpoint via HTTP POST.
17
+ *
18
+ * @class OtlpHttpTraceExporter
19
+ * @augments OtlpHttpExporterBase
20
+ */
21
+ class OtlpHttpTraceExporter extends OtlpHttpExporterBase {
22
+ #transformer
23
+
24
+ /**
25
+ * Creates a new OtlpHttpTraceExporter instance.
26
+ *
27
+ * @param {string} url - OTLP endpoint URL
28
+ * @param {string} headers - Additional HTTP headers as comma-separated key=value string
29
+ * @param {number} timeout - Request timeout in milliseconds
30
+ * @param {import('@opentelemetry/api').Attributes} resourceAttributes - Resource attributes
31
+ */
32
+ constructor (url, headers, timeout, resourceAttributes) {
33
+ super(url, headers, timeout, 'http/json', '/v1/traces', 'traces')
34
+ this.#transformer = new OtlpTraceTransformer(resourceAttributes)
35
+ }
36
+
37
+ /**
38
+ * Exports DD-formatted spans via OTLP over HTTP.
39
+ *
40
+ * @param {import('./otlp_transformer').DDFormattedSpan[]} spans - Array of DD-formatted spans to export
41
+ * @returns {void}
42
+ */
43
+ export (spans) {
44
+ if (spans.length === 0) {
45
+ return
46
+ }
47
+
48
+ // Drop unsampled traces — OTLP endpoints have no agent-side sampling.
49
+ const priority = spans[0]?.metrics?.[SAMPLING_PRIORITY_KEY]
50
+ if (priority !== undefined && priority < AUTO_KEEP) {
51
+ return
52
+ }
53
+
54
+ const additionalTags = [`spans:${spans.length}`]
55
+ this.recordTelemetry('otel.traces_export_attempts', 1, additionalTags)
56
+
57
+ const payload = this.#transformer.transformSpans(spans)
58
+ this.sendPayload(payload, (result) => {
59
+ if (result.code === 0) {
60
+ this.recordTelemetry('otel.traces_export_successes', 1, additionalTags)
61
+ }
62
+ })
63
+ }
64
+ }
65
+
66
+ module.exports = OtlpHttpTraceExporter
@@ -0,0 +1,332 @@
1
+ 'use strict'
2
+
3
+ const OtlpTransformerBase = require('../otlp/otlp_transformer_base')
4
+ const { getProtobufTypes } = require('../otlp/protobuf_loader')
5
+ const { VERSION } = require('../../../../../version')
6
+
7
+ const { protoSpanKind } = getProtobufTypes()
8
+ const SPAN_KIND_UNSPECIFIED = protoSpanKind.values.SPAN_KIND_UNSPECIFIED
9
+ const SPAN_KIND_INTERNAL = protoSpanKind.values.SPAN_KIND_INTERNAL
10
+ const SPAN_KIND_SERVER = protoSpanKind.values.SPAN_KIND_SERVER
11
+ const SPAN_KIND_CLIENT = protoSpanKind.values.SPAN_KIND_CLIENT
12
+ const SPAN_KIND_PRODUCER = protoSpanKind.values.SPAN_KIND_PRODUCER
13
+ const SPAN_KIND_CONSUMER = protoSpanKind.values.SPAN_KIND_CONSUMER
14
+
15
+ /**
16
+ * @typedef {object} DDFormattedSpan
17
+ * @property {import('../../id')} trace_id - DD Identifier for trace ID
18
+ * @property {import('../../id')} span_id - DD Identifier for span ID
19
+ * @property {import('../../id')} parent_id - DD Identifier for parent span ID
20
+ * @property {string} name - Span operation name
21
+ * @property {string} resource - Resource name
22
+ * @property {string} [service] - Service name
23
+ * @property {string} [type] - Span type
24
+ * @property {number} error - Error flag (0 or 1)
25
+ * @property {{[key: string]: string}} meta - String key-value tags
26
+ * @property {{[key: string]: number}} metrics - Numeric key-value tags
27
+ * @property {number} start - Start time in nanoseconds since epoch
28
+ * @property {number} duration - Duration in nanoseconds
29
+ * @property {object[]} [span_events] - Span events
30
+ */
31
+
32
+ // Map DD span.kind string values to OTLP SpanKind numeric values
33
+ const SPAN_KIND_MAP = {
34
+ internal: SPAN_KIND_INTERNAL,
35
+ server: SPAN_KIND_SERVER,
36
+ client: SPAN_KIND_CLIENT,
37
+ producer: SPAN_KIND_PRODUCER,
38
+ consumer: SPAN_KIND_CONSUMER,
39
+ }
40
+
41
+ // OTLP StatusCode values (from trace.proto Status.StatusCode enum)
42
+ const STATUS_CODE_UNSET = 0
43
+ const STATUS_CODE_ERROR = 2
44
+
45
+ // DD meta keys that are mapped to dedicated OTLP span fields and should not appear as attributes
46
+ const EXCLUDED_META_KEYS = new Set([
47
+ '_dd.span_links',
48
+ 'span.kind',
49
+ ])
50
+
51
+ /**
52
+ * OtlpTraceTransformer transforms DD-formatted spans to OTLP trace JSON format.
53
+ *
54
+ * This implementation follows the OTLP Trace v1.7.0 Data Model specification:
55
+ * https://opentelemetry.io/docs/specs/otlp/#trace-data-model
56
+ *
57
+ * It receives DD-formatted spans (from span_format.js) and produces
58
+ * an ExportTraceServiceRequest serialized as JSON (http/json protocol only).
59
+ *
60
+ * @class OtlpTraceTransformer
61
+ * @augments OtlpTransformerBase
62
+ */
63
+ class OtlpTraceTransformer extends OtlpTransformerBase {
64
+ /**
65
+ * Creates a new OtlpTraceTransformer instance.
66
+ *
67
+ * @param {import('@opentelemetry/api').Attributes} resourceAttributes - Resource attributes
68
+ */
69
+ constructor (resourceAttributes) {
70
+ super(resourceAttributes, 'http/json', 'traces')
71
+ }
72
+
73
+ /**
74
+ * Transforms DD-formatted spans to OTLP JSON format.
75
+ *
76
+ * @param {DDFormattedSpan[]} spans - Array of DD-formatted spans to transform
77
+ * @returns {Buffer} JSON-encoded trace data
78
+ */
79
+ transformSpans (spans) {
80
+ const traceData = {
81
+ resourceSpans: [{
82
+ resource: this.transformResource(),
83
+ scopeSpans: this.#transformScopeSpans(spans),
84
+ }],
85
+ }
86
+ return this.serializeToJson(traceData)
87
+ }
88
+
89
+ /**
90
+ * Creates scope spans. DD spans do not carry instrumentation scope info,
91
+ * so all spans are placed under a single default scope.
92
+ *
93
+ * @param {DDFormattedSpan[]} spans - Array of DD-formatted spans
94
+ * @returns {object[]} Array of scope span objects
95
+ */
96
+ #transformScopeSpans (spans) {
97
+ return [{
98
+ scope: {
99
+ name: 'dd-trace-js',
100
+ version: VERSION,
101
+ attributes: [],
102
+ droppedAttributesCount: 0,
103
+ },
104
+ schemaUrl: '',
105
+ spans: spans.map(span => this.#transformSpan(span)),
106
+ }]
107
+ }
108
+
109
+ /**
110
+ * Transforms a single DD-formatted span to an OTLP Span object.
111
+ *
112
+ * @param {DDFormattedSpan} span - DD-formatted span to transform
113
+ * @returns {object} OTLP Span object
114
+ */
115
+ #transformSpan (span) {
116
+ const parentId = span.parent_id
117
+ const links = this.#extractLinks(span.meta?.['_dd.span_links'])
118
+
119
+ return {
120
+ traceId: this.#idToBytes(span.trace_id, 16),
121
+ spanId: this.#idToBytes(span.span_id, 8),
122
+ parentSpanId: (parentId && !this.#isZeroId(parentId)) ? this.#idToBytes(parentId, 8) : undefined,
123
+ name: span.resource,
124
+ kind: this.#mapSpanKind(span.meta?.['span.kind']),
125
+ startTimeUnixNano: span.start,
126
+ endTimeUnixNano: span.start + span.duration,
127
+ attributes: this.#buildAttributes(span),
128
+ droppedAttributesCount: 0,
129
+ events: span.span_events?.length ? span.span_events.map(event => this.#transformEvent(event)) : undefined,
130
+ droppedEventsCount: 0,
131
+ links: links.length ? links : undefined,
132
+ droppedLinksCount: 0,
133
+ status: this.#mapStatus(span),
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Builds OTLP attributes from DD span fields.
139
+ * Merges top-level DD fields (service, resource, type), meta (string tags),
140
+ * and metrics (numeric tags) into a single OTLP KeyValue array.
141
+ *
142
+ * @param {DDFormattedSpan} span - DD-formatted span
143
+ * @returns {object[]} Array of OTLP KeyValue objects
144
+ */
145
+ #buildAttributes (span) {
146
+ const attributes = []
147
+
148
+ // Add top-level DD span fields as OTLP attributes
149
+ if (span.service) {
150
+ attributes.push({ key: 'service.name', value: { stringValue: span.service } })
151
+ }
152
+ if (span.name) {
153
+ attributes.push({ key: 'operation.name', value: { stringValue: span.name } })
154
+ }
155
+ if (span.resource) {
156
+ attributes.push({ key: 'resource.name', value: { stringValue: span.resource } })
157
+ }
158
+ if (span.type) {
159
+ attributes.push({ key: 'span.type', value: { stringValue: span.type } })
160
+ }
161
+
162
+ // Add meta string tags, skipping keys that map to dedicated OTLP fields
163
+ if (span.meta) {
164
+ for (const [key, value] of Object.entries(span.meta)) {
165
+ if (EXCLUDED_META_KEYS.has(key)) continue
166
+ attributes.push({ key, value: { stringValue: value } })
167
+ }
168
+ }
169
+
170
+ // Add metrics as numeric attributes
171
+ if (span.metrics) {
172
+ for (const [key, value] of Object.entries(span.metrics)) {
173
+ if (Number.isInteger(value)) {
174
+ attributes.push({ key, value: { intValue: value } })
175
+ } else {
176
+ attributes.push({ key, value: { doubleValue: value } })
177
+ }
178
+ }
179
+ }
180
+
181
+ // Add meta_struct as bytesValue attributes (JSON-serialized, base64-encoded per proto JSON mapping)
182
+ if (span.meta_struct) {
183
+ for (const [key, value] of Object.entries(span.meta_struct)) {
184
+ const bytes = Buffer.from(JSON.stringify(value))
185
+ attributes.push({ key, value: { bytesValue: bytes.toString('base64') } })
186
+ }
187
+ }
188
+
189
+ return attributes
190
+ }
191
+
192
+ /**
193
+ * Maps a DD span.kind string to an OTLP SpanKind enum value.
194
+ *
195
+ * @param {string | undefined} kind - DD span kind string
196
+ * @returns {number} OTLP SpanKind enum value
197
+ */
198
+ #mapSpanKind (kind) {
199
+ if (!kind) return SPAN_KIND_UNSPECIFIED
200
+ return SPAN_KIND_MAP[kind] ?? SPAN_KIND_UNSPECIFIED
201
+ }
202
+
203
+ /**
204
+ * Maps DD span error state to an OTLP Status object.
205
+ *
206
+ * @param {DDFormattedSpan} span - DD-formatted span
207
+ * @returns {object} OTLP Status object with code and message
208
+ */
209
+ #mapStatus (span) {
210
+ if (span.error === 1) {
211
+ return {
212
+ code: STATUS_CODE_ERROR,
213
+ message: span.meta?.['error.message'] || '',
214
+ }
215
+ }
216
+ return { code: STATUS_CODE_UNSET, message: '' }
217
+ }
218
+
219
+ /**
220
+ * Transforms a DD span event to an OTLP Event object.
221
+ *
222
+ * @param {object} event - DD span event with name, time_unix_nano, and attributes
223
+ * @returns {object} OTLP Event object
224
+ */
225
+ #transformEvent (event) {
226
+ return {
227
+ timeUnixNano: event.time_unix_nano,
228
+ name: event.name || '',
229
+ attributes: event.attributes && Object.keys(event.attributes).length > 0
230
+ ? this.transformAttributes(event.attributes)
231
+ : [],
232
+ droppedAttributesCount: 0,
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Extracts and transforms span links from the DD _dd.span_links meta JSON string.
238
+ *
239
+ * @param {string | undefined} spanLinksJson - JSON-encoded array of DD span links
240
+ * @returns {object[]} Array of OTLP Link objects
241
+ */
242
+ #extractLinks (spanLinksJson) {
243
+ if (!spanLinksJson) return []
244
+
245
+ let parsedLinks
246
+ try {
247
+ parsedLinks = JSON.parse(spanLinksJson)
248
+ } catch {
249
+ return []
250
+ }
251
+
252
+ if (!Array.isArray(parsedLinks)) return []
253
+
254
+ return parsedLinks.map(link => this.#transformLink(link))
255
+ }
256
+
257
+ /**
258
+ * Transforms a single DD span link to an OTLP Link object.
259
+ *
260
+ * @param {object} link - DD span link with trace_id, span_id, attributes, flags, tracestate
261
+ * @returns {object} OTLP Link object
262
+ */
263
+ #transformLink (link) {
264
+ return {
265
+ traceId: this.#hexToBytes(link.trace_id, 16),
266
+ spanId: this.#hexToBytes(link.span_id, 8),
267
+ traceState: link.tracestate || '',
268
+ attributes: link.attributes && Object.keys(link.attributes).length > 0
269
+ ? this.transformAttributes(link.attributes)
270
+ : [],
271
+ droppedAttributesCount: 0,
272
+ flags: link.flags,
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Converts a DD Identifier object to a hex-encoded string of the specified byte length.
278
+ * Pads with leading zeros if the identifier buffer is shorter than the target.
279
+ * Per the OTLP http/json spec, trace-ids and span-ids must be hex-encoded strings.
280
+ *
281
+ * @param {object} identifier - DD Identifier object with toBuffer() method
282
+ * @param {number} targetLength - Target byte length (16 for trace ID, 8 for span ID)
283
+ * @returns {string} Hex-encoded string of the specified length
284
+ */
285
+ #idToBytes (identifier, targetLength) {
286
+ const buffer = identifier.toBuffer()
287
+ if (buffer.length === targetLength) {
288
+ return Buffer.from(buffer).toString('hex')
289
+ }
290
+ if (buffer.length > targetLength) {
291
+ return Buffer.from(buffer.slice(buffer.length - targetLength)).toString('hex')
292
+ }
293
+ // Pad with leading zeros to reach target length
294
+ const result = Buffer.alloc(targetLength)
295
+ const offset = targetLength - buffer.length
296
+ for (let i = 0; i < buffer.length; i++) {
297
+ result[offset + i] = buffer[i]
298
+ }
299
+ return result.toString('hex')
300
+ }
301
+
302
+ /**
303
+ * Checks if a DD Identifier represents a zero ID (all bytes are 0).
304
+ *
305
+ * @param {object} identifier - DD Identifier object with toBuffer() method
306
+ * @returns {boolean} True if the identifier is all zeros
307
+ */
308
+ #isZeroId (identifier) {
309
+ const buffer = identifier.toBuffer()
310
+ for (let i = 0; i < buffer.length; i++) {
311
+ if (buffer[i] !== 0) return false
312
+ }
313
+ return true
314
+ }
315
+
316
+ /**
317
+ * Normalizes a hex string to the specified byte length.
318
+ * Pads with leading zeros if the hex string is shorter than expected.
319
+ * Per the OTLP http/json spec, trace-ids and span-ids must be hex-encoded strings.
320
+ *
321
+ * @param {string | undefined} hexString - Hex string to normalize
322
+ * @param {number} targetLength - Target byte length
323
+ * @returns {string} Hex-encoded string of the specified length
324
+ */
325
+ #hexToBytes (hexString, targetLength) {
326
+ if (!hexString) return '0'.repeat(targetLength * 2)
327
+ const cleanHex = hexString.startsWith('0x') ? hexString.slice(2) : hexString
328
+ return cleanHex.padStart(targetLength * 2, '0')
329
+ }
330
+ }
331
+
332
+ module.exports = OtlpTraceTransformer
@@ -20,9 +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) {
24
- const Exporter = getExporter(config.experimental.exporter)
25
-
23
+ constructor (config, prioritySampler, exporter) {
26
24
  this._config = config
27
25
  this._service = config.service
28
26
  this._version = config.version
@@ -30,7 +28,14 @@ class DatadogTracer {
30
28
  this._logInjection = config.logInjection
31
29
  this._debug = config.debug
32
30
  this._prioritySampler = prioritySampler ?? new PrioritySampler(config.env, config.sampler)
33
- this._exporter = new Exporter(config, this._prioritySampler)
31
+
32
+ if (exporter) {
33
+ this._exporter = exporter
34
+ } else {
35
+ const Exporter = getExporter(config.experimental.exporter)
36
+ this._exporter = new Exporter(config, this._prioritySampler)
37
+ }
38
+
34
39
  this._processor = new SpanProcessor(this._exporter, this._prioritySampler, config)
35
40
  this._url = this._exporter._url
36
41
  this._enableGetRumData = config.experimental.enableGetRumData
@@ -13,6 +13,9 @@ function messageProxy (message, holder) {
13
13
 
14
14
  return target[key]
15
15
  },
16
+ set (target, key, value) {
17
+ return Reflect.set(target, key, value)
18
+ },
16
19
  ownKeys (target) {
17
20
  const ownKeys = Reflect.ownKeys(target)
18
21
  if (!Object.hasOwn(target, 'dd') && Reflect.isExtensible(target)) {
@@ -106,12 +106,6 @@ module.exports = class Plugin {
106
106
  storage('legacy').enterWith({ ...store, span })
107
107
  }
108
108
 
109
- // TODO: Implement filters on resource name for all plugins.
110
- /** Prevents creation of spans here and for all async descendants. */
111
- skip () {
112
- storage('legacy').enterWith({ noop: true })
113
- }
114
-
115
109
  /**
116
110
  * Subscribe to a diagnostic channel with automatic error handling and enable/disable lifecycle.
117
111
  *
@@ -157,8 +151,9 @@ module.exports = class Plugin {
157
151
 
158
152
  if (!store || !store.span) return
159
153
 
160
- if (!store.span._spanContext._tags.error) {
161
- store.span.setTag('error', error || 1)
154
+ const span = /** @type {import('../opentracing/span')} */ (store.span)
155
+ if (!span._spanContext._tags.error) {
156
+ span.setTag('error', error || 1)
162
157
  }
163
158
  }
164
159
 
@@ -167,12 +162,12 @@ module.exports = class Plugin {
167
162
  *
168
163
  * TODO: Remove the overloading with `enabled` and use the config object directly.
169
164
  *
170
- * @param {boolean|import('../config/config-base')} config Either a boolean to enable/disable
171
- * or a configuration object containing at least `{ enabled: boolean }`.
165
+ * @param {boolean | import('../config/config-base') & {enabled: boolean}} config Either a boolean to
166
+ * enable/disable or a configuration object containing at least `{ enabled: boolean }`.
172
167
  */
173
168
  configure (config) {
174
169
  if (typeof config === 'boolean') {
175
- config = { enabled: config }
170
+ config = /** @type {import('../config/config-base') & {enabled: boolean}} */ ({ enabled: config })
176
171
  }
177
172
  this.config = config
178
173
  if (config.enabled) {
@@ -12,8 +12,8 @@ class StoragePlugin extends ClientPlugin {
12
12
  }
13
13
 
14
14
  startSpan (name, options, ctx) {
15
- if (!options.service && this.system) {
16
- options.service = `${this.tracer._service}-${this.system}`
15
+ if (!options.service?.name && this.system) {
16
+ options.service = { name: `${this.tracer._service}-${this.system}`, source: this.system }
17
17
  }
18
18
 
19
19
  return super.startSpan(name, options, ctx)
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { storage } = require('../../../datadog-core')
4
4
  const analyticsSampler = require('../analytics_sampler')
5
- const { COMPONENT } = require('../constants')
5
+ const { COMPONENT, SVC_SRC_KEY } = require('../constants')
6
6
  const Plugin = require('./plugin')
7
7
 
8
8
  class TracingPlugin extends Plugin {
@@ -26,7 +26,7 @@ class TracingPlugin extends Plugin {
26
26
  * @param {string} [opts.type]
27
27
  * @param {string} [opts.id]
28
28
  * @param {string} [opts.kind]
29
- * @returns {string}
29
+ * @returns {{ name: string, source: string | undefined }}
30
30
  */
31
31
  serviceName (opts = {}) {
32
32
  const {
@@ -157,7 +157,8 @@ class TracingPlugin extends Plugin {
157
157
  * @param {string} [options.kind] - The kind of the span.
158
158
  * @param {object} [options.meta] - The meta data for the span.
159
159
  * @param {object} [options.metrics] - The metrics for the span.
160
- * @param {string} [options.service] - The service name.
160
+ * @param {string | { name: string, source?: string }} [options.service] - The service name, or an object with
161
+ * name and source.
161
162
  * @param {number} [options.startTime] - The start time of the span.
162
163
  * @param {string} [options.resource] - The resource name.
163
164
  * @param {string} [options.type] - The type of the span.
@@ -180,24 +181,40 @@ class TracingPlugin extends Plugin {
180
181
  resource,
181
182
  type,
182
183
  } = options
183
-
184
+ let serviceSource
184
185
  const tracer = options.tracer || this.tracer
185
186
  const config = options.config || this.config
186
187
 
188
+ if (service && typeof service === 'object') {
189
+ serviceSource = service.source
190
+ service = service.name
191
+ } else if (service !== undefined) {
192
+ // service is a plain value returned by service naming/config logic
193
+ serviceSource = service ? 'opt.plugin' : undefined
194
+ }
195
+
187
196
  const store = storage('legacy').getStore()
188
197
  if (store && childOf === undefined) {
189
198
  childOf = /** @type {import('../opentracing/span') | undefined} */ (store.span)
190
199
  }
191
200
 
201
+ // clear service source if service is the same as tracer._service
202
+ const serviceName = service || meta?.service
203
+
204
+ if (!serviceName || serviceName === tracer._service) {
205
+ serviceSource = undefined
206
+ }
207
+
192
208
  const span = tracer.startSpan(name, {
193
209
  startTime,
194
210
  childOf,
195
211
  tags: {
196
212
  [COMPONENT]: component,
197
- 'service.name': service || meta?.service || tracer._service,
213
+ 'service.name': serviceName || tracer._service,
198
214
  'resource.name': resource,
199
215
  'span.kind': kind,
200
216
  'span.type': type,
217
+ ...(serviceSource === undefined ? undefined : { [SVC_SRC_KEY]: serviceSource }),
201
218
  ...meta,
202
219
  ...metrics,
203
220
  },
@@ -137,6 +137,7 @@ const JEST_WORKER_TRACE_PAYLOAD_CODE = 60
137
137
  const JEST_WORKER_COVERAGE_PAYLOAD_CODE = 61
138
138
  const JEST_WORKER_LOGS_PAYLOAD_CODE = 62
139
139
  const JEST_WORKER_TELEMETRY_PAYLOAD_CODE = 63
140
+ const JEST_WORKER_QUARANTINE_PAYLOAD_CODE = 64
140
141
 
141
142
  // cucumber worker variables
142
143
  const CUCUMBER_WORKER_TRACE_PAYLOAD_CODE = 70
@@ -262,6 +263,7 @@ module.exports = {
262
263
  JEST_WORKER_COVERAGE_PAYLOAD_CODE,
263
264
  JEST_WORKER_LOGS_PAYLOAD_CODE,
264
265
  JEST_WORKER_TELEMETRY_PAYLOAD_CODE,
266
+ JEST_WORKER_QUARANTINE_PAYLOAD_CODE,
265
267
  CUCUMBER_WORKER_TRACE_PAYLOAD_CODE,
266
268
  MOCHA_WORKER_TRACE_PAYLOAD_CODE,
267
269
  PLAYWRIGHT_WORKER_TRACE_PAYLOAD_CODE,