dd-trace 5.61.0 → 5.62.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 (192) hide show
  1. package/package.json +1 -1
  2. package/packages/datadog-instrumentations/src/apollo-server.js +50 -8
  3. package/packages/datadog-instrumentations/src/aws-sdk.js +49 -60
  4. package/packages/datadog-instrumentations/src/fastify.js +61 -55
  5. package/packages/datadog-instrumentations/src/graphql.js +90 -122
  6. package/packages/datadog-instrumentations/src/http2/server.js +14 -20
  7. package/packages/datadog-instrumentations/src/microgateway-core.js +16 -15
  8. package/packages/datadog-instrumentations/src/mongodb-core.js +34 -29
  9. package/packages/datadog-instrumentations/src/mongodb.js +9 -13
  10. package/packages/datadog-instrumentations/src/mongoose.js +25 -29
  11. package/packages/datadog-instrumentations/src/openai.js +0 -2
  12. package/packages/datadog-instrumentations/src/oracledb.js +39 -33
  13. package/packages/datadog-instrumentations/src/router.js +1 -1
  14. package/packages/datadog-plugin-aerospike/src/index.js +5 -9
  15. package/packages/datadog-plugin-amqp10/src/consumer.js +2 -2
  16. package/packages/datadog-plugin-amqp10/src/index.js +1 -1
  17. package/packages/datadog-plugin-amqp10/src/producer.js +3 -3
  18. package/packages/datadog-plugin-amqplib/src/client.js +3 -3
  19. package/packages/datadog-plugin-amqplib/src/consumer.js +2 -2
  20. package/packages/datadog-plugin-amqplib/src/index.js +1 -1
  21. package/packages/datadog-plugin-amqplib/src/producer.js +2 -2
  22. package/packages/datadog-plugin-apollo/src/gateway/execute.js +2 -4
  23. package/packages/datadog-plugin-apollo/src/gateway/fetch.js +2 -4
  24. package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
  25. package/packages/datadog-plugin-apollo/src/gateway/plan.js +2 -4
  26. package/packages/datadog-plugin-apollo/src/gateway/postprocessing.js +2 -4
  27. package/packages/datadog-plugin-apollo/src/gateway/request.js +2 -4
  28. package/packages/datadog-plugin-apollo/src/gateway/validate.js +2 -4
  29. package/packages/datadog-plugin-apollo/src/index.js +1 -1
  30. package/packages/datadog-plugin-avsc/src/index.js +2 -2
  31. package/packages/datadog-plugin-aws-sdk/src/base.js +70 -46
  32. package/packages/datadog-plugin-aws-sdk/src/index.js +1 -3
  33. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +1 -3
  34. package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
  35. package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
  36. package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +3 -3
  37. package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
  38. package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +22 -20
  39. package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
  40. package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
  41. package/packages/datadog-plugin-aws-sdk/src/services/s3.js +3 -3
  42. package/packages/datadog-plugin-aws-sdk/src/services/sfn.js +1 -1
  43. package/packages/datadog-plugin-aws-sdk/src/services/sns.js +3 -3
  44. package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +17 -15
  45. package/packages/datadog-plugin-aws-sdk/src/services/states.js +1 -1
  46. package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
  47. package/packages/datadog-plugin-azure-functions/src/index.js +5 -5
  48. package/packages/datadog-plugin-azure-service-bus/src/index.js +1 -1
  49. package/packages/datadog-plugin-azure-service-bus/src/producer.js +2 -2
  50. package/packages/datadog-plugin-bunyan/src/index.js +3 -5
  51. package/packages/datadog-plugin-cassandra-driver/src/index.js +3 -3
  52. package/packages/datadog-plugin-child_process/src/index.js +2 -2
  53. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/batch-consumer.js +1 -3
  54. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/consumer.js +1 -3
  55. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
  56. package/packages/datadog-plugin-confluentinc-kafka-javascript/src/producer.js +1 -3
  57. package/packages/datadog-plugin-connect/src/index.js +1 -3
  58. package/packages/datadog-plugin-couchbase/src/index.js +2 -2
  59. package/packages/datadog-plugin-cucumber/src/index.js +1 -3
  60. package/packages/datadog-plugin-cypress/src/index.js +1 -3
  61. package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -3
  62. package/packages/datadog-plugin-dns/src/index.js +1 -1
  63. package/packages/datadog-plugin-dns/src/lookup.js +2 -2
  64. package/packages/datadog-plugin-dns/src/lookup_service.js +2 -2
  65. package/packages/datadog-plugin-dns/src/resolve.js +2 -2
  66. package/packages/datadog-plugin-dns/src/reverse.js +2 -2
  67. package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
  68. package/packages/datadog-plugin-express/src/code_origin.js +1 -3
  69. package/packages/datadog-plugin-express/src/index.js +1 -1
  70. package/packages/datadog-plugin-express/src/tracing.js +1 -3
  71. package/packages/datadog-plugin-fastify/src/code_origin.js +1 -3
  72. package/packages/datadog-plugin-fastify/src/index.js +1 -1
  73. package/packages/datadog-plugin-fastify/src/tracing.js +18 -3
  74. package/packages/datadog-plugin-fetch/src/index.js +2 -2
  75. package/packages/datadog-plugin-find-my-way/src/index.js +1 -3
  76. package/packages/datadog-plugin-fs/src/index.js +2 -2
  77. package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +3 -3
  78. package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -2
  79. package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +1 -1
  80. package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +2 -2
  81. package/packages/datadog-plugin-google-cloud-vertexai/src/index.js +1 -1
  82. package/packages/datadog-plugin-google-cloud-vertexai/src/tracing.js +2 -4
  83. package/packages/datadog-plugin-graphql/src/execute.js +16 -9
  84. package/packages/datadog-plugin-graphql/src/index.js +1 -1
  85. package/packages/datadog-plugin-graphql/src/parse.js +12 -7
  86. package/packages/datadog-plugin-graphql/src/resolve.js +50 -16
  87. package/packages/datadog-plugin-graphql/src/validate.js +13 -7
  88. package/packages/datadog-plugin-grpc/src/client.js +4 -4
  89. package/packages/datadog-plugin-grpc/src/index.js +1 -1
  90. package/packages/datadog-plugin-grpc/src/server.js +3 -3
  91. package/packages/datadog-plugin-hapi/src/index.js +1 -3
  92. package/packages/datadog-plugin-hono/src/index.js +1 -3
  93. package/packages/datadog-plugin-http/src/client.js +2 -2
  94. package/packages/datadog-plugin-http/src/index.js +1 -1
  95. package/packages/datadog-plugin-http/src/server.js +3 -7
  96. package/packages/datadog-plugin-http2/src/client.js +2 -2
  97. package/packages/datadog-plugin-http2/src/index.js +1 -1
  98. package/packages/datadog-plugin-http2/src/server.js +22 -11
  99. package/packages/datadog-plugin-ioredis/src/index.js +1 -3
  100. package/packages/datadog-plugin-iovalkey/src/index.js +2 -4
  101. package/packages/datadog-plugin-jest/src/index.js +1 -3
  102. package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -2
  103. package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -2
  104. package/packages/datadog-plugin-kafkajs/src/index.js +1 -1
  105. package/packages/datadog-plugin-kafkajs/src/producer.js +3 -3
  106. package/packages/datadog-plugin-koa/src/index.js +1 -3
  107. package/packages/datadog-plugin-langchain/src/index.js +2 -2
  108. package/packages/datadog-plugin-langchain/src/tracing.js +30 -48
  109. package/packages/datadog-plugin-mariadb/src/index.js +2 -2
  110. package/packages/datadog-plugin-memcached/src/index.js +1 -1
  111. package/packages/datadog-plugin-microgateway-core/src/index.js +4 -4
  112. package/packages/datadog-plugin-mocha/src/index.js +1 -3
  113. package/packages/datadog-plugin-moleculer/src/client.js +2 -2
  114. package/packages/datadog-plugin-moleculer/src/index.js +1 -1
  115. package/packages/datadog-plugin-moleculer/src/server.js +2 -2
  116. package/packages/datadog-plugin-mongodb-core/src/index.js +9 -5
  117. package/packages/datadog-plugin-mongoose/src/index.js +20 -0
  118. package/packages/datadog-plugin-mysql/src/index.js +2 -2
  119. package/packages/datadog-plugin-mysql2/src/index.js +1 -1
  120. package/packages/datadog-plugin-net/src/index.js +1 -1
  121. package/packages/datadog-plugin-net/src/ipc.js +2 -2
  122. package/packages/datadog-plugin-net/src/tcp.js +2 -2
  123. package/packages/datadog-plugin-next/src/index.js +1 -3
  124. package/packages/datadog-plugin-nyc/src/index.js +1 -3
  125. package/packages/datadog-plugin-openai/src/index.js +1 -1
  126. package/packages/datadog-plugin-openai/src/tracing.js +7 -411
  127. package/packages/datadog-plugin-opensearch/src/index.js +1 -3
  128. package/packages/datadog-plugin-oracledb/src/index.js +9 -5
  129. package/packages/datadog-plugin-pg/src/index.js +3 -3
  130. package/packages/datadog-plugin-pino/src/index.js +3 -5
  131. package/packages/datadog-plugin-playwright/src/index.js +1 -3
  132. package/packages/datadog-plugin-prisma/src/client.js +4 -6
  133. package/packages/datadog-plugin-prisma/src/engine.js +3 -3
  134. package/packages/datadog-plugin-prisma/src/index.js +1 -1
  135. package/packages/datadog-plugin-protobufjs/src/index.js +2 -6
  136. package/packages/datadog-plugin-redis/src/index.js +2 -2
  137. package/packages/datadog-plugin-restify/src/index.js +1 -3
  138. package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
  139. package/packages/datadog-plugin-rhea/src/index.js +1 -1
  140. package/packages/datadog-plugin-rhea/src/producer.js +2 -2
  141. package/packages/datadog-plugin-router/src/index.js +1 -3
  142. package/packages/datadog-plugin-selenium/src/index.js +1 -3
  143. package/packages/datadog-plugin-sharedb/src/index.js +1 -1
  144. package/packages/datadog-plugin-tedious/src/index.js +3 -3
  145. package/packages/datadog-plugin-undici/src/index.js +2 -4
  146. package/packages/datadog-plugin-vitest/src/index.js +1 -3
  147. package/packages/datadog-plugin-web/src/index.js +1 -3
  148. package/packages/datadog-plugin-winston/src/index.js +3 -5
  149. package/packages/dd-trace/src/appsec/channels.js +1 -0
  150. package/packages/dd-trace/src/appsec/graphql.js +14 -12
  151. package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
  152. package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
  153. package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +1 -3
  154. package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +1 -3
  155. package/packages/dd-trace/src/config.js +1 -1
  156. package/packages/dd-trace/src/datastreams/checkpointer.js +23 -2
  157. package/packages/dd-trace/src/datastreams/processor.js +4 -3
  158. package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +30 -50
  159. package/packages/dd-trace/src/llmobs/plugins/openai.js +3 -5
  160. package/packages/dd-trace/src/llmobs/plugins/vertexai.js +3 -5
  161. package/packages/dd-trace/src/opentracing/propagation/text_map.js +25 -2
  162. package/packages/dd-trace/src/plugins/apollo.js +3 -3
  163. package/packages/dd-trace/src/plugins/cache.js +1 -1
  164. package/packages/dd-trace/src/plugins/client.js +3 -3
  165. package/packages/dd-trace/src/plugins/consumer.js +3 -3
  166. package/packages/dd-trace/src/plugins/database.js +2 -2
  167. package/packages/dd-trace/src/plugins/index.js +1 -0
  168. package/packages/dd-trace/src/plugins/log_plugin.js +1 -5
  169. package/packages/dd-trace/src/plugins/outbound.js +1 -1
  170. package/packages/dd-trace/src/plugins/plugin.js +1 -1
  171. package/packages/dd-trace/src/plugins/producer.js +3 -3
  172. package/packages/dd-trace/src/plugins/server.js +3 -3
  173. package/packages/dd-trace/src/plugins/storage.js +1 -1
  174. package/packages/dd-trace/src/plugins/tracing.js +24 -6
  175. package/packages/dd-trace/src/plugins/util/ci.js +11 -7
  176. package/packages/dd-trace/src/plugins/util/inferred_proxy.js +15 -19
  177. package/packages/dd-trace/src/plugins/util/tags.js +2 -0
  178. package/packages/dd-trace/src/plugins/util/web.js +26 -7
  179. package/packages/dd-trace/src/profiling/config.js +2 -0
  180. package/packages/dd-trace/src/profiling/exporters/event_serializer.js +2 -21
  181. package/packages/dd-trace/src/profiling/libuv-size.js +49 -0
  182. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns.js +2 -6
  183. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookup.js +1 -3
  184. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookupservice.js +1 -3
  185. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_resolve.js +1 -3
  186. package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_reverse.js +1 -3
  187. package/packages/dd-trace/src/profiling/profilers/event_plugins/fs.js +3 -9
  188. package/packages/dd-trace/src/profiling/profilers/event_plugins/net.js +3 -9
  189. package/packages/dd-trace/src/profiling/profilers/events.js +80 -62
  190. package/packages/dd-trace/src/profiling/profilers/poisson.js +105 -0
  191. package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
  192. package/packages/dd-trace/src/remote_config/manager.js +1 -1
@@ -3,9 +3,12 @@
3
3
  const { performance, constants, PerformanceObserver } = require('perf_hooks')
4
4
  const { END_TIMESTAMP_LABEL, SPAN_ID_LABEL, LOCAL_ROOT_SPAN_ID_LABEL, encodeProfileAsync } = require('./shared')
5
5
  const { Function, Label, Line, Location, Profile, Sample, StringTable, ValueType } = require('pprof-format')
6
-
6
+ const PoissonProcessSamplingFilter = require('./poisson')
7
+ const { availableParallelism, effectiveLibuvThreadCount } = require('../libuv-size')
7
8
  // perf_hooks uses millis, with fractional part representing nanos. We emit nanos into the pprof file.
8
9
  const MS_TO_NS = 1_000_000
10
+ // The number of sampling intervals that need to pass before we reset the Poisson process sampling instant.
11
+ const POISSON_RESET_FACTOR = 2
9
12
 
10
13
  // While this is an "events profiler", meaning it emits a pprof file based on events observed as
11
14
  // perf_hooks events, the emitted pprof file uses the type "timeline".
@@ -38,6 +41,24 @@ function labelFromStrStr (stringTable, keyStr, valStr) {
38
41
  return labelFromStr(stringTable, stringTable.dedup(keyStr), valStr)
39
42
  }
40
43
 
44
+ function getSamplingIntervalMillis (options) {
45
+ return (options.samplingInterval || 1e3 / 99) // 99Hz
46
+ }
47
+
48
+ function getMaxSamples (options) {
49
+ const cpuSamplingInterval = getSamplingIntervalMillis(options)
50
+ const flushInterval = options.flushInterval || 65 * 1e3 // 60 seconds
51
+ const maxCpuSamples = flushInterval / cpuSamplingInterval
52
+
53
+ // The lesser of max parallelism and libuv thread pool size, plus one so we can detect
54
+ // oversubscription on libuv thread pool, plus another one for GC.
55
+ const factor = Math.max(1, Math.min(availableParallelism(), effectiveLibuvThreadCount)) + 2
56
+
57
+ // Let's not go overboard with too large limit and cap it at 100k. With current defaults, the
58
+ // value will be 65000/10.1*(4+2) = 38613.
59
+ return Math.min(100_000, Math.floor(maxCpuSamples * factor))
60
+ }
61
+
41
62
  class GCDecorator {
42
63
  constructor (stringTable) {
43
64
  this.stringTable = stringTable
@@ -181,12 +202,15 @@ const decoratorTypes = {
181
202
 
182
203
  // Translates performance entries into pprof samples.
183
204
  class EventSerializer {
184
- constructor () {
205
+ #sampleCount = 0
206
+
207
+ constructor (maxSamples) {
185
208
  this.stringTable = new StringTable()
186
209
  this.samples = []
187
210
  this.locations = []
188
211
  this.functions = []
189
212
  this.decorators = {}
213
+ this.maxSamples = maxSamples
190
214
 
191
215
  // A synthetic single-frame location to serve as the location for timeline
192
216
  // samples. We need these as the profiling backend (mimicking official pprof
@@ -204,6 +228,31 @@ class EventSerializer {
204
228
  }
205
229
 
206
230
  addEvent (item) {
231
+ if (this.samples.length < this.maxSamples) {
232
+ const sample = this.#createSample(item)
233
+ if (sample !== undefined) {
234
+ this.samples.push(sample)
235
+ this.#sampleCount++
236
+ }
237
+ } else {
238
+ this.#sampleCount++
239
+ // Reservoir sampling
240
+ const replacementIndex = Math.floor(Math.random() * this.#sampleCount)
241
+ if (replacementIndex < this.maxSamples) {
242
+ const sample = this.#createSample(item)
243
+ if (sample === undefined) {
244
+ this.#sampleCount-- // unlikely
245
+ } else {
246
+ // This will cause the samples to no longer be sorted in their array
247
+ // by their end time. This is fine as the backend has no ordering
248
+ // expectations.
249
+ this.samples[replacementIndex] = sample
250
+ }
251
+ }
252
+ }
253
+ }
254
+
255
+ #createSample (item) {
207
256
  const { entryType, startTime, duration, _ddSpanId, _ddRootSpanId } = item
208
257
  let decorator = this.decorators[entryType]
209
258
  if (!decorator) {
@@ -236,7 +285,7 @@ class EventSerializer {
236
285
  label
237
286
  }
238
287
  decorator.decorateSample(sampleInput, item)
239
- this.samples.push(new Sample(sampleInput))
288
+ return new Sample(sampleInput)
240
289
  }
241
290
 
242
291
  createProfile (startDate, endDate) {
@@ -324,50 +373,13 @@ class DatadogInstrumentationEventSource {
324
373
  }
325
374
  }
326
375
 
327
- class CompositeEventSource {
328
- constructor (sources) {
329
- this.sources = sources
330
- }
331
-
332
- start () {
333
- this.sources.forEach(s => s.start())
334
- }
335
-
336
- stop () {
337
- this.sources.forEach(s => s.stop())
338
- }
339
- }
340
-
341
- function createPossionProcessSamplingFilter (samplingIntervalMillis) {
342
- let nextSamplingInstant = performance.now()
343
- let currentSamplingInstant = 0
344
- setNextSamplingInstant()
345
-
346
- return event => {
347
- const endTime = event.startTime + event.duration
348
- while (endTime >= nextSamplingInstant) {
349
- setNextSamplingInstant()
350
- }
351
- // An event is sampled if it started before, and ended on or after a sampling instant. The above
352
- // while loop will ensure that the ending invariant is always true for the current sampling
353
- // instant so we don't have to test for it below. Across calls, the invariant also holds as long
354
- // as the events arrive in endTime order. This is true for events coming from
355
- // DatadogInstrumentationEventSource; they will be ordered by endTime by virtue of this method
356
- // being invoked synchronously with the plugins' finish() handler which evaluates
357
- // performance.now(). OTOH, events coming from NodeAPIEventSource (GC in typical setup) might be
358
- // somewhat delayed as they are queued by Node, so they can arrive out of order with regard to
359
- // events coming from the non-queued source. By omitting the endTime check, we will pass through
360
- // some short events that started and ended before the current sampling instant. OTOH, if we
361
- // were to check for this.currentSamplingInstant <= endTime, we would discard some long events
362
- // that also ended before the current sampling instant. We'd rather err on the side of including
363
- // some short events than excluding some long events.
364
- return event.startTime < currentSamplingInstant
365
- }
366
-
367
- function setNextSamplingInstant () {
368
- currentSamplingInstant = nextSamplingInstant
369
- nextSamplingInstant -= Math.log(1 - Math.random()) * samplingIntervalMillis
370
- }
376
+ function createPoissonProcessSamplingFilter (samplingIntervalMillis) {
377
+ const poissonFilter = new PoissonProcessSamplingFilter({
378
+ samplingInterval: samplingIntervalMillis,
379
+ resetInterval: samplingIntervalMillis * POISSON_RESET_FACTOR,
380
+ now: performance.now.bind(performance)
381
+ })
382
+ return poissonFilter.filter.bind(poissonFilter)
371
383
  }
372
384
 
373
385
  /**
@@ -376,45 +388,51 @@ function createPossionProcessSamplingFilter (samplingIntervalMillis) {
376
388
  */
377
389
  class EventsProfiler {
378
390
  type = 'events'
379
- eventSerializer = new EventSerializer()
391
+ #maxSamples
392
+ #eventSerializer
393
+ #eventSources
380
394
 
381
395
  constructor (options = {}) {
382
- const eventHandler = event => this.eventSerializer.addEvent(event)
396
+ this.#maxSamples = getMaxSamples(options)
397
+ this.#eventSerializer = new EventSerializer(this.#maxSamples)
398
+
399
+ const eventHandler = event => this.#eventSerializer.addEvent(event)
383
400
  const eventFilter = options.timelineSamplingEnabled
384
- // options.samplingInterval comes in microseconds, we need millis
385
- ? createPossionProcessSamplingFilter((options.samplingInterval ?? 1e6 / 99) / 1000)
386
- : _ => true
401
+ ? createPoissonProcessSamplingFilter(getSamplingIntervalMillis(options))
402
+ : () => true
387
403
  const filteringEventHandler = event => {
388
404
  if (eventFilter(event)) {
389
405
  eventHandler(event)
390
406
  }
391
407
  }
392
408
 
393
- this.eventSource = options.codeHotspotsEnabled
409
+ this.#eventSources = options.codeHotspotsEnabled
394
410
  // Use Datadog instrumentation to collect events with span IDs. Still use
395
411
  // Node API for GC events.
396
- ? new CompositeEventSource([
397
- new DatadogInstrumentationEventSource(eventHandler, eventFilter),
398
- new NodeApiEventSource(filteringEventHandler, ['gc'])
399
- ])
412
+ ? [
413
+ new DatadogInstrumentationEventSource(eventHandler, eventFilter),
414
+ new NodeApiEventSource(filteringEventHandler, ['gc']),
415
+ ]
400
416
  // Use Node API instrumentation to collect events without span IDs
401
- : new NodeApiEventSource(filteringEventHandler)
417
+ : [
418
+ new NodeApiEventSource(filteringEventHandler)
419
+ ]
402
420
  }
403
421
 
404
422
  start () {
405
- this.eventSource.start()
423
+ this.#eventSources.forEach(s => s.start())
406
424
  }
407
425
 
408
426
  stop () {
409
- this.eventSource.stop()
427
+ this.#eventSources.forEach(s => s.stop())
410
428
  }
411
429
 
412
430
  profile (restart, startDate, endDate) {
413
431
  if (!restart) {
414
432
  this.stop()
415
433
  }
416
- const thatEventSerializer = this.eventSerializer
417
- this.eventSerializer = new EventSerializer()
434
+ const thatEventSerializer = this.#eventSerializer
435
+ this.#eventSerializer = new EventSerializer(this.#maxSamples)
418
436
  return () => thatEventSerializer.createProfile(startDate, endDate)
419
437
  }
420
438
 
@@ -0,0 +1,105 @@
1
+ 'use strict'
2
+
3
+ class PoissonProcessSamplingFilter {
4
+ #currentSamplingInstant = 0
5
+ #nextSamplingInstant
6
+ #samplingInterval
7
+ #resetInterval
8
+ #now
9
+ #lastNow = Number.NEGATIVE_INFINITY
10
+ #samplingInstantCount = 0
11
+
12
+ constructor ({ samplingInterval, now, resetInterval }) {
13
+ if (samplingInterval <= 0) {
14
+ throw new RangeError(`samplingInterval (${samplingInterval}) must be greater than 0`)
15
+ }
16
+ if (resetInterval < samplingInterval) {
17
+ throw new RangeError(
18
+ `resetInterval (${resetInterval}) must be greater than samplingInterval (${samplingInterval})`
19
+ )
20
+ }
21
+ if (typeof now !== 'function') {
22
+ throw new TypeError('now must be a function')
23
+ }
24
+ this.#samplingInterval = samplingInterval
25
+ this.#resetInterval = resetInterval
26
+ this.#now = now
27
+ this.#nextSamplingInstant = this.#callNow()
28
+ this.#setNextSamplingInstant()
29
+ }
30
+
31
+ get currentSamplingInstant () {
32
+ return this.#currentSamplingInstant
33
+ }
34
+
35
+ get nextSamplingInstant () {
36
+ return this.#nextSamplingInstant
37
+ }
38
+
39
+ get samplingInstantCount () {
40
+ return this.#samplingInstantCount
41
+ }
42
+
43
+ #callNow () {
44
+ const nowValue = this.#now()
45
+ if (typeof nowValue !== 'number') {
46
+ throw new TypeError('now() must return a number')
47
+ }
48
+ if (nowValue < this.#lastNow) {
49
+ throw new RangeError('now() must return a value greater than or equal to the last returned value')
50
+ }
51
+ this.#lastNow = nowValue
52
+ return nowValue
53
+ }
54
+
55
+ filter (event) {
56
+ const endTime = event.startTime + event.duration
57
+ // We're using the end times of events as an approximation of current time as events are
58
+ // expected to be reported close to where they ended. If the end time (and thus, presumably, the
59
+ // current time) is past the next sampling instant, we make it the current sampling instant and
60
+ // compute the next sampling instant in its future.
61
+ if (endTime >= this.#nextSamplingInstant) {
62
+ // All observed events are supposed to have happened in the past. For purposes of advancing
63
+ // the next sampling instant, we cap endTime to now(). This protects us from advancing it far
64
+ // into future if we receive an event with erroneously long duration, which would also take
65
+ // many iterations of the below "while" loop.
66
+ const cappedEndTime = Math.min(endTime, this.#callNow())
67
+
68
+ // If nextSamplingInstant is far in cappedEndTime's past, first advance it close to it. This
69
+ // can happen if we didn't receive any events for a while. Since a Poisson process has no
70
+ // memory, we can reset it anytime. This will ensure that the "while" loop below runs at most
71
+ // few iterations.
72
+ const earliestContinuousPast = cappedEndTime - this.#resetInterval
73
+ if (this.#nextSamplingInstant < earliestContinuousPast) {
74
+ this.#nextSamplingInstant = earliestContinuousPast
75
+ }
76
+
77
+ // Advance the next sampling instant until it is in cappedEndTime's future.
78
+ while (cappedEndTime >= this.#nextSamplingInstant) {
79
+ this.#setNextSamplingInstant()
80
+ }
81
+ }
82
+ // An event is sampled if it started before, and ended on or after a sampling instant. The above
83
+ // while loop will ensure that the ending invariant is always true for the current sampling
84
+ // instant so we don't have to test for it below. Across calls, the invariant also holds as long
85
+ // as the events arrive in endTime order. This is true for events coming from
86
+ // DatadogInstrumentationEventSource; they will be ordered by endTime by virtue of this method
87
+ // being invoked synchronously with the plugins' finish() handler which evaluates
88
+ // performance.now(). OTOH, events coming from NodeAPIEventSource (GC in typical setup) might be
89
+ // somewhat delayed as they are queued by Node, so they can arrive out of order with regard to
90
+ // events coming from the non-queued source. By omitting the endTime check, we will pass through
91
+ // some short events that started and ended before the current sampling instant. OTOH, if we
92
+ // were to check for this.currentSamplingInstant <= endTime, we would discard some long events
93
+ // that also ended before the current sampling instant. We'd rather err on the side of including
94
+ // some short events than excluding some long events.
95
+ return event.startTime < this.#currentSamplingInstant
96
+ }
97
+
98
+ #setNextSamplingInstant () {
99
+ this.#currentSamplingInstant = this.#nextSamplingInstant
100
+ this.#nextSamplingInstant -= Math.log(1 - Math.random()) * this.#samplingInterval
101
+ this.#samplingInstantCount++
102
+ }
103
+ }
104
+
105
+ module.exports = PoissonProcessSamplingFilter
@@ -75,7 +75,7 @@ class NativeWallProfiler {
75
75
  _started = false
76
76
 
77
77
  constructor (options = {}) {
78
- this._samplingIntervalMicros = options.samplingInterval || 1e6 / 99 // 99hz
78
+ this._samplingIntervalMicros = (options.samplingInterval || 1e3 / 99) * 1000 // 99hz
79
79
  this._flushIntervalMillis = options.flushInterval || 60 * 1e3 // 60 seconds
80
80
  this._codeHotspotsEnabled = !!options.codeHotspotsEnabled
81
81
  this._endpointCollectionEnabled = !!options.endpointCollectionEnabled
@@ -22,7 +22,7 @@ const kSupportsAckCallback = Symbol('kSupportsAckCallback')
22
22
  // There MUST NOT exist separate instances of RC clients in a tracer making separate ClientGetConfigsRequest
23
23
  // with their own separated Client.ClientState.
24
24
  class RemoteConfigManager extends EventEmitter {
25
- static get kPreUpdate () { return kPreUpdate }
25
+ static kPreUpdate = kPreUpdate
26
26
 
27
27
  constructor (config) {
28
28
  super()