Skip to content

Commit 813dfda

Browse files
committed
Add 'bugsnag.sampling.p' attribute
1 parent 8c2592b commit 813dfda

File tree

4 files changed

+67
-6
lines changed

4 files changed

+67
-6
lines changed

packages/core/lib/attributes.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,12 @@ export function attributeToJson (key: string, attribute: SpanAttribute): JsonAtt
6060
if (Number.isNaN(attribute) || !Number.isFinite(attribute)) {
6161
return undefined
6262
}
63-
if (Number.isInteger(attribute)) {
63+
64+
// 'bugsnag.sampling.p' must always be sent as a doubleValue
65+
if (key !== 'bugsnag.sampling.p' && Number.isInteger(attribute)) {
6466
return { key, value: { intValue: `${attribute}` } }
6567
}
68+
6669
return { key, value: { doubleValue: attribute } }
6770
case 'boolean':
6871
return { key, value: { boolValue: attribute } }

packages/core/lib/span.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ export class SpanInternal implements SpanContext {
9494

9595
end (endTime: number, samplingProbability: SpanProbability): SpanEnded {
9696
this.endTime = endTime
97+
let _samplingProbability = samplingProbability
98+
99+
this.attributes.set('bugsnag.sampling.p', _samplingProbability.raw)
100+
97101
return {
98102
id: this.id,
99103
name: this.name,
@@ -104,7 +108,13 @@ export class SpanInternal implements SpanContext {
104108
events: this.events,
105109
samplingRate: this.samplingRate,
106110
endTime,
107-
samplingProbability,
111+
get samplingProbability (): SpanProbability {
112+
return _samplingProbability
113+
},
114+
set samplingProbability (samplingProbability: SpanProbability) {
115+
_samplingProbability = samplingProbability
116+
this.attributes.set('bugsnag.sampling.p', _samplingProbability.raw)
117+
},
108118
parentSpanId: this.parentSpanId
109119
}
110120
}

packages/core/tests/span-factory.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ describe('SpanFactory', () => {
139139
expect(jestLogger.warn).not.toHaveBeenCalled()
140140
})
141141
})
142+
142143
describe('isFirstClass', () => {
143144
it('omits first class span attribute by default', () => {
144145
const clock = new IncrementingClock('1970-01-01T00:00:00.000Z')

packages/core/tests/span.test.ts

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
import { DefaultSpanContextStorage, Kind } from '@bugsnag/core-performance'
32
import {
43
ControllableBackgroundingListener,
@@ -7,14 +6,18 @@ import {
76
IncrementingIdGenerator,
87
StableIdGenerator,
98
VALID_API_KEY,
9+
createSamplingProbability,
1010
createTestClient,
1111
spanAttributesSource
1212
} from '@bugsnag/js-performance-test-utilities'
1313
import {
1414
InMemoryPersistence,
15+
SpanAttributes,
1516
SpanFactory,
17+
SpanInternal,
1618
spanToJson,
1719
spanContextEquals,
20+
type SpanAttribute,
1821
type SpanEnded
1922
} from '../lib'
2023
import Sampler from '../lib/sampler'
@@ -103,6 +106,39 @@ describe('SpanInternal', () => {
103106
}))
104107
})
105108
})
109+
110+
describe('bugsnag.sampling.p', () => {
111+
it.each([0.25, 0.5, 0.1, 1, 0, 0.4, 0.3])('is set to the correct value on "end"', (probability) => {
112+
const span = new SpanInternal(
113+
'span id',
114+
'trace id',
115+
'name',
116+
1234,
117+
new SpanAttributes(new Map<string, SpanAttribute>())
118+
)
119+
120+
const endedSpan = span.end(5678, createSamplingProbability(probability))
121+
122+
// @ts-expect-error 'attributes' is private but very awkward to test otherwise
123+
expect(endedSpan.attributes.attributes.get('bugsnag.sampling.p')).toBe(probability)
124+
})
125+
126+
it.each([0.25, 0.5, 0.1, 1, 0, 0.4, 0.3])('is updated when samplingProbability is changed', (probability) => {
127+
const span = new SpanInternal(
128+
'span id',
129+
'trace id',
130+
'name',
131+
1234,
132+
new SpanAttributes(new Map<string, SpanAttribute>())
133+
)
134+
135+
const endedSpan = span.end(5678, createSamplingProbability(probability))
136+
endedSpan.samplingProbability = createSamplingProbability(probability + 0.1)
137+
138+
// @ts-expect-error 'attributes' is private but very awkward to test otherwise
139+
expect(endedSpan.attributes.attributes.get('bugsnag.sampling.p')).toBe(probability + 0.1)
140+
})
141+
})
106142
})
107143

108144
describe('Span', () => {
@@ -415,7 +451,12 @@ describe('Span', () => {
415451

416452
await jest.runOnlyPendingTimersAsync()
417453

418-
expect(delivery.requests).toHaveLength(1)
454+
expect(delivery).toHaveSentSpan(expect.objectContaining({
455+
name: 'test span',
456+
attributes: expect.arrayContaining([
457+
{ key: 'bugsnag.sampling.p', value: { doubleValue: 1 } }
458+
])
459+
}))
419460
})
420461

421462
it('will always be discarded when probability is 0', async () => {
@@ -491,15 +532,21 @@ describe('Span', () => {
491532
await jest.runOnlyPendingTimersAsync()
492533

493534
expect(delivery).toHaveSentSpan(expect.objectContaining({
494-
name: 'span 1'
535+
name: 'span 1',
536+
attributes: expect.arrayContaining([
537+
{ key: 'bugsnag.sampling.p', value: { doubleValue: 0.14 } }
538+
])
495539
}))
496540

497541
expect(delivery).not.toHaveSentSpan(expect.objectContaining({
498542
name: 'span 2'
499543
}))
500544

501545
expect(delivery).toHaveSentSpan(expect.objectContaining({
502-
name: 'span 3'
546+
name: 'span 3',
547+
attributes: expect.arrayContaining([
548+
{ key: 'bugsnag.sampling.p', value: { doubleValue: 0.14 } }
549+
])
503550
}))
504551
})
505552

0 commit comments

Comments
 (0)