dd-trace 4.18.0 → 4.23.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 (137) hide show
  1. package/LICENSE-3rdparty.csv +3 -2
  2. package/README.md +3 -3
  3. package/ext/kinds.d.ts +1 -0
  4. package/ext/kinds.js +2 -1
  5. package/ext/tags.d.ts +2 -1
  6. package/ext/tags.js +6 -1
  7. package/index.d.ts +29 -0
  8. package/package.json +12 -11
  9. package/packages/datadog-core/src/storage/async_resource.js +1 -1
  10. package/packages/datadog-esbuild/index.js +1 -20
  11. package/packages/datadog-instrumentations/src/aerospike.js +47 -0
  12. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  13. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  14. package/packages/datadog-instrumentations/src/child-process.js +4 -5
  15. package/packages/datadog-instrumentations/src/couchbase.js +5 -4
  16. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  17. package/packages/datadog-instrumentations/src/dns.js +2 -1
  18. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  19. package/packages/datadog-instrumentations/src/helpers/bundler-register.js +1 -2
  20. package/packages/datadog-instrumentations/src/helpers/hooks.js +10 -2
  21. package/packages/datadog-instrumentations/src/helpers/instrument.js +9 -4
  22. package/packages/datadog-instrumentations/src/helpers/register.js +19 -3
  23. package/packages/datadog-instrumentations/src/http/client.js +12 -2
  24. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  25. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  26. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  27. package/packages/datadog-instrumentations/src/jest.js +12 -6
  28. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  29. package/packages/datadog-instrumentations/src/net.js +10 -2
  30. package/packages/datadog-instrumentations/src/next.js +18 -6
  31. package/packages/datadog-instrumentations/src/restify.js +14 -1
  32. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  33. package/packages/datadog-plugin-aerospike/src/index.js +113 -0
  34. package/packages/datadog-plugin-cucumber/src/index.js +34 -2
  35. package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
  36. package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
  37. package/packages/datadog-plugin-http/src/client.js +19 -2
  38. package/packages/datadog-plugin-jest/src/index.js +38 -4
  39. package/packages/datadog-plugin-kafkajs/src/consumer.js +59 -6
  40. package/packages/datadog-plugin-kafkajs/src/producer.js +64 -6
  41. package/packages/datadog-plugin-mocha/src/index.js +32 -1
  42. package/packages/datadog-plugin-next/src/index.js +40 -14
  43. package/packages/datadog-plugin-playwright/src/index.js +17 -1
  44. package/packages/dd-trace/src/appsec/activation.js +29 -0
  45. package/packages/dd-trace/src/appsec/addresses.js +3 -1
  46. package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
  47. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  48. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  49. package/packages/dd-trace/src/appsec/channels.js +5 -2
  50. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  51. package/packages/dd-trace/src/appsec/iast/analyzers/analyzers.js +1 -0
  52. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +105 -0
  53. package/packages/dd-trace/src/appsec/iast/iast-log.js +1 -1
  54. package/packages/dd-trace/src/appsec/iast/iast-plugin.js +1 -1
  55. package/packages/dd-trace/src/appsec/iast/index.js +1 -1
  56. package/packages/dd-trace/src/appsec/iast/path-line.js +1 -1
  57. package/packages/dd-trace/src/appsec/iast/taint-tracking/rewriter.js +1 -1
  58. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/constants.js +7 -0
  59. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/command-sensitive-analyzer.js +12 -19
  60. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/header-sensitive-analyzer.js +20 -0
  61. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/json-sensitive-analyzer.js +6 -10
  62. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/ldap-sensitive-analyzer.js +18 -25
  63. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/sql-sensitive-analyzer.js +79 -85
  64. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-analyzers/url-sensitive-analyzer.js +27 -36
  65. package/packages/dd-trace/src/appsec/iast/vulnerabilities-formatter/evidence-redaction/sensitive-handler.js +14 -11
  66. package/packages/dd-trace/src/appsec/iast/vulnerabilities.js +1 -0
  67. package/packages/dd-trace/src/appsec/index.js +33 -32
  68. package/packages/dd-trace/src/appsec/recommended.json +1737 -120
  69. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +6 -1
  70. package/packages/dd-trace/src/appsec/remote_config/index.js +40 -15
  71. package/packages/dd-trace/src/appsec/reporter.js +50 -34
  72. package/packages/dd-trace/src/appsec/rule_manager.js +9 -6
  73. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  74. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +28 -13
  75. package/packages/dd-trace/src/appsec/waf/waf_manager.js +0 -1
  76. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  77. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  78. package/packages/dd-trace/src/ci-visibility/exporters/ci-visibility-exporter.js +17 -1
  79. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +110 -59
  80. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +40 -7
  81. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
  82. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  83. package/packages/dd-trace/src/config.js +145 -63
  84. package/packages/dd-trace/src/datastreams/processor.js +166 -26
  85. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
  86. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  87. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  88. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  89. package/packages/dd-trace/src/format.js +6 -1
  90. package/packages/dd-trace/src/id.js +12 -0
  91. package/packages/dd-trace/src/iitm.js +1 -1
  92. package/packages/dd-trace/src/log/channels.js +1 -1
  93. package/packages/dd-trace/src/noop/proxy.js +4 -0
  94. package/packages/dd-trace/src/opentelemetry/span.js +95 -2
  95. package/packages/dd-trace/src/opentelemetry/tracer.js +9 -10
  96. package/packages/dd-trace/src/opentracing/propagation/text_map.js +14 -5
  97. package/packages/dd-trace/src/opentracing/span.js +6 -0
  98. package/packages/dd-trace/src/opentracing/span_context.js +5 -2
  99. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  100. package/packages/dd-trace/src/plugin_manager.js +1 -1
  101. package/packages/dd-trace/src/plugins/ci_plugin.js +46 -9
  102. package/packages/dd-trace/src/plugins/database.js +1 -1
  103. package/packages/dd-trace/src/plugins/index.js +6 -0
  104. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  105. package/packages/dd-trace/src/plugins/util/ci.js +6 -19
  106. package/packages/dd-trace/src/plugins/util/exec.js +23 -2
  107. package/packages/dd-trace/src/plugins/util/git.js +98 -22
  108. package/packages/dd-trace/src/plugins/util/ip_extractor.js +7 -6
  109. package/packages/dd-trace/src/plugins/util/test.js +3 -2
  110. package/packages/dd-trace/src/plugins/util/url.js +26 -0
  111. package/packages/dd-trace/src/plugins/util/user-provided-git.js +4 -16
  112. package/packages/dd-trace/src/priority_sampler.js +30 -38
  113. package/packages/dd-trace/src/profiler.js +5 -3
  114. package/packages/dd-trace/src/profiling/config.js +26 -2
  115. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
  116. package/packages/dd-trace/src/profiling/profiler.js +17 -10
  117. package/packages/dd-trace/src/profiling/profilers/events.js +264 -0
  118. package/packages/dd-trace/src/profiling/profilers/shared.js +39 -0
  119. package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
  120. package/packages/dd-trace/src/profiling/profilers/wall.js +121 -58
  121. package/packages/dd-trace/src/proxy.js +25 -1
  122. package/packages/dd-trace/src/ritm.js +1 -1
  123. package/packages/dd-trace/src/sampling_rule.js +130 -0
  124. package/packages/dd-trace/src/service-naming/schemas/v0/storage.js +5 -0
  125. package/packages/dd-trace/src/service-naming/schemas/v1/storage.js +4 -0
  126. package/packages/dd-trace/src/span_processor.js +4 -0
  127. package/packages/dd-trace/src/span_sampler.js +6 -64
  128. package/packages/dd-trace/src/spanleak.js +98 -0
  129. package/packages/dd-trace/src/startup-log.js +7 -1
  130. package/packages/dd-trace/src/telemetry/dependencies.js +56 -10
  131. package/packages/dd-trace/src/telemetry/index.js +171 -41
  132. package/packages/dd-trace/src/telemetry/logs/index.js +2 -2
  133. package/packages/dd-trace/src/telemetry/send-data.js +47 -5
  134. package/packages/dd-trace/src/tracer.js +8 -2
  135. package/scripts/install_plugin_modules.js +11 -3
  136. package/packages/diagnostics_channel/index.js +0 -3
  137. package/packages/diagnostics_channel/src/index.js +0 -121
@@ -109,13 +109,6 @@ class Config {
109
109
  log.use(this.logger)
110
110
  log.toggle(this.debug, this.logLevel, this)
111
111
 
112
- this.tags = {}
113
-
114
- tagger.add(this.tags, process.env.DD_TAGS)
115
- tagger.add(this.tags, process.env.DD_TRACE_TAGS)
116
- tagger.add(this.tags, process.env.DD_TRACE_GLOBAL_TAGS)
117
- tagger.add(this.tags, options.tags)
118
-
119
112
  const DD_TRACING_ENABLED = coalesce(
120
113
  process.env.DD_TRACING_ENABLED,
121
114
  true
@@ -184,33 +177,12 @@ class Config {
184
177
  false
185
178
  )
186
179
 
187
- const DD_SERVICE = options.service ||
188
- process.env.DD_SERVICE ||
189
- process.env.DD_SERVICE_NAME ||
190
- this.tags.service ||
191
- process.env.AWS_LAMBDA_FUNCTION_NAME ||
192
- process.env.FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
193
- process.env.K_SERVICE || // Google Cloud Function Name set by newer runtimes
194
- process.env.WEBSITE_SITE_NAME || // set by Azure Functions
195
- pkg.name ||
196
- 'node'
197
180
  const DD_SERVICE_MAPPING = coalesce(
198
181
  options.serviceMapping,
199
182
  process.env.DD_SERVICE_MAPPING ? fromEntries(
200
183
  process.env.DD_SERVICE_MAPPING.split(',').map(x => x.trim().split(':'))
201
184
  ) : {}
202
185
  )
203
- const DD_ENV = coalesce(
204
- options.env,
205
- process.env.DD_ENV,
206
- this.tags.env
207
- )
208
- const DD_VERSION = coalesce(
209
- options.version,
210
- process.env.DD_VERSION,
211
- this.tags.version,
212
- pkg.version
213
- )
214
186
  const DD_TRACE_STARTUP_LOGS = coalesce(
215
187
  options.startupLogs,
216
188
  process.env.DD_TRACE_STARTUP_LOGS,
@@ -235,8 +207,9 @@ class Config {
235
207
 
236
208
  const inServerlessEnvironment = inAWSLambda || isGCPFunction || isAzureFunctionConsumptionPlan
237
209
 
238
- const DD_TRACE_TELEMETRY_ENABLED = coalesce(
239
- process.env.DD_TRACE_TELEMETRY_ENABLED,
210
+ const DD_INSTRUMENTATION_TELEMETRY_ENABLED = coalesce(
211
+ process.env.DD_TRACE_TELEMETRY_ENABLED, // for backward compatibility
212
+ process.env.DD_INSTRUMENTATION_TELEMETRY_ENABLED, // to comply with instrumentation telemetry specs
240
213
  !inServerlessEnvironment
241
214
  )
242
215
  const DD_TELEMETRY_HEARTBEAT_INTERVAL = process.env.DD_TELEMETRY_HEARTBEAT_INTERVAL
@@ -308,6 +281,10 @@ class Config {
308
281
  options.tracePropagationStyle,
309
282
  defaultPropagationStyle
310
283
  )
284
+ const DD_TRACE_PROPAGATION_EXTRACT_FIRST = coalesce(
285
+ process.env.DD_TRACE_PROPAGATION_EXTRACT_FIRST,
286
+ false
287
+ )
311
288
  const DD_TRACE_RUNTIME_ID_ENABLED = coalesce(
312
289
  options.experimental && options.experimental.runtimeId,
313
290
  process.env.DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED,
@@ -367,10 +344,11 @@ class Config {
367
344
  isGCPFunction || isAzureFunctionConsumptionPlan
368
345
  )
369
346
 
347
+ // the tracer generates 128 bit IDs by default as of v5
370
348
  const DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED = coalesce(
371
349
  options.traceId128BitGenerationEnabled,
372
350
  process.env.DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED,
373
- false
351
+ true
374
352
  )
375
353
 
376
354
  const DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED = coalesce(
@@ -393,7 +371,6 @@ class Config {
393
371
  appsec.enabled,
394
372
  process.env.DD_APPSEC_ENABLED && isTrue(process.env.DD_APPSEC_ENABLED)
395
373
  )
396
-
397
374
  const DD_APPSEC_RULES = coalesce(
398
375
  appsec.rules,
399
376
  process.env.DD_APPSEC_RULES
@@ -430,11 +407,25 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
430
407
  maybeFile(appsec.blockedTemplateJson),
431
408
  maybeFile(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
432
409
  )
410
+ const DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON = coalesce(
411
+ maybeFile(appsec.blockedTemplateGraphql),
412
+ maybeFile(process.env.DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON)
413
+ )
433
414
  const DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING = coalesce(
434
415
  appsec.eventTracking && appsec.eventTracking.mode,
435
416
  process.env.DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
436
417
  'safe'
437
418
  ).toLowerCase()
419
+ const DD_EXPERIMENTAL_API_SECURITY_ENABLED = coalesce(
420
+ appsec?.apiSecurity?.enabled,
421
+ isTrue(process.env.DD_EXPERIMENTAL_API_SECURITY_ENABLED),
422
+ false
423
+ )
424
+ const DD_API_SECURITY_REQUEST_SAMPLE_RATE = coalesce(
425
+ appsec?.apiSecurity?.requestSampling,
426
+ parseFloat(process.env.DD_API_SECURITY_REQUEST_SAMPLE_RATE),
427
+ 0.1
428
+ )
438
429
 
439
430
  const remoteConfigOptions = options.remoteConfig || {}
440
431
  const DD_REMOTE_CONFIGURATION_ENABLED = coalesce(
@@ -459,6 +450,11 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
459
450
  DD_IAST_ENABLED
460
451
  )
461
452
 
453
+ const DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED = coalesce(
454
+ process.env.DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED,
455
+ true
456
+ )
457
+
462
458
  const defaultIastRequestSampling = 30
463
459
  const iastRequestSampling = coalesce(
464
460
  parseInt(iastOptions?.requestSampling),
@@ -520,6 +516,25 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
520
516
  true
521
517
  )
522
518
 
519
+ // 0: disabled, 1: logging, 2: garbage collection + logging
520
+ const DD_TRACE_SPAN_LEAK_DEBUG = coalesce(
521
+ process.env.DD_TRACE_SPAN_LEAK_DEBUG,
522
+ 0
523
+ )
524
+
525
+ const DD_INSTRUMENTATION_INSTALL_ID = coalesce(
526
+ process.env.DD_INSTRUMENTATION_INSTALL_ID,
527
+ null
528
+ )
529
+ const DD_INSTRUMENTATION_INSTALL_TIME = coalesce(
530
+ process.env.DD_INSTRUMENTATION_INSTALL_TIME,
531
+ null
532
+ )
533
+ const DD_INSTRUMENTATION_INSTALL_TYPE = coalesce(
534
+ process.env.DD_INSTRUMENTATION_INSTALL_TYPE,
535
+ null
536
+ )
537
+
523
538
  const ingestion = options.ingestion || {}
524
539
  const dogstatsd = coalesce(options.dogstatsd, {})
525
540
  const sampler = {
@@ -553,7 +568,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
553
568
  this.dsmEnabled = isTrue(DD_DATA_STREAMS_ENABLED)
554
569
  this.openAiLogsEnabled = DD_OPENAI_LOGS_ENABLED
555
570
  this.apiKey = DD_API_KEY
556
- this.env = DD_ENV
557
571
  this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
558
572
  : getAgentUrl(DD_TRACE_AGENT_URL, options)
559
573
  this.site = coalesce(options.site, process.env.DD_SITE, 'datadoghq.com')
@@ -565,9 +579,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
565
579
  this.clientIpEnabled = DD_TRACE_CLIENT_IP_ENABLED
566
580
  this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
567
581
  this.plugins = !!coalesce(options.plugins, true)
568
- this.service = DD_SERVICE
569
582
  this.serviceMapping = DD_SERVICE_MAPPING
570
- this.version = DD_VERSION
571
583
  this.dogstatsd = {
572
584
  hostname: coalesce(dogstatsd.hostname, process.env.DD_DOGSTATSD_HOSTNAME, this.hostname),
573
585
  port: String(coalesce(dogstatsd.port, process.env.DD_DOGSTATSD_PORT, 8125))
@@ -577,6 +589,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
577
589
  inject: DD_TRACE_PROPAGATION_STYLE_INJECT,
578
590
  extract: DD_TRACE_PROPAGATION_STYLE_EXTRACT
579
591
  }
592
+ this.tracePropagationExtractFirst = isTrue(DD_TRACE_PROPAGATION_EXTRACT_FIRST)
580
593
  this.experimental = {
581
594
  runtimeId: isTrue(DD_TRACE_RUNTIME_ID_ENABLED),
582
595
  exporter: DD_TRACE_EXPORTER,
@@ -598,17 +611,18 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
598
611
  this.startupLogs = isTrue(DD_TRACE_STARTUP_LOGS)
599
612
  // Disabled for CI Visibility's agentless
600
613
  this.telemetry = {
601
- enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_TRACE_TELEMETRY_ENABLED),
614
+ enabled: DD_TRACE_EXPORTER !== 'datadog' && isTrue(DD_INSTRUMENTATION_TELEMETRY_ENABLED),
602
615
  heartbeatInterval: DD_TELEMETRY_HEARTBEAT_INTERVAL,
603
616
  debug: isTrue(DD_TELEMETRY_DEBUG),
604
617
  logCollection: isTrue(DD_TELEMETRY_LOG_COLLECTION_ENABLED),
605
- metrics: isTrue(DD_TELEMETRY_METRICS_ENABLED)
618
+ metrics: isTrue(DD_TELEMETRY_METRICS_ENABLED),
619
+ dependencyCollection: DD_TELEMETRY_DEPENDENCY_COLLECTION_ENABLED
606
620
  }
607
621
  this.protocolVersion = DD_TRACE_AGENT_PROTOCOL_VERSION
608
622
  this.tagsHeaderMaxLength = parseInt(DD_TRACE_X_DATADOG_TAGS_MAX_LENGTH)
609
623
  this.appsec = {
610
624
  enabled: DD_APPSEC_ENABLED,
611
- rules: DD_APPSEC_RULES ? safeJsonParse(maybeFile(DD_APPSEC_RULES)) : require('./appsec/recommended.json'),
625
+ rules: DD_APPSEC_RULES,
612
626
  customRulesProvided: !!DD_APPSEC_RULES,
613
627
  rateLimit: DD_APPSEC_TRACE_RATE_LIMIT,
614
628
  wafTimeout: DD_APPSEC_WAF_TIMEOUT,
@@ -616,11 +630,18 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
616
630
  obfuscatorValueRegex: DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
617
631
  blockedTemplateHtml: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
618
632
  blockedTemplateJson: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
633
+ blockedTemplateGraphql: DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
619
634
  eventTracking: {
620
635
  enabled: ['extended', 'safe'].includes(DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING),
621
636
  mode: DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING
637
+ },
638
+ apiSecurity: {
639
+ enabled: DD_EXPERIMENTAL_API_SECURITY_ENABLED,
640
+ // Coerce value between 0 and 1
641
+ requestSampling: Math.min(1, Math.max(0, DD_API_SECURITY_REQUEST_SAMPLE_RATE))
622
642
  }
623
643
  }
644
+
624
645
  this.remoteConfig = {
625
646
  enabled: DD_REMOTE_CONFIGURATION_ENABLED,
626
647
  pollInterval: DD_REMOTE_CONFIG_POLL_INTERVAL_SECONDS
@@ -651,6 +672,37 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
651
672
  // Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
652
673
  this.memcachedCommandEnabled = isTrue(DD_TRACE_MEMCACHED_COMMAND_ENABLED)
653
674
 
675
+ this.stats = {
676
+ enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
677
+ }
678
+
679
+ this.traceId128BitGenerationEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
680
+ this.traceId128BitLoggingEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
681
+
682
+ this.isGCPFunction = isGCPFunction
683
+ this.isAzureFunctionConsumptionPlan = isAzureFunctionConsumptionPlan
684
+
685
+ this.spanLeakDebug = Number(DD_TRACE_SPAN_LEAK_DEBUG)
686
+
687
+ this.installSignature = {
688
+ id: DD_INSTRUMENTATION_INSTALL_ID,
689
+ time: DD_INSTRUMENTATION_INSTALL_TIME,
690
+ type: DD_INSTRUMENTATION_INSTALL_TYPE
691
+ }
692
+
693
+ this._applyDefaults()
694
+ this._applyEnvironment()
695
+ this._applyOptions(options)
696
+ this._applyRemote({})
697
+ this._merge()
698
+
699
+ tagger.add(this.tags, {
700
+ service: this.service,
701
+ env: this.env,
702
+ version: this.version,
703
+ 'runtime-id': uuid()
704
+ })
705
+
654
706
  if (this.gitMetadataEnabled) {
655
707
  this.repositoryUrl = removeUserSensitiveInfo(
656
708
  coalesce(
@@ -683,29 +735,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
683
735
  }
684
736
  }
685
737
  }
686
-
687
- this.stats = {
688
- enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
689
- }
690
-
691
- this.traceId128BitGenerationEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
692
- this.traceId128BitLoggingEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
693
-
694
- this.isGCPFunction = isGCPFunction
695
- this.isAzureFunctionConsumptionPlan = isAzureFunctionConsumptionPlan
696
-
697
- tagger.add(this.tags, {
698
- service: this.service,
699
- env: this.env,
700
- version: this.version,
701
- 'runtime-id': uuid()
702
- })
703
-
704
- this._applyDefaults()
705
- this._applyEnvironment()
706
- this._applyOptions(options)
707
- this._applyRemote({})
708
- this._merge()
709
738
  }
710
739
 
711
740
  // Supports only a subset of options for now.
@@ -720,48 +749,93 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
720
749
  }
721
750
 
722
751
  _applyDefaults () {
752
+ const {
753
+ AWS_LAMBDA_FUNCTION_NAME,
754
+ FUNCTION_NAME,
755
+ K_SERVICE,
756
+ WEBSITE_SITE_NAME
757
+ } = process.env
758
+
759
+ const service = AWS_LAMBDA_FUNCTION_NAME ||
760
+ FUNCTION_NAME || // Google Cloud Function Name set by deprecated runtimes
761
+ K_SERVICE || // Google Cloud Function Name set by newer runtimes
762
+ WEBSITE_SITE_NAME || // set by Azure Functions
763
+ pkg.name ||
764
+ 'node'
765
+
723
766
  const defaults = this._defaults = {}
724
767
 
768
+ this._setValue(defaults, 'service', service)
769
+ this._setValue(defaults, 'env', undefined)
770
+ this._setValue(defaults, 'version', pkg.version)
725
771
  this._setUnit(defaults, 'sampleRate', undefined)
726
772
  this._setBoolean(defaults, 'logInjection', false)
727
773
  this._setArray(defaults, 'headerTags', [])
774
+ this._setValue(defaults, 'tags', {})
728
775
  }
729
776
 
730
777
  _applyEnvironment () {
731
778
  const {
732
- DD_TRACE_SAMPLE_RATE,
779
+ DD_ENV,
733
780
  DD_LOGS_INJECTION,
734
- DD_TRACE_HEADER_TAGS
781
+ DD_SERVICE,
782
+ DD_SERVICE_NAME,
783
+ DD_TAGS,
784
+ DD_TRACE_GLOBAL_TAGS,
785
+ DD_TRACE_HEADER_TAGS,
786
+ DD_TRACE_SAMPLE_RATE,
787
+ DD_TRACE_TAGS,
788
+ DD_VERSION
735
789
  } = process.env
736
790
 
791
+ const tags = {}
737
792
  const env = this._env = {}
738
793
 
794
+ tagger.add(tags, DD_TAGS)
795
+ tagger.add(tags, DD_TRACE_TAGS)
796
+ tagger.add(tags, DD_TRACE_GLOBAL_TAGS)
797
+
798
+ this._setValue(env, 'service', DD_SERVICE || DD_SERVICE_NAME || tags.service)
799
+ this._setValue(env, 'env', DD_ENV || tags.env)
800
+ this._setValue(env, 'version', DD_VERSION || tags.version)
739
801
  this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE)
740
802
  this._setBoolean(env, 'logInjection', DD_LOGS_INJECTION)
741
803
  this._setArray(env, 'headerTags', DD_TRACE_HEADER_TAGS)
804
+ this._setTags(env, 'tags', tags)
742
805
  }
743
806
 
744
807
  _applyOptions (options) {
745
808
  const opts = this._options = this._options || {}
809
+ const tags = {}
746
810
 
747
811
  options = Object.assign({ ingestion: {} }, options, opts)
748
812
 
813
+ tagger.add(tags, options.tags)
814
+
815
+ this._setValue(opts, 'service', options.service || tags.service)
816
+ this._setValue(opts, 'env', options.env || tags.env)
817
+ this._setValue(opts, 'version', options.version || tags.version)
749
818
  this._setUnit(opts, 'sampleRate', coalesce(options.sampleRate, options.ingestion.sampleRate))
750
819
  this._setBoolean(opts, 'logInjection', options.logInjection)
751
820
  this._setArray(opts, 'headerTags', options.headerTags)
821
+ this._setTags(opts, 'tags', tags)
752
822
  }
753
823
 
754
824
  _applyRemote (options) {
755
825
  const opts = this._remote = this._remote || {}
826
+ const tags = {}
756
827
  const headerTags = options.tracing_header_tags
757
828
  ? options.tracing_header_tags.map(tag => {
758
829
  return tag.tag_name ? `${tag.header}:${tag.tag_name}` : tag.header
759
830
  })
760
831
  : undefined
761
832
 
833
+ tagger.add(tags, options.tracing_tags)
834
+
762
835
  this._setUnit(opts, 'sampleRate', options.tracing_sampling_rate)
763
836
  this._setBoolean(opts, 'logInjection', options.log_injection_enabled)
764
837
  this._setArray(opts, 'headerTags', headerTags)
838
+ this._setTags(opts, 'tags', tags)
765
839
  }
766
840
 
767
841
  _setBoolean (obj, name, value) {
@@ -801,6 +875,14 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
801
875
  }
802
876
  }
803
877
 
878
+ _setTags (obj, name, value) {
879
+ if (!value || Object.keys(value).length === 0) {
880
+ return this._setValue(obj, name, null)
881
+ }
882
+
883
+ this._setValue(obj, name, value)
884
+ }
885
+
804
886
  _setValue (obj, name, value) {
805
887
  obj[name] = value
806
888
  }
@@ -4,12 +4,16 @@ const pkg = require('../../../../package.json')
4
4
  const Uint64 = require('int64-buffer').Uint64BE
5
5
 
6
6
  const { LogCollapsingLowestDenseDDSketch } = require('@datadog/sketches-js')
7
-
7
+ const { encodePathwayContext } = require('./pathway')
8
8
  const { DataStreamsWriter } = require('./writer')
9
9
  const { computePathwayHash } = require('./pathway')
10
+ const { types } = require('util')
11
+ const { PATHWAY_HASH } = require('../../../../ext/tags')
12
+
10
13
  const ENTRY_PARENT_HASH = Buffer.from('0000000000000000', 'hex')
11
14
 
12
15
  const HIGH_ACCURACY_DISTRIBUTION = 0.0075
16
+ const CONTEXT_PROPAGATION_KEY = 'dd-pathway-ctx'
13
17
 
14
18
  class StatsPoint {
15
19
  constructor (hash, parentHash, edgeTags) {
@@ -18,6 +22,7 @@ class StatsPoint {
18
22
  this.edgeTags = edgeTags
19
23
  this.edgeLatency = new LogCollapsingLowestDenseDDSketch(HIGH_ACCURACY_DISTRIBUTION)
20
24
  this.pathwayLatency = new LogCollapsingLowestDenseDDSketch(HIGH_ACCURACY_DISTRIBUTION)
25
+ this.payloadSize = new LogCollapsingLowestDenseDDSketch(HIGH_ACCURACY_DISTRIBUTION)
21
26
  }
22
27
 
23
28
  addLatencies (checkpoint) {
@@ -25,6 +30,7 @@ class StatsPoint {
25
30
  const pathwayLatencySec = checkpoint.pathwayLatencyNs / 1e9
26
31
  this.edgeLatency.accept(edgeLatencySec)
27
32
  this.pathwayLatency.accept(pathwayLatencySec)
33
+ this.payloadSize.accept(checkpoint.payloadSize)
28
34
  }
29
35
 
30
36
  encode () {
@@ -33,22 +39,105 @@ class StatsPoint {
33
39
  ParentHash: this.parentHash,
34
40
  EdgeTags: this.edgeTags,
35
41
  EdgeLatency: this.edgeLatency.toProto(),
36
- PathwayLatency: this.pathwayLatency.toProto()
42
+ PathwayLatency: this.pathwayLatency.toProto(),
43
+ PayloadSize: this.payloadSize.toProto()
37
44
  }
38
45
  }
39
46
  }
40
47
 
41
- class StatsBucket extends Map {
48
+ class Backlog {
49
+ constructor ({ offset, ...tags }) {
50
+ this._tags = Object.keys(tags).sort().map(key => `${key}:${tags[key]}`)
51
+ this._hash = this._tags.join(',')
52
+ this._offset = offset
53
+ }
54
+
55
+ get hash () { return this._hash }
56
+
57
+ get offset () { return this._offset }
58
+
59
+ get tags () { return this._tags }
60
+
61
+ encode () {
62
+ return {
63
+ Tags: this.tags,
64
+ Value: this.offset
65
+ }
66
+ }
67
+ }
68
+
69
+ class StatsBucket {
70
+ constructor () {
71
+ this._checkpoints = new Map()
72
+ this._backlogs = new Map()
73
+ }
74
+
75
+ get checkpoints () {
76
+ return this._checkpoints
77
+ }
78
+
79
+ get backlogs () {
80
+ return this._backlogs
81
+ }
82
+
42
83
  forCheckpoint (checkpoint) {
43
84
  const key = checkpoint.hash
44
- if (!this.has(key)) {
45
- this.set(key, new StatsPoint(checkpoint.hash, checkpoint.parentHash, checkpoint.edgeTags)) // StatsPoint
85
+ if (!this._checkpoints.has(key)) {
86
+ this._checkpoints.set(
87
+ key, new StatsPoint(checkpoint.hash, checkpoint.parentHash, checkpoint.edgeTags)
88
+ )
46
89
  }
47
90
 
48
- return this.get(key)
91
+ return this._checkpoints.get(key)
92
+ }
93
+
94
+ /**
95
+ * Conditionally add a backlog to the bucket. If there is currently an offset
96
+ * matching the backlog's tags, overwrite the offset IFF the backlog's offset
97
+ * is greater than the recorded offset.
98
+ *
99
+ * @typedef {{[key: string]: string}} BacklogData
100
+ * @property {number} offset
101
+ *
102
+ * @param {BacklogData} backlogData
103
+ * @returns {Backlog}
104
+ */
105
+ forBacklog (backlogData) {
106
+ const backlog = new Backlog(backlogData)
107
+ const existingBacklog = this._backlogs.get(backlog.hash)
108
+ if (existingBacklog !== undefined) {
109
+ if (existingBacklog.offset > backlog.offset) {
110
+ return existingBacklog
111
+ }
112
+ }
113
+ this._backlogs.set(backlog.hash, backlog)
114
+ return backlog
49
115
  }
50
116
  }
51
117
 
118
+ function getSizeOrZero (obj) {
119
+ if (typeof obj === 'string') {
120
+ return Buffer.from(obj, 'utf-8').length
121
+ }
122
+ if (types.isArrayBuffer(obj)) {
123
+ return obj.byteLength
124
+ }
125
+ if (Buffer.isBuffer(obj)) {
126
+ return obj.length
127
+ }
128
+ return 0
129
+ }
130
+
131
+ function getHeadersSize (headers) {
132
+ if (headers === undefined) return 0
133
+ return Object.entries(headers).reduce((prev, [key, val]) => getSizeOrZero(key) + getSizeOrZero(val) + prev, 0)
134
+ }
135
+
136
+ function getMessageSize (message) {
137
+ const { key, value, headers } = message
138
+ return getSizeOrZero(key) + getSizeOrZero(value) + getHeadersSize(headers)
139
+ }
140
+
52
141
  class TimeBuckets extends Map {
53
142
  forTime (time) {
54
143
  if (!this.has(time)) {
@@ -92,12 +181,12 @@ class DataStreamsProcessor {
92
181
  }
93
182
 
94
183
  onInterval () {
95
- const serialized = this._serializeBuckets()
96
- if (!serialized) return
184
+ const { Stats } = this._serializeBuckets()
185
+ if (Stats.length === 0) return
97
186
  const payload = {
98
187
  Env: this.env,
99
188
  Service: this.service,
100
- Stats: serialized,
189
+ Stats,
101
190
  TracerVersion: pkg.version,
102
191
  Version: this.version,
103
192
  Lang: 'javascript'
@@ -105,15 +194,28 @@ class DataStreamsProcessor {
105
194
  this.writer.flush(payload)
106
195
  }
107
196
 
108
- recordCheckpoint (checkpoint) {
197
+ /**
198
+ * Given a timestamp in nanoseconds, compute and return the closest TimeBucket
199
+ * @param {number} timestamp
200
+ * @returns {StatsBucket}
201
+ */
202
+ bucketFromTimestamp (timestamp) {
203
+ const bucketTime = Math.round(timestamp - (timestamp % this.bucketSizeNs))
204
+ return this.buckets.forTime(bucketTime)
205
+ }
206
+
207
+ recordCheckpoint (checkpoint, span = null) {
109
208
  if (!this.enabled) return
110
- const bucketTime = Math.round(checkpoint.currentTimestamp - (checkpoint.currentTimestamp % this.bucketSizeNs))
111
- this.buckets.forTime(bucketTime)
209
+ this.bucketFromTimestamp(checkpoint.currentTimestamp)
112
210
  .forCheckpoint(checkpoint)
113
211
  .addLatencies(checkpoint)
212
+ // set DSM pathway hash on span to enable related traces feature on DSM tab, convert from buffer to uint64
213
+ if (span) {
214
+ span.setTag(PATHWAY_HASH, checkpoint.hash.readBigUInt64BE(0).toString())
215
+ }
114
216
  }
115
217
 
116
- setCheckpoint (edgeTags, ctx = null) {
218
+ setCheckpoint (edgeTags, span, ctx = null, payloadSize = 0) {
117
219
  if (!this.enabled) return null
118
220
  const nowNs = Date.now() * 1e6
119
221
  const direction = edgeTags.find(t => t.startsWith('direction:'))
@@ -147,45 +249,78 @@ class DataStreamsProcessor {
147
249
  const hash = computePathwayHash(this.service, this.env, edgeTags, parentHash)
148
250
  const edgeLatencyNs = nowNs - edgeStartNs
149
251
  const pathwayLatencyNs = nowNs - pathwayStartNs
252
+ const dataStreamsContext = {
253
+ hash: hash,
254
+ edgeStartNs: edgeStartNs,
255
+ pathwayStartNs: pathwayStartNs,
256
+ previousDirection: direction,
257
+ closestOppositeDirectionHash: closestOppositeDirectionHash,
258
+ closestOppositeDirectionEdgeStart: closestOppositeDirectionEdgeStart
259
+ }
260
+ if (direction === 'direction:out') {
261
+ // Add the header for this now, as the callee doesn't have access to context when producing
262
+ payloadSize += getSizeOrZero(encodePathwayContext(dataStreamsContext))
263
+ payloadSize += CONTEXT_PROPAGATION_KEY.length
264
+ }
150
265
  const checkpoint = {
151
266
  currentTimestamp: nowNs,
152
267
  parentHash: parentHash,
153
268
  hash: hash,
154
269
  edgeTags: edgeTags,
155
270
  edgeLatencyNs: edgeLatencyNs,
156
- pathwayLatencyNs: pathwayLatencyNs
271
+ pathwayLatencyNs: pathwayLatencyNs,
272
+ payloadSize: payloadSize
157
273
  }
158
- this.recordCheckpoint(checkpoint)
159
- return {
160
- hash: hash,
161
- edgeStartNs: edgeStartNs,
162
- pathwayStartNs: pathwayStartNs,
163
- previousDirection: direction,
164
- closestOppositeDirectionHash: closestOppositeDirectionHash,
165
- closestOppositeDirectionEdgeStart: closestOppositeDirectionEdgeStart
274
+ this.recordCheckpoint(checkpoint, span)
275
+ return dataStreamsContext
276
+ }
277
+
278
+ recordOffset ({ timestamp, ...backlogData }) {
279
+ if (!this.enabled) return
280
+ return this.bucketFromTimestamp(timestamp)
281
+ .forBacklog(backlogData)
282
+ }
283
+
284
+ setOffset (offsetObj) {
285
+ if (!this.enabled) return
286
+ const nowNs = Date.now() * 1e6
287
+ const backlogData = {
288
+ ...offsetObj,
289
+ timestamp: nowNs
166
290
  }
291
+ this.recordOffset(backlogData)
167
292
  }
168
293
 
169
294
  _serializeBuckets () {
295
+ // TimeBuckets
170
296
  const serializedBuckets = []
171
297
 
172
298
  for (const [ timeNs, bucket ] of this.buckets.entries()) {
173
299
  const points = []
174
300
 
175
- for (const stats of bucket.values()) {
301
+ // bucket: StatsBucket
302
+ // stats: StatsPoint
303
+ for (const stats of bucket._checkpoints.values()) {
176
304
  points.push(stats.encode())
177
305
  }
178
306
 
307
+ const backlogs = []
308
+ for (const backlog of bucket._backlogs.values()) {
309
+ backlogs.push(backlog.encode())
310
+ }
179
311
  serializedBuckets.push({
180
312
  Start: new Uint64(timeNs),
181
313
  Duration: new Uint64(this.bucketSizeNs),
182
- Stats: points
314
+ Stats: points,
315
+ Backlogs: backlogs
183
316
  })
184
317
  }
185
318
 
186
319
  this.buckets.clear()
187
320
 
188
- return serializedBuckets
321
+ return {
322
+ Stats: serializedBuckets
323
+ }
189
324
  }
190
325
  }
191
326
 
@@ -193,6 +328,11 @@ module.exports = {
193
328
  DataStreamsProcessor: DataStreamsProcessor,
194
329
  StatsPoint: StatsPoint,
195
330
  StatsBucket: StatsBucket,
331
+ Backlog,
196
332
  TimeBuckets,
197
- ENTRY_PARENT_HASH
333
+ getMessageSize,
334
+ getHeadersSize,
335
+ getSizeOrZero,
336
+ ENTRY_PARENT_HASH,
337
+ CONTEXT_PROPAGATION_KEY
198
338
  }