-
Notifications
You must be signed in to change notification settings - Fork 406
Expand file tree
/
Copy pathindex.js
More file actions
120 lines (108 loc) · 4.35 KB
/
Copy pathindex.js
File metadata and controls
120 lines (108 loc) · 4.35 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
'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')
const 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()