dd-trace 4.44.0 → 4.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/index.d.ts +2 -1
  2. package/package.json +3 -3
  3. package/packages/datadog-instrumentations/src/body-parser.js +14 -2
  4. package/packages/datadog-instrumentations/src/cucumber.js +10 -0
  5. package/packages/datadog-instrumentations/src/helpers/hooks.js +3 -2
  6. package/packages/datadog-instrumentations/src/helpers/register.js +8 -1
  7. package/packages/datadog-instrumentations/src/mocha/main.js +90 -70
  8. package/packages/datadog-instrumentations/src/nyc.js +23 -0
  9. package/packages/datadog-instrumentations/src/vitest.js +18 -2
  10. package/packages/datadog-plugin-cucumber/src/index.js +12 -2
  11. package/packages/datadog-plugin-cypress/src/cypress-plugin.js +16 -4
  12. package/packages/datadog-plugin-jest/src/index.js +17 -4
  13. package/packages/datadog-plugin-mocha/src/index.js +25 -6
  14. package/packages/datadog-plugin-nyc/src/index.js +35 -0
  15. package/packages/datadog-plugin-playwright/src/index.js +9 -4
  16. package/packages/datadog-plugin-vitest/src/index.js +30 -4
  17. package/packages/dd-trace/src/ci-visibility/early-flake-detection/get-known-tests.js +40 -1
  18. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +2 -4
  19. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +2 -4
  20. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +8 -7
  21. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +2 -4
  22. package/packages/dd-trace/src/ci-visibility/requests/get-library-configuration.js +2 -4
  23. package/packages/dd-trace/src/ci-visibility/telemetry.js +29 -2
  24. package/packages/dd-trace/src/config.js +118 -112
  25. package/packages/dd-trace/src/opentelemetry/context_manager.js +22 -39
  26. package/packages/dd-trace/src/opentelemetry/span_context.js +2 -2
  27. package/packages/dd-trace/src/opentelemetry/tracer.js +23 -14
  28. package/packages/dd-trace/src/opentelemetry/tracer_provider.js +9 -1
  29. package/packages/dd-trace/src/opentracing/propagation/log.js +1 -1
  30. package/packages/dd-trace/src/opentracing/propagation/text_map.js +60 -0
  31. package/packages/dd-trace/src/opentracing/span_context.js +1 -0
  32. package/packages/dd-trace/src/plugins/ci_plugin.js +2 -2
  33. package/packages/dd-trace/src/plugins/index.js +1 -0
  34. package/packages/dd-trace/src/plugins/util/git.js +14 -1
  35. package/packages/dd-trace/src/telemetry/index.js +1 -1
@@ -183,7 +183,7 @@ function remapify (input, mappings) {
183
183
  return output
184
184
  }
185
185
 
186
- function propagationStyle (key, option, defaultValue) {
186
+ function propagationStyle (key, option) {
187
187
  // Extract by key if in object-form value
188
188
  if (option !== null && typeof option === 'object' && !Array.isArray(option)) {
189
189
  option = option[key]
@@ -206,8 +206,16 @@ function propagationStyle (key, option, defaultValue) {
206
206
  .filter(v => v !== '')
207
207
  .map(v => v.trim().toLowerCase())
208
208
  }
209
+ }
209
210
 
210
- return defaultValue
211
+ function reformatSpanSamplingRules (rules) {
212
+ if (!rules) return rules
213
+ return rules.map(rule => {
214
+ return remapify(rule, {
215
+ sample_rate: 'sampleRate',
216
+ max_per_second: 'maxPerSecond'
217
+ })
218
+ })
211
219
  }
212
220
 
213
221
  class Config {
@@ -229,36 +237,11 @@ class Config {
229
237
 
230
238
  checkIfBothOtelAndDdEnvVarSet()
231
239
 
232
- const DD_TRACE_MEMCACHED_COMMAND_ENABLED = coalesce(
233
- process.env.DD_TRACE_MEMCACHED_COMMAND_ENABLED,
234
- false
235
- )
236
-
237
- const DD_SERVICE_MAPPING = coalesce(
238
- options.serviceMapping,
239
- process.env.DD_SERVICE_MAPPING
240
- ? fromEntries(
241
- process.env.DD_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
242
- )
243
- : {}
244
- )
245
-
246
240
  const DD_API_KEY = coalesce(
247
241
  process.env.DATADOG_API_KEY,
248
242
  process.env.DD_API_KEY
249
243
  )
250
244
 
251
- // TODO: Remove the experimental env vars as a major?
252
- const DD_TRACE_B3_ENABLED = coalesce(
253
- options.experimental && options.experimental.b3,
254
- process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
255
- false
256
- )
257
- const defaultPropagationStyle = ['datadog', 'tracecontext']
258
- if (isTrue(DD_TRACE_B3_ENABLED)) {
259
- defaultPropagationStyle.push('b3')
260
- defaultPropagationStyle.push('b3 single header')
261
- }
262
245
  if (process.env.DD_TRACE_PROPAGATION_STYLE && (
263
246
  process.env.DD_TRACE_PROPAGATION_STYLE_INJECT ||
264
247
  process.env.DD_TRACE_PROPAGATION_STYLE_EXTRACT
@@ -272,21 +255,11 @@ class Config {
272
255
  const PROPAGATION_STYLE_INJECT = propagationStyle(
273
256
  'inject',
274
257
  options.tracePropagationStyle,
275
- defaultPropagationStyle
276
- )
277
- const PROPAGATION_STYLE_EXTRACT = propagationStyle(
278
- 'extract',
279
- options.tracePropagationStyle,
280
- defaultPropagationStyle
258
+ this._getDefaultPropagationStyle(options)
281
259
  )
282
260
 
283
261
  validateOtelPropagators(PROPAGATION_STYLE_INJECT)
284
262
 
285
- const DD_TRACE_PROPAGATION_EXTRACT_FIRST = coalesce(
286
- process.env.DD_TRACE_PROPAGATION_EXTRACT_FIRST,
287
- false
288
- )
289
-
290
263
  if (typeof options.appsec === 'boolean') {
291
264
  options.appsec = {
292
265
  enabled: options.appsec
@@ -295,33 +268,6 @@ class Config {
295
268
  options.appsec = {}
296
269
  }
297
270
 
298
- const DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON = coalesce(
299
- maybeFile(options.appsec.blockedTemplateGraphql),
300
- maybeFile(process.env.DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON)
301
- )
302
- const DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING = coalesce(
303
- options.appsec.eventTracking && options.appsec.eventTracking.mode,
304
- process.env.DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
305
- 'safe'
306
- ).toLowerCase()
307
- const DD_API_SECURITY_ENABLED = coalesce(
308
- options.appsec?.apiSecurity?.enabled,
309
- process.env.DD_API_SECURITY_ENABLED && isTrue(process.env.DD_API_SECURITY_ENABLED),
310
- process.env.DD_EXPERIMENTAL_API_SECURITY_ENABLED && isTrue(process.env.DD_EXPERIMENTAL_API_SECURITY_ENABLED),
311
- true
312
- )
313
- const DD_API_SECURITY_REQUEST_SAMPLE_RATE = coalesce(
314
- options.appsec?.apiSecurity?.requestSampling,
315
- parseFloat(process.env.DD_API_SECURITY_REQUEST_SAMPLE_RATE),
316
- 0.1
317
- )
318
-
319
- // 0: disabled, 1: logging, 2: garbage collection + logging
320
- const DD_TRACE_SPAN_LEAK_DEBUG = coalesce(
321
- process.env.DD_TRACE_SPAN_LEAK_DEBUG,
322
- 0
323
- )
324
-
325
271
  const DD_INSTRUMENTATION_INSTALL_ID = coalesce(
326
272
  process.env.DD_INSTRUMENTATION_INSTALL_ID,
327
273
  null
@@ -335,51 +281,10 @@ class Config {
335
281
  null
336
282
  )
337
283
 
338
- const sampler = {
339
- spanSamplingRules: coalesce(
340
- options.spanSamplingRules,
341
- safeJsonParse(maybeFile(process.env.DD_SPAN_SAMPLING_RULES_FILE)),
342
- safeJsonParse(process.env.DD_SPAN_SAMPLING_RULES),
343
- []
344
- ).map(rule => {
345
- return remapify(rule, {
346
- sample_rate: 'sampleRate',
347
- max_per_second: 'maxPerSecond'
348
- })
349
- })
350
- }
351
-
352
284
  // TODO: refactor
353
285
  this.apiKey = DD_API_KEY
354
- this.serviceMapping = DD_SERVICE_MAPPING
355
- this.tracePropagationStyle = {
356
- inject: PROPAGATION_STYLE_INJECT,
357
- extract: PROPAGATION_STYLE_EXTRACT,
358
- otelPropagators: process.env.DD_TRACE_PROPAGATION_STYLE ||
359
- process.env.DD_TRACE_PROPAGATION_STYLE_INJECT ||
360
- process.env.DD_TRACE_PROPAGATION_STYLE_EXTRACT
361
- ? false
362
- : !!process.env.OTEL_PROPAGATORS
363
- }
364
- this.tracePropagationExtractFirst = isTrue(DD_TRACE_PROPAGATION_EXTRACT_FIRST)
365
- this.sampler = sampler
366
- this.appsec = {
367
- blockedTemplateGraphql: DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
368
- eventTracking: {
369
- enabled: ['extended', 'safe'].includes(DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING),
370
- mode: DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING
371
- },
372
- apiSecurity: {
373
- enabled: DD_API_SECURITY_ENABLED,
374
- // Coerce value between 0 and 1
375
- requestSampling: Math.min(1, Math.max(0, DD_API_SECURITY_REQUEST_SAMPLE_RATE))
376
- }
377
- }
378
286
 
379
- // Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
380
- this.memcachedCommandEnabled = isTrue(DD_TRACE_MEMCACHED_COMMAND_ENABLED)
381
- this.isAzureFunction = getIsAzureFunction()
382
- this.spanLeakDebug = Number(DD_TRACE_SPAN_LEAK_DEBUG)
287
+ // sent in telemetry event app-started
383
288
  this.installSignature = {
384
289
  id: DD_INSTRUMENTATION_INSTALL_ID,
385
290
  time: DD_INSTRUMENTATION_INSTALL_TIME,
@@ -453,6 +358,21 @@ class Config {
453
358
  this._merge()
454
359
  }
455
360
 
361
+ _getDefaultPropagationStyle (options) {
362
+ // TODO: Remove the experimental env vars as a major?
363
+ const DD_TRACE_B3_ENABLED = coalesce(
364
+ options.experimental && options.experimental.b3,
365
+ process.env.DD_TRACE_EXPERIMENTAL_B3_ENABLED,
366
+ false
367
+ )
368
+ const defaultPropagationStyle = ['datadog', 'tracecontext']
369
+ if (isTrue(DD_TRACE_B3_ENABLED)) {
370
+ defaultPropagationStyle.push('b3')
371
+ defaultPropagationStyle.push('b3 single header')
372
+ }
373
+ return defaultPropagationStyle
374
+ }
375
+
456
376
  _isInServerlessEnvironment () {
457
377
  const inAWSLambda = process.env.AWS_LAMBDA_FUNCTION_NAME !== undefined
458
378
  const isGCPFunction = getIsGCPFunction()
@@ -478,9 +398,14 @@ class Config {
478
398
 
479
399
  const defaults = setHiddenProperty(this, '_defaults', {})
480
400
 
401
+ this._setValue(defaults, 'appsec.apiSecurity.enabled', true)
402
+ this._setValue(defaults, 'appsec.apiSecurity.requestSampling', 0.1)
403
+ this._setValue(defaults, 'appsec.blockedTemplateGraphql', undefined)
481
404
  this._setValue(defaults, 'appsec.blockedTemplateHtml', undefined)
482
405
  this._setValue(defaults, 'appsec.blockedTemplateJson', undefined)
483
406
  this._setValue(defaults, 'appsec.enabled', undefined)
407
+ this._setValue(defaults, 'appsec.eventTracking.enabled', true)
408
+ this._setValue(defaults, 'appsec.eventTracking.mode', 'safe')
484
409
  this._setValue(defaults, 'appsec.obfuscatorKeyRegex', defaultWafObfuscatorKeyRegex)
485
410
  this._setValue(defaults, 'appsec.obfuscatorValueRegex', defaultWafObfuscatorValueRegex)
486
411
  this._setValue(defaults, 'appsec.rasp.enabled', true)
@@ -516,6 +441,7 @@ class Config {
516
441
  this._setValue(defaults, 'iast.redactionValuePattern', null)
517
442
  this._setValue(defaults, 'iast.requestSampling', 30)
518
443
  this._setValue(defaults, 'iast.telemetryVerbosity', 'INFORMATION')
444
+ this._setValue(defaults, 'isAzureFunction', false)
519
445
  this._setValue(defaults, 'isCiVisibility', false)
520
446
  this._setValue(defaults, 'isEarlyFlakeDetectionEnabled', false)
521
447
  this._setValue(defaults, 'isGCPFunction', false)
@@ -524,6 +450,7 @@ class Config {
524
450
  this._setValue(defaults, 'isManualApiEnabled', false)
525
451
  this._setValue(defaults, 'logInjection', false)
526
452
  this._setValue(defaults, 'lookup', undefined)
453
+ this._setValue(defaults, 'memcachedCommandEnabled', false)
527
454
  this._setValue(defaults, 'openAiLogsEnabled', false)
528
455
  this._setValue(defaults, 'openaiSpanCharLimit', 128)
529
456
  this._setValue(defaults, 'peerServiceMapping', {})
@@ -544,11 +471,14 @@ class Config {
544
471
  this._setValue(defaults, 'sampleRate', undefined)
545
472
  this._setValue(defaults, 'sampler.rateLimit', undefined)
546
473
  this._setValue(defaults, 'sampler.rules', [])
474
+ this._setValue(defaults, 'sampler.spanSamplingRules', [])
547
475
  this._setValue(defaults, 'scope', undefined)
548
476
  this._setValue(defaults, 'service', service)
477
+ this._setValue(defaults, 'serviceMapping', {})
549
478
  this._setValue(defaults, 'site', 'datadoghq.com')
550
479
  this._setValue(defaults, 'spanAttributeSchema', 'v0')
551
480
  this._setValue(defaults, 'spanComputePeerService', false)
481
+ this._setValue(defaults, 'spanLeakDebug', 0)
552
482
  this._setValue(defaults, 'spanRemoveIntegrationFromService', false)
553
483
  this._setValue(defaults, 'startupLogs', false)
554
484
  this._setValue(defaults, 'stats.enabled', false)
@@ -562,6 +492,10 @@ class Config {
562
492
  this._setValue(defaults, 'telemetry.metrics', true)
563
493
  this._setValue(defaults, 'traceId128BitGenerationEnabled', true)
564
494
  this._setValue(defaults, 'traceId128BitLoggingEnabled', false)
495
+ this._setValue(defaults, 'tracePropagationExtractFirst', false)
496
+ this._setValue(defaults, 'tracePropagationStyle.inject', ['datadog', 'tracecontext'])
497
+ this._setValue(defaults, 'tracePropagationStyle.extract', ['datadog', 'tracecontext'])
498
+ this._setValue(defaults, 'tracePropagationStyle.otelPropagators', false)
565
499
  this._setValue(defaults, 'tracing', true)
566
500
  this._setValue(defaults, 'url', undefined)
567
501
  this._setValue(defaults, 'version', pkg.version)
@@ -572,7 +506,11 @@ class Config {
572
506
  const {
573
507
  AWS_LAMBDA_FUNCTION_NAME,
574
508
  DD_AGENT_HOST,
509
+ DD_API_SECURITY_ENABLED,
510
+ DD_API_SECURITY_REQUEST_SAMPLE_RATE,
511
+ DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
575
512
  DD_APPSEC_ENABLED,
513
+ DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
576
514
  DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
577
515
  DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
578
516
  DD_APPSEC_MAX_STACK_TRACES,
@@ -590,6 +528,7 @@ class Config {
590
528
  DD_DOGSTATSD_HOSTNAME,
591
529
  DD_DOGSTATSD_PORT,
592
530
  DD_ENV,
531
+ DD_EXPERIMENTAL_API_SECURITY_ENABLED,
593
532
  DD_EXPERIMENTAL_APPSEC_STANDALONE_ENABLED,
594
533
  DD_EXPERIMENTAL_PROFILING_ENABLED,
595
534
  JEST_WORKER_ID,
@@ -616,8 +555,11 @@ class Config {
616
555
  DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS,
617
556
  DD_RUNTIME_METRICS_ENABLED,
618
557
  DD_SERVICE,
558
+ DD_SERVICE_MAPPING,
619
559
  DD_SERVICE_NAME,
620
560
  DD_SITE,
561
+ DD_SPAN_SAMPLING_RULES,
562
+ DD_SPAN_SAMPLING_RULES_FILE,
621
563
  DD_TAGS,
622
564
  DD_TELEMETRY_DEBUG,
623
565
  DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED,
@@ -637,9 +579,14 @@ class Config {
637
579
  DD_TRACE_GIT_METADATA_ENABLED,
638
580
  DD_TRACE_GLOBAL_TAGS,
639
581
  DD_TRACE_HEADER_TAGS,
582
+ DD_TRACE_MEMCACHED_COMMAND_ENABLED,
640
583
  DD_TRACE_OBFUSCATION_QUERY_STRING_REGEXP,
641
584
  DD_TRACE_PARTIAL_FLUSH_MIN_SPANS,
642
585
  DD_TRACE_PEER_SERVICE_MAPPING,
586
+ DD_TRACE_PROPAGATION_EXTRACT_FIRST,
587
+ DD_TRACE_PROPAGATION_STYLE,
588
+ DD_TRACE_PROPAGATION_STYLE_INJECT,
589
+ DD_TRACE_PROPAGATION_STYLE_EXTRACT,
643
590
  DD_TRACE_RATE_LIMIT,
644
591
  DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED,
645
592
  DD_TRACE_REPORT_HOSTNAME,
@@ -647,17 +594,19 @@ class Config {
647
594
  DD_TRACE_SAMPLING_RULES,
648
595
  DD_TRACE_SCOPE,
649
596
  DD_TRACE_SPAN_ATTRIBUTE_SCHEMA,
597
+ DD_TRACE_SPAN_LEAK_DEBUG,
650
598
  DD_TRACE_STARTUP_LOGS,
651
599
  DD_TRACE_TAGS,
652
600
  DD_TRACE_TELEMETRY_ENABLED,
653
601
  DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH,
654
602
  DD_TRACING_ENABLED,
655
603
  DD_VERSION,
656
- OTEL_SERVICE_NAME,
604
+ OTEL_METRICS_EXPORTER,
605
+ OTEL_PROPAGATORS,
657
606
  OTEL_RESOURCE_ATTRIBUTES,
607
+ OTEL_SERVICE_NAME,
658
608
  OTEL_TRACES_SAMPLER,
659
- OTEL_TRACES_SAMPLER_ARG,
660
- OTEL_METRICS_EXPORTER
609
+ OTEL_TRACES_SAMPLER_ARG
661
610
  } = process.env
662
611
 
663
612
  const tags = {}
@@ -669,11 +618,22 @@ class Config {
669
618
  tagger.add(tags, DD_TRACE_TAGS)
670
619
  tagger.add(tags, DD_TRACE_GLOBAL_TAGS)
671
620
 
621
+ this._setBoolean(env, 'appsec.apiSecurity.enabled', coalesce(
622
+ DD_API_SECURITY_ENABLED && isTrue(DD_API_SECURITY_ENABLED),
623
+ DD_EXPERIMENTAL_API_SECURITY_ENABLED && isTrue(DD_EXPERIMENTAL_API_SECURITY_ENABLED)
624
+ ))
625
+ this._setUnit(env, 'appsec.apiSecurity.requestSampling', DD_API_SECURITY_REQUEST_SAMPLE_RATE)
626
+ this._setValue(env, 'appsec.blockedTemplateGraphql', maybeFile(DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON))
672
627
  this._setValue(env, 'appsec.blockedTemplateHtml', maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML))
673
628
  this._envUnprocessed['appsec.blockedTemplateHtml'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML
674
629
  this._setValue(env, 'appsec.blockedTemplateJson', maybeFile(DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON))
675
630
  this._envUnprocessed['appsec.blockedTemplateJson'] = DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON
676
631
  this._setBoolean(env, 'appsec.enabled', DD_APPSEC_ENABLED)
632
+ if (DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING) {
633
+ this._setValue(env, 'appsec.eventTracking.enabled',
634
+ ['extended', 'safe'].includes(DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING.toLowerCase()))
635
+ this._setValue(env, 'appsec.eventTracking.mode', DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING.toLowerCase())
636
+ }
677
637
  this._setString(env, 'appsec.obfuscatorKeyRegex', DD_APPSEC_OBFUSCATION_PARAMETER_KEY_REGEXP)
678
638
  this._setString(env, 'appsec.obfuscatorValueRegex', DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP)
679
639
  this._setBoolean(env, 'appsec.rasp.enabled', DD_APPSEC_RASP_ENABLED)
@@ -721,8 +681,11 @@ class Config {
721
681
  }
722
682
  this._envUnprocessed['iast.requestSampling'] = DD_IAST_REQUEST_SAMPLING
723
683
  this._setString(env, 'iast.telemetryVerbosity', DD_IAST_TELEMETRY_VERBOSITY)
684
+ this._setBoolean(env, 'isAzureFunction', getIsAzureFunction())
724
685
  this._setBoolean(env, 'isGCPFunction', getIsGCPFunction())
725
686
  this._setBoolean(env, 'logInjection', DD_LOGS_INJECTION)
687
+ // Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
688
+ this._setBoolean(env, 'memcachedCommandEnabled', DD_TRACE_MEMCACHED_COMMAND_ENABLED)
726
689
  this._setBoolean(env, 'openAiLogsEnabled', DD_OPENAI_LOGS_ENABLED)
727
690
  this._setValue(env, 'openaiSpanCharLimit', maybeInt(DD_OPENAI_SPAN_CHAR_LIMIT))
728
691
  this._envUnprocessed.openaiSpanCharLimit = DD_OPENAI_SPAN_CHAR_LIMIT
@@ -762,6 +725,10 @@ class Config {
762
725
  : undefined
763
726
  this._setBoolean(env, 'runtimeMetrics', DD_RUNTIME_METRICS_ENABLED ||
764
727
  otelSetRuntimeMetrics)
728
+ this._setArray(env, 'sampler.spanSamplingRules', reformatSpanSamplingRules(coalesce(
729
+ safeJsonParse(maybeFile(DD_SPAN_SAMPLING_RULES_FILE)),
730
+ safeJsonParse(DD_SPAN_SAMPLING_RULES)
731
+ )))
765
732
  this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE ||
766
733
  getFromOtelSamplerMap(OTEL_TRACES_SAMPLER, OTEL_TRACES_SAMPLER_ARG))
767
734
  this._setValue(env, 'sampler.rateLimit', DD_TRACE_RATE_LIMIT)
@@ -769,11 +736,18 @@ class Config {
769
736
  this._envUnprocessed['sampler.rules'] = DD_TRACE_SAMPLING_RULES
770
737
  this._setString(env, 'scope', DD_TRACE_SCOPE)
771
738
  this._setString(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service || OTEL_SERVICE_NAME)
739
+ if (DD_SERVICE_MAPPING) {
740
+ this._setValue(env, 'serviceMapping', fromEntries(
741
+ process.env.DD_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
742
+ ))
743
+ }
772
744
  this._setString(env, 'site', DD_SITE)
773
745
  if (DD_TRACE_SPAN_ATTRIBUTE_SCHEMA) {
774
746
  this._setString(env, 'spanAttributeSchema', validateNamingVersion(DD_TRACE_SPAN_ATTRIBUTE_SCHEMA))
775
747
  this._envUnprocessed.spanAttributeSchema = DD_TRACE_SPAN_ATTRIBUTE_SCHEMA
776
748
  }
749
+ // 0: disabled, 1: logging, 2: garbage collection + logging
750
+ this._setValue(env, 'spanLeakDebug', maybeInt(DD_TRACE_SPAN_LEAK_DEBUG))
777
751
  this._setBoolean(env, 'spanRemoveIntegrationFromService', DD_TRACE_REMOVE_INTEGRATION_SERVICE_NAMES_ENABLED)
778
752
  this._setBoolean(env, 'startupLogs', DD_TRACE_STARTUP_LOGS)
779
753
  this._setTags(env, 'tags', tags)
@@ -797,6 +771,13 @@ class Config {
797
771
  this._setBoolean(env, 'telemetry.metrics', DD_TELEMETRY_METRICS_ENABLED)
798
772
  this._setBoolean(env, 'traceId128BitGenerationEnabled', DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
799
773
  this._setBoolean(env, 'traceId128BitLoggingEnabled', DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
774
+ this._setBoolean(env, 'tracePropagationExtractFirst', DD_TRACE_PROPAGATION_EXTRACT_FIRST)
775
+ this._setBoolean(env, 'tracePropagationStyle.otelPropagators',
776
+ DD_TRACE_PROPAGATION_STYLE ||
777
+ DD_TRACE_PROPAGATION_STYLE_INJECT ||
778
+ DD_TRACE_PROPAGATION_STYLE_EXTRACT
779
+ ? false
780
+ : !!OTEL_PROPAGATORS)
800
781
  this._setBoolean(env, 'tracing', DD_TRACING_ENABLED)
801
782
  this._setString(env, 'version', DD_VERSION || tags.version)
802
783
  }
@@ -810,11 +791,20 @@ class Config {
810
791
 
811
792
  tagger.add(tags, options.tags)
812
793
 
794
+ this._setBoolean(opts, 'appsec.apiSecurity.enabled', options.appsec.apiSecurity?.enabled)
795
+ this._setUnit(opts, 'appsec.apiSecurity.requestSampling', options.appsec.apiSecurity?.requestSampling)
796
+ this._setValue(opts, 'appsec.blockedTemplateGraphql', maybeFile(options.appsec.blockedTemplateGraphql))
813
797
  this._setValue(opts, 'appsec.blockedTemplateHtml', maybeFile(options.appsec.blockedTemplateHtml))
814
798
  this._optsUnprocessed['appsec.blockedTemplateHtml'] = options.appsec.blockedTemplateHtml
815
799
  this._setValue(opts, 'appsec.blockedTemplateJson', maybeFile(options.appsec.blockedTemplateJson))
816
800
  this._optsUnprocessed['appsec.blockedTemplateJson'] = options.appsec.blockedTemplateJson
817
801
  this._setBoolean(opts, 'appsec.enabled', options.appsec.enabled)
802
+ let eventTracking = options.appsec.eventTracking?.mode
803
+ if (eventTracking) {
804
+ eventTracking = eventTracking.toLowerCase()
805
+ this._setValue(opts, 'appsec.eventTracking.enabled', ['extended', 'safe'].includes(eventTracking))
806
+ this._setValue(opts, 'appsec.eventTracking.mode', eventTracking)
807
+ }
818
808
  this._setString(opts, 'appsec.obfuscatorKeyRegex', options.appsec.obfuscatorKeyRegex)
819
809
  this._setString(opts, 'appsec.obfuscatorValueRegex', options.appsec.obfuscatorValueRegex)
820
810
  this._setBoolean(opts, 'appsec.rasp.enabled', options.appsec.rasp?.enabled)
@@ -880,11 +870,13 @@ class Config {
880
870
  }
881
871
  this._setBoolean(opts, 'reportHostname', options.reportHostname)
882
872
  this._setBoolean(opts, 'runtimeMetrics', options.runtimeMetrics)
873
+ this._setArray(opts, 'sampler.spanSamplingRules', reformatSpanSamplingRules(options.spanSamplingRules))
883
874
  this._setUnit(opts, 'sampleRate', coalesce(options.sampleRate, options.ingestion.sampleRate))
884
875
  const ingestion = options.ingestion || {}
885
876
  this._setValue(opts, 'sampler.rateLimit', coalesce(options.rateLimit, ingestion.rateLimit))
886
877
  this._setSamplingRule(opts, 'sampler.rules', options.samplingRules)
887
878
  this._setString(opts, 'service', options.service || tags.service)
879
+ this._setValue(opts, 'serviceMapping', options.serviceMapping)
888
880
  this._setString(opts, 'site', options.site)
889
881
  if (options.spanAttributeSchema) {
890
882
  this._setString(opts, 'spanAttributeSchema', validateNamingVersion(options.spanAttributeSchema))
@@ -994,7 +986,8 @@ class Config {
994
986
  const calc = setHiddenProperty(this, '_calculated', {})
995
987
 
996
988
  const {
997
- DD_CIVISIBILITY_AGENTLESS_URL
989
+ DD_CIVISIBILITY_AGENTLESS_URL,
990
+ DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED
998
991
  } = process.env
999
992
 
1000
993
  if (DD_CIVISIBILITY_AGENTLESS_URL) {
@@ -1004,7 +997,7 @@ class Config {
1004
997
  }
1005
998
  if (this._isCiVisibility()) {
1006
999
  this._setBoolean(calc, 'isEarlyFlakeDetectionEnabled',
1007
- coalesce(process.env.DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED, true))
1000
+ coalesce(DD_CIVISIBILITY_EARLY_FLAKE_DETECTION_ENABLED, true))
1008
1001
  this._setBoolean(calc, 'isIntelligentTestRunnerEnabled', isTrue(this._isCiVisibilityItrEnabled()))
1009
1002
  this._setBoolean(calc, 'isManualApiEnabled', this._isCiVisibilityManualApiEnabled())
1010
1003
  }
@@ -1013,6 +1006,19 @@ class Config {
1013
1006
  calc.isIntelligentTestRunnerEnabled && !isFalse(this._isCiVisibilityGitUploadEnabled()))
1014
1007
  this._setBoolean(calc, 'spanComputePeerService', this._getSpanComputePeerService())
1015
1008
  this._setBoolean(calc, 'stats.enabled', this._isTraceStatsComputationEnabled())
1009
+ const defaultPropagationStyle = this._getDefaultPropagationStyle(this._optionsArg)
1010
+ this._setValue(calc, 'tracePropagationStyle.inject', propagationStyle(
1011
+ 'inject',
1012
+ this._optionsArg.tracePropagationStyle
1013
+ ))
1014
+ this._setValue(calc, 'tracePropagationStyle.extract', propagationStyle(
1015
+ 'extract',
1016
+ this._optionsArg.tracePropagationStyle
1017
+ ))
1018
+ if (defaultPropagationStyle.length > 2) {
1019
+ calc['tracePropagationStyle.inject'] = calc['tracePropagationStyle.inject'] || defaultPropagationStyle
1020
+ calc['tracePropagationStyle.extract'] = calc['tracePropagationStyle.extract'] || defaultPropagationStyle
1021
+ }
1016
1022
  }
1017
1023
 
1018
1024
  _applyRemote (options) {
@@ -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
  }