-
Notifications
You must be signed in to change notification settings - Fork 407
Expand file tree
/
Copy pathspans.js
More file actions
118 lines (105 loc) · 4.05 KB
/
Copy pathspans.js
File metadata and controls
118 lines (105 loc) · 4.05 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
'use strict'
const assert = require('node:assert/strict')
const guard = require('../startup-guard')
const eraseTrace = require('../../../packages/dd-trace/src/span-processor-state')
const tracer = require('../../..').init()
/** @param {import('../../../packages/dd-trace/src/opentracing/span')} span */
tracer._tracer._processor.process = function process (span) {
const trace = span.context()._trace
eraseTrace(trace, [])
}
const { FINISH, SHAPE = 'plain' } = process.env
// Keep the operation count tunable because the span shapes cross the allocation
// cliff at different points.
const OPERATIONS = Number(process.env.OPERATIONS)
// finish-later defers the finish so it runs off the active-span path. Holding all
// operations live at once would grow the heap with the workload. Fixed-size batches
// still exercise deferred finish while keeping live memory flat.
const BATCH = Number(process.env.BATCH) || 2000
const spans = []
// Span sanitizes link / event attributes inline; reusing the pre-built objects across
// iterations is safe and matches plugin-emitted span construction.
const TAGS = { service: 'svc', env: 'prod', 'http.method': 'GET' }
const LINK_TARGET = tracer.startSpan('link-target')
const LINK_CONTEXT = LINK_TARGET.context()
const LINK_ATTRIBUTES = { 'event.kind': 'fork', priority: 1, ok: true }
const EVENT_ATTRIBUTES = { attempt: 1, ok: true, code: 200 }
const FIELDS_WITH_TAGS = { tags: TAGS }
const FIELDS_WITH_TAGS_AND_LINKS = {
tags: TAGS,
links: [{ context: LINK_CONTEXT, attributes: LINK_ATTRIBUTES }],
}
// An enriched HTTP+DB server span: ~20 tags across http, db, peer and custom
// keys, matching what a plugin plus user code attaches on a real request. Drives
// the addTags path far harder than the 3-tag shape.
const MANY_TAGS = {
'http.method': 'POST',
'http.url': 'https://api.example.com/v2/orders',
'http.status_code': 200,
'http.route': '/v2/orders',
'span.kind': 'server',
component: 'express',
'db.type': 'postgres',
'db.name': 'orders',
'db.user': 'app_writer',
'peer.service': 'orders-db',
'out.host': 'db-primary.internal',
'out.port': 5432,
env: 'production',
version: '1.42.3',
'service.name': 'orders-api',
'user.id': 'u-1234567',
'tenant.id': 't-7654321',
region: 'us-east-1',
'request.id': 'req-abcdef0123',
'feature.flag': 'checkout_v2',
}
const FIELDS_WITH_MANY_TAGS = { tags: MANY_TAGS }
// Pre-flight: confirm tags / links / events actually attach; catches a silent
// breakage where the construction shape stopped propagating.
const sanitySpan = tracer.startSpan('sanity.span', FIELDS_WITH_TAGS_AND_LINKS)
sanitySpan.addEvent('sanity-event', EVENT_ATTRIBUTES)
assert.equal(sanitySpan.context().getTag('service'), 'svc')
assert.equal(sanitySpan._links.length, 1)
assert.equal(sanitySpan._events.length, 1)
sanitySpan.finish()
LINK_TARGET.finish()
// One span creation for the active shape. addEvent only applies to the otel shape.
function startOne () {
if (SHAPE === 'tags') {
return tracer.startSpan('some.span.name', FIELDS_WITH_TAGS)
}
if (SHAPE === 'many-tags') {
return tracer.startSpan('some.span.name', FIELDS_WITH_MANY_TAGS)
}
if (SHAPE === 'tags-and-otel') {
const span = tracer.startSpan('some.span.name', FIELDS_WITH_TAGS_AND_LINKS)
span.addEvent('event-name', EVENT_ATTRIBUTES)
return span
}
return tracer.startSpan('some.span.name', {})
}
guard.loopStart()
if (FINISH === 'now') {
for (let iteration = 0; iteration < OPERATIONS; iteration++) {
startOne().finish()
}
} else {
// Deferred finish in batches: start BATCH spans, finish them after the batch is
// built (so each finishes off the active path), then drop the references.
let remaining = OPERATIONS
while (remaining > 0) {
const size = remaining < BATCH ? remaining : BATCH
for (let i = 0; i < size; i++) {
spans.push(startOne())
}
for (let i = 0; i < size; i++) {
spans[i].finish()
}
spans.length = 0
remaining -= size
}
}
// These allocation-heavy variants cannot grow enough to meet the default startup
// share without crossing the GC cliff.
guard.done(0.15)