-
Notifications
You must be signed in to change notification settings - Fork 406
Expand file tree
/
Copy pathindex.js
More file actions
127 lines (115 loc) · 4.62 KB
/
Copy pathindex.js
File metadata and controls
127 lines (115 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
'use strict'
const assert = require('node:assert/strict')
// Entry point normally primes this; bench imports src directly.
globalThis[Symbol.for('dd-trace')] ??= { beforeExitHandlers: new Set() }
const hostname = require('os').hostname()
const guard = require('../startup-guard')
// CI runs candidate benchmark sources against the baseline tracer source.
let SpanProcessor
try {
SpanProcessor = require('../../../packages/dd-trace/src/js_span_processor')
} catch (e) {
if (e.code !== 'MODULE_NOT_FOUND' || !e.message.includes('js_span_processor')) throw e
SpanProcessor = require('../../../packages/dd-trace/src/span_processor')
}
const PrioritySampler = require('../../../packages/dd-trace/src/priority_sampler')
const id = require('../../../packages/dd-trace/src/id')
// Measures the front of the export pipeline: SpanProcessor.process -> priority
// and span sampling -> spanFormat (span -> wire shape). The encoder and the
// agent socket are out of scope on purpose: encode is covered by the `encoding`
// bench, and the real flush is a deferred unref'd timer that barely fires in a
// short run. A no-op exporter keeps the loop CPU-bound, leaves memory flat (the
// formatted chunk is discarded each pass) and drops the agent dependency.
const OPERATIONS = Number(process.env.OPERATIONS)
const WITH_STATS = process.env.WITH_STATS === '1'
const WITH_LINKS = process.env.WITH_LINKS === '1'
// Span link + events fixture for the links-and-events variant. spanFormat
// serializes links into meta['_dd.span_links'] and maps events onto span_events
// for every formatted span -- otel-era paths the plain shape never hits.
const LINK_CONTEXT = {
toTraceId: () => '1234567890abcdef1234567890abcdef',
toSpanId: () => 'abcdef1234567890',
_sampling: { priority: 1 },
}
const LINK_ATTRIBUTES = { 'link.kind': 'fork', priority: 1, ok: true }
const SPAN_EVENTS = [
{ name: 'http.attempt', startTime: 1_415_926.5, attributes: { attempt: 1, ok: true, code: 200 } },
{ name: 'db.query', startTime: 1_415_927, attributes: { rows: 17 } },
]
let exported = 0
let lastFormatted
const exporter = { export (formatted) { exported += formatted.length; lastFormatted = formatted } }
const prioritySampler = new PrioritySampler()
const config = {
flushMinSpans: 100,
stats: {
DD_TRACE_STATS_COMPUTATION_ENABLED: WITH_STATS,
},
appsec: {},
}
const sp = new SpanProcessor(exporter, prioritySampler, config)
const finished = []
const trace = { finished, started: finished, tags: {} }
function createSpan (parent) {
const spanId = id(0)
const context = {
_trace: trace,
_spanId: spanId,
_name: 'this is a name',
_traceId: parent ? parent.context()._traceId : spanId,
_parentId: parent ? parent.context()._spanId : id(0),
_hostname: hostname,
_sampling: {},
_tags: {
'service.name': 'hello',
a: 'b',
and: 'this is a longer string, just because we want to test some longer strongs, got it? okay',
b: 45,
something: 98764389,
afloaty: 203987465.756754,
},
getTag (key) { return this._tags[key] },
getTags () { return this._tags },
}
const span = {
context: () => context,
tracer: () => { return { _service: 'exporting-pipeline-sirun' } },
setTag: () => {},
_startTime: 1415926,
_duration: 100,
}
if (WITH_LINKS) {
span._links = [{ context: LINK_CONTEXT, attributes: LINK_ATTRIBUTES }]
span._events = SPAN_EVENTS
}
finished.push(span)
return span
}
for (let i = 0, parent = null; i < 30; i++) {
parent = createSpan(parent)
}
// Pre-flight: one pass must format and hand the whole 30-span chunk to the
// exporter; a broken format path would otherwise measure a near-empty loop.
trace.started = finished
trace.finished = finished
sp.process(finished[0])
assert.equal(exported, 30, 'span processor did not format and export the chunk')
// The stats variant must actually build the stats processor: a renamed config
// key would otherwise leave it off and the variant would silently measure the
// no-stats path, showing up as a spurious A/B improvement.
assert.equal(Boolean(sp._stats), WITH_STATS, 'stats computation did not match the WITH_STATS variant')
if (WITH_LINKS) {
assert.ok(lastFormatted[0].meta['_dd.span_links'], 'span links were not formatted')
assert.ok(lastFormatted[0].span_events?.length, 'span events were not formatted')
}
guard.loopStart()
exported = 0
for (let i = 0; i < OPERATIONS; i++) {
// process() erases trace.finished each pass; restore the chunk so every
// iteration formats the full set.
trace.started = finished
trace.finished = finished
sp.process(finished[0])
}
assert.ok(exported > 0, 'export loop produced no formatted spans')
guard.done()