dd-trace 5.0.0-pre-069b62a → 5.0.0-pre-e2df7ec

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 (76) hide show
  1. package/LICENSE-3rdparty.csv +1 -0
  2. package/index.d.ts +5 -0
  3. package/package.json +4 -3
  4. package/packages/datadog-instrumentations/src/apollo-server-core.js +41 -0
  5. package/packages/datadog-instrumentations/src/apollo-server.js +83 -0
  6. package/packages/datadog-instrumentations/src/child-process.js +4 -5
  7. package/packages/datadog-instrumentations/src/crypto.js +2 -1
  8. package/packages/datadog-instrumentations/src/dns.js +2 -1
  9. package/packages/datadog-instrumentations/src/graphql.js +18 -4
  10. package/packages/datadog-instrumentations/src/helpers/hooks.js +9 -2
  11. package/packages/datadog-instrumentations/src/helpers/instrument.js +8 -3
  12. package/packages/datadog-instrumentations/src/helpers/register.js +18 -2
  13. package/packages/datadog-instrumentations/src/http/client.js +4 -16
  14. package/packages/datadog-instrumentations/src/http/server.js +7 -4
  15. package/packages/datadog-instrumentations/src/http2/client.js +3 -1
  16. package/packages/datadog-instrumentations/src/http2/server.js +3 -1
  17. package/packages/datadog-instrumentations/src/jest.js +1 -1
  18. package/packages/datadog-instrumentations/src/kafkajs.js +27 -0
  19. package/packages/datadog-instrumentations/src/net.js +10 -2
  20. package/packages/datadog-instrumentations/src/next.js +15 -5
  21. package/packages/datadog-instrumentations/src/restify.js +1 -1
  22. package/packages/datadog-instrumentations/src/rhea.js +15 -9
  23. package/packages/datadog-plugin-cucumber/src/index.js +34 -2
  24. package/packages/datadog-plugin-cypress/src/plugin.js +60 -8
  25. package/packages/datadog-plugin-graphql/src/resolve.js +26 -18
  26. package/packages/datadog-plugin-http/src/client.js +1 -1
  27. package/packages/datadog-plugin-jest/src/index.js +38 -4
  28. package/packages/datadog-plugin-kafkajs/src/consumer.js +51 -0
  29. package/packages/datadog-plugin-kafkajs/src/producer.js +55 -0
  30. package/packages/datadog-plugin-mocha/src/index.js +32 -1
  31. package/packages/datadog-plugin-next/src/index.js +32 -6
  32. package/packages/datadog-plugin-playwright/src/index.js +17 -1
  33. package/packages/dd-trace/src/appsec/activation.js +29 -0
  34. package/packages/dd-trace/src/appsec/addresses.js +1 -0
  35. package/packages/dd-trace/src/appsec/api_security_sampler.js +48 -0
  36. package/packages/dd-trace/src/appsec/blocked_templates.js +4 -1
  37. package/packages/dd-trace/src/appsec/blocking.js +95 -43
  38. package/packages/dd-trace/src/appsec/channels.js +4 -1
  39. package/packages/dd-trace/src/appsec/graphql.js +146 -0
  40. package/packages/dd-trace/src/appsec/iast/analyzers/header-injection-analyzer.js +16 -7
  41. package/packages/dd-trace/src/appsec/index.js +29 -40
  42. package/packages/dd-trace/src/appsec/recommended.json +1395 -2
  43. package/packages/dd-trace/src/appsec/remote_config/capabilities.js +6 -1
  44. package/packages/dd-trace/src/appsec/remote_config/index.js +40 -15
  45. package/packages/dd-trace/src/appsec/reporter.js +2 -4
  46. package/packages/dd-trace/src/appsec/sdk/user_blocking.js +1 -1
  47. package/packages/dd-trace/src/appsec/waf/waf_context_wrapper.js +25 -13
  48. package/packages/dd-trace/src/ci-visibility/exporters/agentless/coverage-writer.js +30 -1
  49. package/packages/dd-trace/src/ci-visibility/exporters/agentless/writer.js +30 -1
  50. package/packages/dd-trace/src/ci-visibility/exporters/git/git_metadata.js +36 -4
  51. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-itr-configuration.js +18 -1
  52. package/packages/dd-trace/src/ci-visibility/intelligent-test-runner/get-skippable-suites.js +26 -1
  53. package/packages/dd-trace/src/ci-visibility/telemetry.js +130 -0
  54. package/packages/dd-trace/src/config.js +110 -56
  55. package/packages/dd-trace/src/datastreams/processor.js +107 -12
  56. package/packages/dd-trace/src/encode/agentless-ci-visibility.js +14 -1
  57. package/packages/dd-trace/src/encode/coverage-ci-visibility.js +14 -0
  58. package/packages/dd-trace/src/exporters/common/agent-info-exporter.js +4 -0
  59. package/packages/dd-trace/src/exporters/common/form-data.js +4 -0
  60. package/packages/dd-trace/src/opentracing/span.js +2 -0
  61. package/packages/dd-trace/src/opentracing/tracer.js +2 -2
  62. package/packages/dd-trace/src/plugins/ci_plugin.js +44 -8
  63. package/packages/dd-trace/src/plugins/index.js +5 -0
  64. package/packages/dd-trace/src/plugins/util/exec.js +23 -2
  65. package/packages/dd-trace/src/plugins/util/git.js +94 -19
  66. package/packages/dd-trace/src/plugins/util/user-provided-git.js +3 -2
  67. package/packages/dd-trace/src/profiling/exporters/agent.js +1 -0
  68. package/packages/dd-trace/src/profiling/profiler.js +7 -6
  69. package/packages/dd-trace/src/profiling/profilers/events.js +19 -51
  70. package/packages/dd-trace/src/profiling/profilers/shared.js +34 -4
  71. package/packages/dd-trace/src/profiling/profilers/space.js +2 -1
  72. package/packages/dd-trace/src/profiling/profilers/wall.js +17 -12
  73. package/packages/dd-trace/src/proxy.js +14 -0
  74. package/packages/dd-trace/src/spanleak.js +98 -0
  75. package/packages/dd-trace/src/telemetry/index.js +43 -5
  76. package/packages/dd-trace/src/tracer.js +4 -0
@@ -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,
@@ -435,6 +407,10 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
435
407
  maybeFile(appsec.blockedTemplateJson),
436
408
  maybeFile(process.env.DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON)
437
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
+ )
438
414
  const DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING = coalesce(
439
415
  appsec.eventTracking && appsec.eventTracking.mode,
440
416
  process.env.DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING,
@@ -540,6 +516,25 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
540
516
  true
541
517
  )
542
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
+
543
538
  const ingestion = options.ingestion || {}
544
539
  const dogstatsd = coalesce(options.dogstatsd, {})
545
540
  const sampler = {
@@ -573,7 +568,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
573
568
  this.dsmEnabled = isTrue(DD_DATA_STREAMS_ENABLED)
574
569
  this.openAiLogsEnabled = DD_OPENAI_LOGS_ENABLED
575
570
  this.apiKey = DD_API_KEY
576
- this.env = DD_ENV
577
571
  this.url = DD_CIVISIBILITY_AGENTLESS_URL ? new URL(DD_CIVISIBILITY_AGENTLESS_URL)
578
572
  : getAgentUrl(DD_TRACE_AGENT_URL, options)
579
573
  this.site = coalesce(options.site, process.env.DD_SITE, 'datadoghq.com')
@@ -585,9 +579,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
585
579
  this.clientIpEnabled = DD_TRACE_CLIENT_IP_ENABLED
586
580
  this.clientIpHeader = DD_TRACE_CLIENT_IP_HEADER
587
581
  this.plugins = !!coalesce(options.plugins, true)
588
- this.service = DD_SERVICE
589
582
  this.serviceMapping = DD_SERVICE_MAPPING
590
- this.version = DD_VERSION
591
583
  this.dogstatsd = {
592
584
  hostname: coalesce(dogstatsd.hostname, process.env.DD_DOGSTATSD_HOSTNAME, this.hostname),
593
585
  port: String(coalesce(dogstatsd.port, process.env.DD_DOGSTATSD_PORT, 8125))
@@ -638,6 +630,7 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
638
630
  obfuscatorValueRegex: DD_APPSEC_OBFUSCATION_PARAMETER_VALUE_REGEXP,
639
631
  blockedTemplateHtml: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_HTML,
640
632
  blockedTemplateJson: DD_APPSEC_HTTP_BLOCKED_TEMPLATE_JSON,
633
+ blockedTemplateGraphql: DD_APPSEC_GRAPHQL_BLOCKED_TEMPLATE_JSON,
641
634
  eventTracking: {
642
635
  enabled: ['extended', 'safe'].includes(DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING),
643
636
  mode: DD_APPSEC_AUTOMATED_USER_EVENTS_TRACKING
@@ -679,6 +672,37 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
679
672
  // Requires an accompanying DD_APM_OBFUSCATION_MEMCACHED_KEEP_COMMAND=true in the agent
680
673
  this.memcachedCommandEnabled = isTrue(DD_TRACE_MEMCACHED_COMMAND_ENABLED)
681
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
+
682
706
  if (this.gitMetadataEnabled) {
683
707
  this.repositoryUrl = removeUserSensitiveInfo(
684
708
  coalesce(
@@ -711,29 +735,6 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
711
735
  }
712
736
  }
713
737
  }
714
-
715
- this.stats = {
716
- enabled: isTrue(DD_TRACE_STATS_COMPUTATION_ENABLED)
717
- }
718
-
719
- this.traceId128BitGenerationEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_GENERATION_ENABLED)
720
- this.traceId128BitLoggingEnabled = isTrue(DD_TRACE_128_BIT_TRACEID_LOGGING_ENABLED)
721
-
722
- this.isGCPFunction = isGCPFunction
723
- this.isAzureFunctionConsumptionPlan = isAzureFunctionConsumptionPlan
724
-
725
- tagger.add(this.tags, {
726
- service: this.service,
727
- env: this.env,
728
- version: this.version,
729
- 'runtime-id': uuid()
730
- })
731
-
732
- this._applyDefaults()
733
- this._applyEnvironment()
734
- this._applyOptions(options)
735
- this._applyRemote({})
736
- this._merge()
737
738
  }
738
739
 
739
740
  // Supports only a subset of options for now.
@@ -748,48 +749,93 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
748
749
  }
749
750
 
750
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
+
751
766
  const defaults = this._defaults = {}
752
767
 
768
+ this._setValue(defaults, 'service', service)
769
+ this._setValue(defaults, 'env', undefined)
770
+ this._setValue(defaults, 'version', pkg.version)
753
771
  this._setUnit(defaults, 'sampleRate', undefined)
754
772
  this._setBoolean(defaults, 'logInjection', false)
755
773
  this._setArray(defaults, 'headerTags', [])
774
+ this._setValue(defaults, 'tags', {})
756
775
  }
757
776
 
758
777
  _applyEnvironment () {
759
778
  const {
760
- DD_TRACE_SAMPLE_RATE,
779
+ DD_ENV,
761
780
  DD_LOGS_INJECTION,
762
- 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
763
789
  } = process.env
764
790
 
791
+ const tags = {}
765
792
  const env = this._env = {}
766
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)
767
801
  this._setUnit(env, 'sampleRate', DD_TRACE_SAMPLE_RATE)
768
802
  this._setBoolean(env, 'logInjection', DD_LOGS_INJECTION)
769
803
  this._setArray(env, 'headerTags', DD_TRACE_HEADER_TAGS)
804
+ this._setTags(env, 'tags', tags)
770
805
  }
771
806
 
772
807
  _applyOptions (options) {
773
808
  const opts = this._options = this._options || {}
809
+ const tags = {}
774
810
 
775
811
  options = Object.assign({ ingestion: {} }, options, opts)
776
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)
777
818
  this._setUnit(opts, 'sampleRate', coalesce(options.sampleRate, options.ingestion.sampleRate))
778
819
  this._setBoolean(opts, 'logInjection', options.logInjection)
779
820
  this._setArray(opts, 'headerTags', options.headerTags)
821
+ this._setTags(opts, 'tags', tags)
780
822
  }
781
823
 
782
824
  _applyRemote (options) {
783
825
  const opts = this._remote = this._remote || {}
826
+ const tags = {}
784
827
  const headerTags = options.tracing_header_tags
785
828
  ? options.tracing_header_tags.map(tag => {
786
829
  return tag.tag_name ? `${tag.header}:${tag.tag_name}` : tag.header
787
830
  })
788
831
  : undefined
789
832
 
833
+ tagger.add(tags, options.tracing_tags)
834
+
790
835
  this._setUnit(opts, 'sampleRate', options.tracing_sampling_rate)
791
836
  this._setBoolean(opts, 'logInjection', options.log_injection_enabled)
792
837
  this._setArray(opts, 'headerTags', headerTags)
838
+ this._setTags(opts, 'tags', tags)
793
839
  }
794
840
 
795
841
  _setBoolean (obj, name, value) {
@@ -829,6 +875,14 @@ ken|consumer_?(?:id|key|secret)|sign(?:ed|ature)?|auth(?:entication|orization)?)
829
875
  }
830
876
  }
831
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
+
832
886
  _setValue (obj, name, value) {
833
887
  obj[name] = value
834
888
  }
@@ -45,14 +45,73 @@ class StatsPoint {
45
45
  }
46
46
  }
47
47
 
48
- 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
+
49
83
  forCheckpoint (checkpoint) {
50
84
  const key = checkpoint.hash
51
- if (!this.has(key)) {
52
- 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
+ )
53
89
  }
54
90
 
55
- 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
56
115
  }
57
116
  }
58
117
 
@@ -122,12 +181,12 @@ class DataStreamsProcessor {
122
181
  }
123
182
 
124
183
  onInterval () {
125
- const serialized = this._serializeBuckets()
126
- if (!serialized) return
184
+ const { Stats } = this._serializeBuckets()
185
+ if (Stats.length === 0) return
127
186
  const payload = {
128
187
  Env: this.env,
129
188
  Service: this.service,
130
- Stats: serialized,
189
+ Stats,
131
190
  TracerVersion: pkg.version,
132
191
  Version: this.version,
133
192
  Lang: 'javascript'
@@ -135,10 +194,19 @@ class DataStreamsProcessor {
135
194
  this.writer.flush(payload)
136
195
  }
137
196
 
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
+
138
207
  recordCheckpoint (checkpoint, span = null) {
139
208
  if (!this.enabled) return
140
- const bucketTime = Math.round(checkpoint.currentTimestamp - (checkpoint.currentTimestamp % this.bucketSizeNs))
141
- this.buckets.forTime(bucketTime)
209
+ this.bucketFromTimestamp(checkpoint.currentTimestamp)
142
210
  .forCheckpoint(checkpoint)
143
211
  .addLatencies(checkpoint)
144
212
  // set DSM pathway hash on span to enable related traces feature on DSM tab, convert from buffer to uint64
@@ -207,26 +275,52 @@ class DataStreamsProcessor {
207
275
  return dataStreamsContext
208
276
  }
209
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
290
+ }
291
+ this.recordOffset(backlogData)
292
+ }
293
+
210
294
  _serializeBuckets () {
295
+ // TimeBuckets
211
296
  const serializedBuckets = []
212
297
 
213
298
  for (const [ timeNs, bucket ] of this.buckets.entries()) {
214
299
  const points = []
215
300
 
216
- for (const stats of bucket.values()) {
301
+ // bucket: StatsBucket
302
+ // stats: StatsPoint
303
+ for (const stats of bucket._checkpoints.values()) {
217
304
  points.push(stats.encode())
218
305
  }
219
306
 
307
+ const backlogs = []
308
+ for (const backlog of bucket._backlogs.values()) {
309
+ backlogs.push(backlog.encode())
310
+ }
220
311
  serializedBuckets.push({
221
312
  Start: new Uint64(timeNs),
222
313
  Duration: new Uint64(this.bucketSizeNs),
223
- Stats: points
314
+ Stats: points,
315
+ Backlogs: backlogs
224
316
  })
225
317
  }
226
318
 
227
319
  this.buckets.clear()
228
320
 
229
- return serializedBuckets
321
+ return {
322
+ Stats: serializedBuckets
323
+ }
230
324
  }
231
325
  }
232
326
 
@@ -234,6 +328,7 @@ module.exports = {
234
328
  DataStreamsProcessor: DataStreamsProcessor,
235
329
  StatsPoint: StatsPoint,
236
330
  StatsBucket: StatsBucket,
331
+ Backlog,
237
332
  TimeBuckets,
238
333
  getMessageSize,
239
334
  getHeadersSize,
@@ -3,8 +3,13 @@ const { truncateSpan, normalizeSpan } = require('./tags-processors')
3
3
  const { AgentEncoder } = require('./0.4')
4
4
  const { version: ddTraceVersion } = require('../../../../package.json')
5
5
  const id = require('../../../dd-trace/src/id')
6
- const ENCODING_VERSION = 1
6
+ const {
7
+ distributionMetric,
8
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
9
+ TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT
10
+ } = require('../ci-visibility/telemetry')
7
11
 
12
+ const ENCODING_VERSION = 1
8
13
  const ALLOWED_CONTENT_TYPES = ['test_session_end', 'test_module_end', 'test_suite_end', 'test']
9
14
 
10
15
  const TEST_SUITE_KEYS_LENGTH = 12
@@ -247,6 +252,8 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
247
252
  }
248
253
 
249
254
  _encode (bytes, trace) {
255
+ const startTime = Date.now()
256
+
250
257
  const rawEvents = trace.map(formatSpan)
251
258
 
252
259
  const testSessionEvents = rawEvents.filter(
@@ -261,9 +268,15 @@ class AgentlessCiVisibilityEncoder extends AgentEncoder {
261
268
  for (const event of events) {
262
269
  this._encodeEvent(bytes, event)
263
270
  }
271
+ distributionMetric(
272
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
273
+ { endpoint: 'test_cycle' },
274
+ Date.now() - startTime
275
+ )
264
276
  }
265
277
 
266
278
  makePayload () {
279
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT, { endpoint: 'test_cycle' }, this._eventCount)
267
280
  const bytes = this._traceBytes
268
281
  const eventsOffset = this._eventsOffset
269
282
  const eventsCount = this._eventCount
@@ -2,6 +2,11 @@
2
2
  const { AgentEncoder } = require('./0.4')
3
3
  const Chunk = require('./chunk')
4
4
 
5
+ const {
6
+ distributionMetric,
7
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
8
+ TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT
9
+ } = require('../ci-visibility/telemetry')
5
10
  const FormData = require('../exporters/common/form-data')
6
11
 
7
12
  const COVERAGE_PAYLOAD_VERSION = 2
@@ -21,8 +26,16 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
21
26
  }
22
27
 
23
28
  encode (coverage) {
29
+ const startTime = Date.now()
30
+
24
31
  this._coveragesCount++
25
32
  this.encodeCodeCoverage(this._coverageBytes, coverage)
33
+
34
+ distributionMetric(
35
+ TELEMETRY_ENDPOINT_PAYLOAD_SERIALIZATION_MS,
36
+ { endpoint: 'code_coverage' },
37
+ Date.now() - startTime
38
+ )
26
39
  }
27
40
 
28
41
  encodeCodeCoverage (bytes, coverage) {
@@ -73,6 +86,7 @@ class CoverageCIVisibilityEncoder extends AgentEncoder {
73
86
  }
74
87
 
75
88
  makePayload () {
89
+ distributionMetric(TELEMETRY_ENDPOINT_PAYLOAD_EVENTS_COUNT, { endpoint: 'code_coverage' }, this._coveragesCount)
76
90
  const bytes = this._coverageBytes
77
91
 
78
92
  const coveragesOffset = this._coveragesOffset
@@ -1,6 +1,7 @@
1
1
  const { URL, format } = require('url')
2
2
 
3
3
  const request = require('./request')
4
+ const { incrementCountMetric, TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION } = require('../../ci-visibility/telemetry')
4
5
 
5
6
  function fetchAgentInfo (url, callback) {
6
7
  request('', {
@@ -49,6 +50,9 @@ class AgentInfoExporter {
49
50
  }
50
51
 
51
52
  _export (payload, writer = this._writer, timerKey = '_timer') {
53
+ if (this._config.isCiVisibility) {
54
+ incrementCountMetric(TELEMETRY_EVENTS_ENQUEUED_FOR_SERIALIZATION, {}, payload.length)
55
+ }
52
56
  writer.append(payload)
53
57
 
54
58
  const { flushInterval } = this._config
@@ -21,6 +21,10 @@ class FormData extends Readable {
21
21
  }
22
22
  }
23
23
 
24
+ size () {
25
+ return this._data.reduce((size, chunk) => size + chunk.length, 0)
26
+ }
27
+
24
28
  getHeaders () {
25
29
  return { 'Content-Type': 'multipart/form-data; boundary=' + this._boundary }
26
30
  }
@@ -13,6 +13,7 @@ const log = require('../log')
13
13
  const { storage } = require('../../../datadog-core')
14
14
  const telemetryMetrics = require('../telemetry/metrics')
15
15
  const { channel } = require('dc-polyfill')
16
+ const spanleak = require('../spanleak')
16
17
 
17
18
  const tracerMetrics = telemetryMetrics.manager.namespace('tracers')
18
19
 
@@ -90,6 +91,7 @@ class DatadogSpan {
90
91
 
91
92
  unfinishedRegistry.register(this, operationName, this)
92
93
  }
94
+ spanleak.addSpan(this, operationName)
93
95
  }
94
96
 
95
97
  toString () {
@@ -22,10 +22,10 @@ class DatadogTracer {
22
22
  constructor (config) {
23
23
  const Exporter = getExporter(config.experimental.exporter)
24
24
 
25
+ this._config = config
25
26
  this._service = config.service
26
27
  this._version = config.version
27
28
  this._env = config.env
28
- this._tags = config.tags
29
29
  this._logInjection = config.logInjection
30
30
  this._debug = config.debug
31
31
  this._prioritySampler = new PrioritySampler(config.env, config.sampler)
@@ -64,7 +64,7 @@ class DatadogTracer {
64
64
  integrationName: options.integrationName
65
65
  }, this._debug)
66
66
 
67
- span.addTags(this._tags)
67
+ span.addTags(this._config.tags)
68
68
  span.addTags(options.tags)
69
69
 
70
70
  return span