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.
- package/package.json +1 -1
- package/packages/datadog-instrumentations/src/apollo-server.js +50 -8
- package/packages/datadog-instrumentations/src/aws-sdk.js +49 -60
- package/packages/datadog-instrumentations/src/fastify.js +61 -55
- package/packages/datadog-instrumentations/src/graphql.js +90 -122
- package/packages/datadog-instrumentations/src/http2/server.js +14 -20
- package/packages/datadog-instrumentations/src/microgateway-core.js +16 -15
- package/packages/datadog-instrumentations/src/mongodb-core.js +34 -29
- package/packages/datadog-instrumentations/src/mongodb.js +9 -13
- package/packages/datadog-instrumentations/src/mongoose.js +25 -29
- package/packages/datadog-instrumentations/src/openai.js +0 -2
- package/packages/datadog-instrumentations/src/oracledb.js +39 -33
- package/packages/datadog-instrumentations/src/router.js +1 -1
- package/packages/datadog-plugin-aerospike/src/index.js +5 -9
- package/packages/datadog-plugin-amqp10/src/consumer.js +2 -2
- package/packages/datadog-plugin-amqp10/src/index.js +1 -1
- package/packages/datadog-plugin-amqp10/src/producer.js +3 -3
- package/packages/datadog-plugin-amqplib/src/client.js +3 -3
- package/packages/datadog-plugin-amqplib/src/consumer.js +2 -2
- package/packages/datadog-plugin-amqplib/src/index.js +1 -1
- package/packages/datadog-plugin-amqplib/src/producer.js +2 -2
- package/packages/datadog-plugin-apollo/src/gateway/execute.js +2 -4
- package/packages/datadog-plugin-apollo/src/gateway/fetch.js +2 -4
- package/packages/datadog-plugin-apollo/src/gateway/index.js +1 -1
- package/packages/datadog-plugin-apollo/src/gateway/plan.js +2 -4
- package/packages/datadog-plugin-apollo/src/gateway/postprocessing.js +2 -4
- package/packages/datadog-plugin-apollo/src/gateway/request.js +2 -4
- package/packages/datadog-plugin-apollo/src/gateway/validate.js +2 -4
- package/packages/datadog-plugin-apollo/src/index.js +1 -1
- package/packages/datadog-plugin-avsc/src/index.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/base.js +70 -46
- package/packages/datadog-plugin-aws-sdk/src/index.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/index.js +1 -3
- package/packages/datadog-plugin-aws-sdk/src/services/bedrockruntime/tracing.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/cloudwatchlogs.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/dynamodb.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/services/eventbridge.js +2 -2
- package/packages/datadog-plugin-aws-sdk/src/services/kinesis.js +22 -20
- package/packages/datadog-plugin-aws-sdk/src/services/lambda.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/redshift.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/s3.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/services/sfn.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/sns.js +3 -3
- package/packages/datadog-plugin-aws-sdk/src/services/sqs.js +17 -15
- package/packages/datadog-plugin-aws-sdk/src/services/states.js +1 -1
- package/packages/datadog-plugin-aws-sdk/src/services/stepfunctions.js +1 -1
- package/packages/datadog-plugin-azure-functions/src/index.js +5 -5
- package/packages/datadog-plugin-azure-service-bus/src/index.js +1 -1
- package/packages/datadog-plugin-azure-service-bus/src/producer.js +2 -2
- package/packages/datadog-plugin-bunyan/src/index.js +3 -5
- package/packages/datadog-plugin-cassandra-driver/src/index.js +3 -3
- package/packages/datadog-plugin-child_process/src/index.js +2 -2
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/batch-consumer.js +1 -3
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/consumer.js +1 -3
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/index.js +1 -1
- package/packages/datadog-plugin-confluentinc-kafka-javascript/src/producer.js +1 -3
- package/packages/datadog-plugin-connect/src/index.js +1 -3
- package/packages/datadog-plugin-couchbase/src/index.js +2 -2
- package/packages/datadog-plugin-cucumber/src/index.js +1 -3
- package/packages/datadog-plugin-cypress/src/index.js +1 -3
- package/packages/datadog-plugin-dd-trace-api/src/index.js +1 -3
- package/packages/datadog-plugin-dns/src/index.js +1 -1
- package/packages/datadog-plugin-dns/src/lookup.js +2 -2
- package/packages/datadog-plugin-dns/src/lookup_service.js +2 -2
- package/packages/datadog-plugin-dns/src/resolve.js +2 -2
- package/packages/datadog-plugin-dns/src/reverse.js +2 -2
- package/packages/datadog-plugin-elasticsearch/src/index.js +1 -1
- package/packages/datadog-plugin-express/src/code_origin.js +1 -3
- package/packages/datadog-plugin-express/src/index.js +1 -1
- package/packages/datadog-plugin-express/src/tracing.js +1 -3
- package/packages/datadog-plugin-fastify/src/code_origin.js +1 -3
- package/packages/datadog-plugin-fastify/src/index.js +1 -1
- package/packages/datadog-plugin-fastify/src/tracing.js +18 -3
- package/packages/datadog-plugin-fetch/src/index.js +2 -2
- package/packages/datadog-plugin-find-my-way/src/index.js +1 -3
- package/packages/datadog-plugin-fs/src/index.js +2 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/client.js +3 -3
- package/packages/datadog-plugin-google-cloud-pubsub/src/consumer.js +2 -2
- package/packages/datadog-plugin-google-cloud-pubsub/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-pubsub/src/producer.js +2 -2
- package/packages/datadog-plugin-google-cloud-vertexai/src/index.js +1 -1
- package/packages/datadog-plugin-google-cloud-vertexai/src/tracing.js +2 -4
- package/packages/datadog-plugin-graphql/src/execute.js +16 -9
- package/packages/datadog-plugin-graphql/src/index.js +1 -1
- package/packages/datadog-plugin-graphql/src/parse.js +12 -7
- package/packages/datadog-plugin-graphql/src/resolve.js +50 -16
- package/packages/datadog-plugin-graphql/src/validate.js +13 -7
- package/packages/datadog-plugin-grpc/src/client.js +4 -4
- package/packages/datadog-plugin-grpc/src/index.js +1 -1
- package/packages/datadog-plugin-grpc/src/server.js +3 -3
- package/packages/datadog-plugin-hapi/src/index.js +1 -3
- package/packages/datadog-plugin-hono/src/index.js +1 -3
- package/packages/datadog-plugin-http/src/client.js +2 -2
- package/packages/datadog-plugin-http/src/index.js +1 -1
- package/packages/datadog-plugin-http/src/server.js +3 -7
- package/packages/datadog-plugin-http2/src/client.js +2 -2
- package/packages/datadog-plugin-http2/src/index.js +1 -1
- package/packages/datadog-plugin-http2/src/server.js +22 -11
- package/packages/datadog-plugin-ioredis/src/index.js +1 -3
- package/packages/datadog-plugin-iovalkey/src/index.js +2 -4
- package/packages/datadog-plugin-jest/src/index.js +1 -3
- package/packages/datadog-plugin-kafkajs/src/batch-consumer.js +2 -2
- package/packages/datadog-plugin-kafkajs/src/consumer.js +2 -2
- package/packages/datadog-plugin-kafkajs/src/index.js +1 -1
- package/packages/datadog-plugin-kafkajs/src/producer.js +3 -3
- package/packages/datadog-plugin-koa/src/index.js +1 -3
- package/packages/datadog-plugin-langchain/src/index.js +2 -2
- package/packages/datadog-plugin-langchain/src/tracing.js +30 -48
- package/packages/datadog-plugin-mariadb/src/index.js +2 -2
- package/packages/datadog-plugin-memcached/src/index.js +1 -1
- package/packages/datadog-plugin-microgateway-core/src/index.js +4 -4
- package/packages/datadog-plugin-mocha/src/index.js +1 -3
- package/packages/datadog-plugin-moleculer/src/client.js +2 -2
- package/packages/datadog-plugin-moleculer/src/index.js +1 -1
- package/packages/datadog-plugin-moleculer/src/server.js +2 -2
- package/packages/datadog-plugin-mongodb-core/src/index.js +9 -5
- package/packages/datadog-plugin-mongoose/src/index.js +20 -0
- package/packages/datadog-plugin-mysql/src/index.js +2 -2
- package/packages/datadog-plugin-mysql2/src/index.js +1 -1
- package/packages/datadog-plugin-net/src/index.js +1 -1
- package/packages/datadog-plugin-net/src/ipc.js +2 -2
- package/packages/datadog-plugin-net/src/tcp.js +2 -2
- package/packages/datadog-plugin-next/src/index.js +1 -3
- package/packages/datadog-plugin-nyc/src/index.js +1 -3
- package/packages/datadog-plugin-openai/src/index.js +1 -1
- package/packages/datadog-plugin-openai/src/tracing.js +7 -411
- package/packages/datadog-plugin-opensearch/src/index.js +1 -3
- package/packages/datadog-plugin-oracledb/src/index.js +9 -5
- package/packages/datadog-plugin-pg/src/index.js +3 -3
- package/packages/datadog-plugin-pino/src/index.js +3 -5
- package/packages/datadog-plugin-playwright/src/index.js +1 -3
- package/packages/datadog-plugin-prisma/src/client.js +4 -6
- package/packages/datadog-plugin-prisma/src/engine.js +3 -3
- package/packages/datadog-plugin-prisma/src/index.js +1 -1
- package/packages/datadog-plugin-protobufjs/src/index.js +2 -6
- package/packages/datadog-plugin-redis/src/index.js +2 -2
- package/packages/datadog-plugin-restify/src/index.js +1 -3
- package/packages/datadog-plugin-rhea/src/consumer.js +1 -1
- package/packages/datadog-plugin-rhea/src/index.js +1 -1
- package/packages/datadog-plugin-rhea/src/producer.js +2 -2
- package/packages/datadog-plugin-router/src/index.js +1 -3
- package/packages/datadog-plugin-selenium/src/index.js +1 -3
- package/packages/datadog-plugin-sharedb/src/index.js +1 -1
- package/packages/datadog-plugin-tedious/src/index.js +3 -3
- package/packages/datadog-plugin-undici/src/index.js +2 -4
- package/packages/datadog-plugin-vitest/src/index.js +1 -3
- package/packages/datadog-plugin-web/src/index.js +1 -3
- package/packages/datadog-plugin-winston/src/index.js +3 -5
- package/packages/dd-trace/src/appsec/channels.js +1 -0
- package/packages/dd-trace/src/appsec/graphql.js +14 -12
- package/packages/dd-trace/src/appsec/iast/taint-tracking/plugin.js +1 -1
- package/packages/dd-trace/src/appsec/waf/waf_manager.js +1 -1
- package/packages/dd-trace/src/ci-visibility/log-submission/log-submission-plugin.js +1 -3
- package/packages/dd-trace/src/ci-visibility/test-api-manual/test-api-manual-plugin.js +1 -3
- package/packages/dd-trace/src/config.js +1 -1
- package/packages/dd-trace/src/datastreams/checkpointer.js +23 -2
- package/packages/dd-trace/src/datastreams/processor.js +4 -3
- package/packages/dd-trace/src/llmobs/plugins/langchain/index.js +30 -50
- package/packages/dd-trace/src/llmobs/plugins/openai.js +3 -5
- package/packages/dd-trace/src/llmobs/plugins/vertexai.js +3 -5
- package/packages/dd-trace/src/opentracing/propagation/text_map.js +25 -2
- package/packages/dd-trace/src/plugins/apollo.js +3 -3
- package/packages/dd-trace/src/plugins/cache.js +1 -1
- package/packages/dd-trace/src/plugins/client.js +3 -3
- package/packages/dd-trace/src/plugins/consumer.js +3 -3
- package/packages/dd-trace/src/plugins/database.js +2 -2
- package/packages/dd-trace/src/plugins/index.js +1 -0
- package/packages/dd-trace/src/plugins/log_plugin.js +1 -5
- package/packages/dd-trace/src/plugins/outbound.js +1 -1
- package/packages/dd-trace/src/plugins/plugin.js +1 -1
- package/packages/dd-trace/src/plugins/producer.js +3 -3
- package/packages/dd-trace/src/plugins/server.js +3 -3
- package/packages/dd-trace/src/plugins/storage.js +1 -1
- package/packages/dd-trace/src/plugins/tracing.js +24 -6
- package/packages/dd-trace/src/plugins/util/ci.js +11 -7
- package/packages/dd-trace/src/plugins/util/inferred_proxy.js +15 -19
- package/packages/dd-trace/src/plugins/util/tags.js +2 -0
- package/packages/dd-trace/src/plugins/util/web.js +26 -7
- package/packages/dd-trace/src/profiling/config.js +2 -0
- package/packages/dd-trace/src/profiling/exporters/event_serializer.js +2 -21
- package/packages/dd-trace/src/profiling/libuv-size.js +49 -0
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns.js +2 -6
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookup.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_lookupservice.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_resolve.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/event_plugins/dns_reverse.js +1 -3
- package/packages/dd-trace/src/profiling/profilers/event_plugins/fs.js +3 -9
- package/packages/dd-trace/src/profiling/profilers/event_plugins/net.js +3 -9
- package/packages/dd-trace/src/profiling/profilers/events.js +80 -62
- package/packages/dd-trace/src/profiling/profilers/poisson.js +105 -0
- package/packages/dd-trace/src/profiling/profilers/wall.js +1 -1
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
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
|
-
|
|
391
|
+
#maxSamples
|
|
392
|
+
#eventSerializer
|
|
393
|
+
#eventSources
|
|
380
394
|
|
|
381
395
|
constructor (options = {}) {
|
|
382
|
-
|
|
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
|
-
|
|
385
|
-
|
|
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
|
|
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
|
-
?
|
|
397
|
-
|
|
398
|
-
|
|
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
|
-
:
|
|
417
|
+
: [
|
|
418
|
+
new NodeApiEventSource(filteringEventHandler)
|
|
419
|
+
]
|
|
402
420
|
}
|
|
403
421
|
|
|
404
422
|
start () {
|
|
405
|
-
this.
|
|
423
|
+
this.#eventSources.forEach(s => s.start())
|
|
406
424
|
}
|
|
407
425
|
|
|
408
426
|
stop () {
|
|
409
|
-
this.
|
|
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
|
|
417
|
-
this
|
|
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 ||
|
|
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
|
|
25
|
+
static kPreUpdate = kPreUpdate
|
|
26
26
|
|
|
27
27
|
constructor (config) {
|
|
28
28
|
super()
|