Skip to content

Commit 672e321

Browse files
committed
Testing
1 parent bf17096 commit 672e321

File tree

3 files changed

+93
-6
lines changed

3 files changed

+93
-6
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict'
2+
3+
const performance = require('perf_hooks').performance
4+
5+
const EVENT_COUNT = parseInt(process.argv[2])
6+
require('dd-trace').init().profilerStarted().then(() => {
7+
const EventSource = require('dd-trace/packages/dd-trace/src/profiling/profilers/events.js')
8+
const template = {
9+
entryType: 'dns',
10+
duration: 10,
11+
name: 'lookup',
12+
_ddSpanId: '1234567890abcdef',
13+
_ddRootSpanId: 'abcdef1234567890',
14+
detail: {
15+
hostname: 'example.com'
16+
}
17+
}
18+
for (let i = 0; i < EVENT_COUNT; i++) {
19+
EventSource.emitTestEvent({ startTime: performance.now(), ...template })
20+
}
21+
})

integration-tests/profiler/profiler.spec.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,33 @@ describe('profiler', () => {
454454
assert.equal(endpoints.size, 3, encoded)
455455
})
456456

457+
it('number of events is limited', async () => {
458+
const threads = 1
459+
const uploadPeriodSec = 10
460+
const samplingPeriodMs = 1000 / 99
461+
// Recreates getMaxSamples from packages/dd-trace/src/profiling/profilers/events.js
462+
const maxEvents = Math.floor((threads + 2) * uploadPeriodSec * 1000 / samplingPeriodMs)
463+
464+
// Test will try to force maxEvents + 10 events, we'll assert that only maxEvents are captured.
465+
const proc = fork(path.join(cwd, 'profiler/eventlimits.js'), [String(maxEvents + 10)], {
466+
cwd,
467+
env: {
468+
DD_PROFILING_EXPORTERS: 'file',
469+
DD_PROFILING_ENABLED: 1,
470+
DD_INTERNAL_PROFILING_TIMELINE_SAMPLING_ENABLED: 0, // capture all events
471+
DD_TRACE_AGENT_PORT: agent.port,
472+
TESTING_PROFILING_EVENTS: 'true', // enable test event source
473+
DD_PROFILING_UPLOAD_PERIOD: String(uploadPeriodSec),
474+
UV_THREADPOOL_SIZE: String(threads)
475+
}
476+
})
477+
478+
await processExitPromise(proc, TIMEOUT)
479+
480+
const { profile, encoded } = await getLatestProfile(cwd, /^events_.+\.pprof$/)
481+
assert.equal(profile.sample.length, maxEvents, encoded)
482+
})
483+
457484
it('fs timeline events work', async () => {
458485
const fsEvents = await gatherFilesystemTimelineEvents(cwd, 'profiler/fstest.js', agent.port)
459486
assert.equal(fsEvents.length, 6)

packages/dd-trace/src/profiling/profilers/events.js

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ const { performance, constants, PerformanceObserver } = require('perf_hooks')
44
const { END_TIMESTAMP_LABEL, SPAN_ID_LABEL, LOCAL_ROOT_SPAN_ID_LABEL, encodeProfileAsync } = require('./shared')
55
const { Function, Label, Line, Location, Profile, Sample, StringTable, ValueType } = require('pprof-format')
66
const { availableParallelism, effectiveLibuvThreadCount } = require('../libuv-size')
7+
const { getEnvironmentVariables } = require('../../config-helper')
8+
const dc = require('dc-polyfill')
9+
10+
const testEventChannel = ['true', '1'].includes(getEnvironmentVariables('TESTING_PROFILING_EVENTS'))
11+
? dc.channel('dd-trace:profiling:events-test')
12+
: undefined
713

814
// perf_hooks uses millis, with fractional part representing nanos. We emit nanos into the pprof file.
915
const MS_TO_NS = 1_000_000
@@ -363,6 +369,27 @@ class DatadogInstrumentationEventSource {
363369
}
364370
}
365371

372+
class TestEventSource {
373+
constructor (eventHandler) {
374+
this.eventHandler = eventHandler
375+
this.started = false
376+
}
377+
378+
start () {
379+
if (!this.started) {
380+
testEventChannel.subscribe(this.eventHandler)
381+
this.started = true
382+
}
383+
}
384+
385+
stop () {
386+
if (this.started) {
387+
testEventChannel.unsubscribe(this.eventHandler)
388+
this.started = false
389+
}
390+
}
391+
}
392+
366393
class CompositeEventSource {
367394
constructor (sources) {
368395
this.sources = sources
@@ -430,15 +457,21 @@ class EventsProfiler {
430457
}
431458
}
432459

433-
this.eventSource = options.codeHotspotsEnabled
460+
const eventSources = options.codeHotspotsEnabled
434461
// Use Datadog instrumentation to collect events with span IDs. Still use
435462
// Node API for GC events.
436-
? new CompositeEventSource([
437-
new DatadogInstrumentationEventSource(eventHandler, eventFilter),
438-
new NodeApiEventSource(filteringEventHandler, ['gc'])
439-
])
463+
? [
464+
new DatadogInstrumentationEventSource(eventHandler, eventFilter),
465+
new NodeApiEventSource(filteringEventHandler, ['gc']),
466+
]
440467
// Use Node API instrumentation to collect events without span IDs
441-
: new NodeApiEventSource(filteringEventHandler)
468+
: [
469+
new NodeApiEventSource(filteringEventHandler)
470+
]
471+
if (testEventChannel !== undefined) {
472+
eventSources.push(new TestEventSource(filteringEventHandler))
473+
}
474+
this.eventSource = new CompositeEventSource(eventSources)
442475
}
443476

444477
start () {
@@ -461,6 +494,12 @@ class EventsProfiler {
461494
encode (profile) {
462495
return encodeProfileAsync(profile())
463496
}
497+
498+
static emitTestEvent (event) {
499+
if (testEventChannel !== undefined) {
500+
testEventChannel.publish(event)
501+
}
502+
}
464503
}
465504

466505
module.exports = EventsProfiler

0 commit comments

Comments
 (0)