Skip to content

Commit 323c0d7

Browse files
committed
Parameterized testing.
1 parent 8a2d8d9 commit 323c0d7

File tree

11 files changed

+1007
-967
lines changed

11 files changed

+1007
-967
lines changed

sdk/highlight-run/src/client/graph/operators/mutation.gql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,12 @@ mutation initializeSession(
142142
}
143143
logs {
144144
message {
145-
...RegexMatchParts
146-
...BasicMatchParts
145+
...RegexMatchParts
146+
...BasicMatchParts
147147
}
148148
severityText {
149-
...RegexMatchParts
150-
...BasicMatchParts
149+
...RegexMatchParts
150+
...BasicMatchParts
151151
}
152152
attributes {
153153
key {

sdk/highlight-run/src/client/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ export class Highlight {
690690
backendUrl:
691691
this.options?.backendUrl ?? 'https://pub.highlight.io',
692692
otlpEndpoint:
693-
this.options?.otlpEndpoint ??
693+
this.options?.otlpEndpoint ??
694694
'https://otel.highlight.io',
695695
projectId: this.sessionData.projectID,
696696
sessionSecureId: this.sessionData.sessionSecureID,

sdk/highlight-run/src/client/otel/exporter.ts

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ export type MetricExporterConfig = ConstructorParameters<
2222
// - https://github.com/open-telemetry/opentelemetry-js/issues/3489
2323
// - https://github.com/open-telemetry/opentelemetry-js/blob/cf8edbed43c3e54eadcafe6fc6f39a1d03c89aa7/experimental/packages/otlp-exporter-base/src/platform/browser/OTLPExporterBrowserBase.ts#L51-L52
2424

25-
function cloneReadableSpanWithAttributes(span: ReadableSpan, attributes: Attributes): ReadableSpan {
26-
const spanContext = span.spanContext();
25+
function cloneReadableSpanWithAttributes(
26+
span: ReadableSpan,
27+
attributes: Attributes,
28+
): ReadableSpan {
29+
const spanContext = span.spanContext()
2730
const cloned = {
2831
name: span.name,
2932
kind: span.kind,
@@ -43,14 +46,17 @@ function cloneReadableSpanWithAttributes(span: ReadableSpan, attributes: Attribu
4346
droppedEventsCount: span.droppedEventsCount,
4447
droppedLinksCount: span.droppedLinksCount,
4548
}
46-
return cloned;
49+
return cloned
4750
}
4851

4952
export class OTLPTraceExporterBrowserWithXhrRetry extends OTLPTraceExporter {
5053
private readonly xhrTraceExporter: OTLPTraceExporter
5154
private readonly sampler: Sampler
5255

53-
constructor(config?: TraceExporterConfig, samplingConfig?: Maybe<SamplingConfig>) {
56+
constructor(
57+
config?: TraceExporterConfig,
58+
samplingConfig?: Maybe<SamplingConfig>,
59+
) {
5460
super(config)
5561
this.sampler = new CustomSampler(samplingConfig)
5662
this.xhrTraceExporter = new OTLPTraceExporter({
@@ -59,26 +65,41 @@ export class OTLPTraceExporterBrowserWithXhrRetry extends OTLPTraceExporter {
5965
})
6066
}
6167

62-
export(items: ReadableSpan[], resultCallback: (result: ExportResult) => void) {
63-
const omittedSpansIds: string[] = [];
64-
const spanById: Record<string, ReadableSpan> = {};
65-
const childrenByParentId: Record<string, string[]> = {};
66-
68+
export(
69+
items: ReadableSpan[],
70+
resultCallback: (result: ExportResult) => void,
71+
) {
72+
const omittedSpansIds: string[] = []
73+
const spanById: Record<string, ReadableSpan> = {}
74+
const childrenByParentId: Record<string, string[]> = {}
75+
6776
// The first pass we sample items which are directly impacted by a sampling decision.
6877
// We also build a map of children spans by parent span id, which allows us to quickly traverse the span tree.
6978
for (const item of items) {
70-
if(item.parentSpanId) {
71-
childrenByParentId[item.parentSpanId] = childrenByParentId[item.parentSpanId] || [];
72-
childrenByParentId[item.parentSpanId].push(item.spanContext().spanId);
79+
if (item.parentSpanId) {
80+
childrenByParentId[item.parentSpanId] =
81+
childrenByParentId[item.parentSpanId] || []
82+
childrenByParentId[item.parentSpanId].push(
83+
item.spanContext().spanId,
84+
)
7385
}
74-
console.log("Before sampling", item.name);
75-
const sampleResult = this.sampler.shouldSample(item);
76-
console.log('After sampling', item.name, 'sampleResult', sampleResult);
86+
console.log('Before sampling', item.name)
87+
const sampleResult = this.sampler.shouldSample(item)
88+
console.log(
89+
'After sampling',
90+
item.name,
91+
'sampleResult',
92+
sampleResult,
93+
)
7794
if (sampleResult.sample) {
78-
if(sampleResult.attributes) {
79-
spanById[item.spanContext().spanId] = cloneReadableSpanWithAttributes(item, sampleResult.attributes);
95+
if (sampleResult.attributes) {
96+
spanById[item.spanContext().spanId] =
97+
cloneReadableSpanWithAttributes(
98+
item,
99+
sampleResult.attributes,
100+
)
80101
} else {
81-
spanById[item.spanContext().spanId] = item;
102+
spanById[item.spanContext().spanId] = item
82103
}
83104
} else {
84105
omittedSpansIds.push(item.spanContext().spanId)
@@ -87,21 +108,22 @@ export class OTLPTraceExporterBrowserWithXhrRetry extends OTLPTraceExporter {
87108

88109
// Find all children of spans that have been sampled out and remove them.
89110
// Repeat until there are no more children to remove.
90-
while(omittedSpansIds.length > 0) {
91-
console.log('omittedSpansIds', omittedSpansIds);
92-
const spanId = omittedSpansIds.shift();
93-
const affectedSpans: string[] | undefined = childrenByParentId[spanId!];
94-
if(!affectedSpans) {
95-
continue;
111+
while (omittedSpansIds.length > 0) {
112+
console.log('omittedSpansIds', omittedSpansIds)
113+
const spanId = omittedSpansIds.shift()
114+
const affectedSpans: string[] | undefined =
115+
childrenByParentId[spanId!]
116+
if (!affectedSpans) {
117+
continue
96118
}
97119

98-
for(const spanIdToRemove of affectedSpans) {
99-
delete spanById[spanIdToRemove];
100-
omittedSpansIds.push(spanIdToRemove);
120+
for (const spanIdToRemove of affectedSpans) {
121+
delete spanById[spanIdToRemove]
122+
omittedSpansIds.push(spanIdToRemove)
101123
}
102124
}
103-
const sampledItems = Object.values(spanById);
104-
125+
const sampledItems = Object.values(spanById)
126+
105127
let retries = 0
106128
const retry = (result: ExportResult) => {
107129
retries++

sdk/highlight-run/src/client/otel/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@ export const setupBrowserTracing = (config: BrowserTracingConfig) => {
108108
keepAlive: true,
109109
},
110110
}
111-
const exporter = new OTLPTraceExporterBrowserWithXhrRetry(exporterOptions, config.sampling)
111+
const exporter = new OTLPTraceExporterBrowserWithXhrRetry(
112+
exporterOptions,
113+
config.sampling,
114+
)
112115

113116
const spanProcessor = new CustomBatchSpanProcessor(exporter, {
114117
maxExportBatchSize: 100,

sdk/highlight-run/src/client/otel/sampling/CustomSampler.test.ts

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,45 +11,45 @@ const LOG_SEVERITY_ATTRIBUTE = 'log.severity'
1111
const LOG_MESSAGE_ATTRIBUTE = 'log.message'
1212

1313
interface SpanTestScenario {
14-
description: string;
15-
samplingConfig: SamplingConfig;
14+
description: string
15+
samplingConfig: SamplingConfig
1616
inputSpan: {
17-
name: string;
18-
attributes?: Record<string, any>;
17+
name: string
18+
attributes?: Record<string, any>
1919
events?: Array<{
20-
name: string;
21-
attributes?: Record<string, any>;
22-
}>;
23-
};
20+
name: string
21+
attributes?: Record<string, any>
22+
}>
23+
}
2424
inputLog?: {
25-
message?: string;
26-
attributes?: Record<string, any>;
27-
severityText?: string;
28-
};
25+
message?: string
26+
attributes?: Record<string, any>
27+
severityText?: string
28+
}
2929
samplerFunctionCases: Array<{
30-
type: 'always' | 'never';
30+
type: 'always' | 'never'
3131
expected_result: {
32-
sample: boolean;
33-
attributes: Record<string, any> | null;
34-
};
35-
}>;
32+
sample: boolean
33+
attributes: Record<string, any> | null
34+
}
35+
}>
3636
}
3737

3838
interface LogTestScenario {
39-
description: string;
40-
samplingConfig: SamplingConfig;
39+
description: string
40+
samplingConfig: SamplingConfig
4141
inputLog: {
42-
message?: string;
43-
attributes?: Record<string, any>;
44-
severityText?: string;
45-
};
42+
message?: string
43+
attributes?: Record<string, any>
44+
severityText?: string
45+
}
4646
samplerFunctionCases: Array<{
47-
type: 'always' | 'never';
47+
type: 'always' | 'never'
4848
expected_result: {
49-
sample: boolean;
50-
attributes: Record<string, any> | null;
51-
};
52-
}>;
49+
sample: boolean
50+
attributes: Record<string, any> | null
51+
}
52+
}>
5353
}
5454

5555
// Test helper function that always returns true for sampling
@@ -97,7 +97,7 @@ const createMockSpan = ({
9797
endTime: [0, 0],
9898
status: { code: 0 },
9999
links: [],
100-
events: events.map(e => ({
100+
events: events.map((e) => ({
101101
name: e.name,
102102
attributes: e.attributes || {},
103103
time: e.time || [0, 0],
@@ -121,8 +121,8 @@ beforeEach(() => {
121121
})
122122

123123
const runTestSpanScenarios = (scenarios: SpanTestScenario[]) => {
124-
scenarios.forEach(scenario => {
125-
scenario.samplerFunctionCases.forEach(samplerCase => {
124+
scenarios.forEach((scenario) => {
125+
scenario.samplerFunctionCases.forEach((samplerCase) => {
126126
const samplerFn = samplerFunctions[samplerCase.type]
127127

128128
it(`${scenario.description} - ${samplerCase.type}`, () => {
@@ -132,15 +132,17 @@ const runTestSpanScenarios = (scenarios: SpanTestScenario[]) => {
132132
const mockSpan = createMockSpan({
133133
name: scenario.inputSpan.name,
134134
attributes: scenario.inputSpan.attributes || {},
135-
events: scenario.inputSpan.events || []
135+
events: scenario.inputSpan.events || [],
136136
})
137137

138138
const result = sampler.shouldSample(mockSpan)
139139

140140
expect(result.sample).toBe(samplerCase.expected_result.sample)
141141

142142
if (samplerCase.expected_result.attributes) {
143-
expect(result.attributes).toEqual(samplerCase.expected_result.attributes)
143+
expect(result.attributes).toEqual(
144+
samplerCase.expected_result.attributes,
145+
)
144146
} else {
145147
expect(result.attributes).toBeUndefined()
146148
}
@@ -150,28 +152,34 @@ const runTestSpanScenarios = (scenarios: SpanTestScenario[]) => {
150152
}
151153

152154
const runTestLogScenarios = (scenarios: LogTestScenario[]) => {
153-
scenarios.forEach(scenario => {
154-
scenario.samplerFunctionCases.forEach(samplerCase => {
155+
scenarios.forEach((scenario) => {
156+
scenario.samplerFunctionCases.forEach((samplerCase) => {
155157
const samplerFn = samplerFunctions[samplerCase.type]
156158

157159
it(`${scenario.description} - ${samplerCase.type}`, () => {
158160
const config = scenario.samplingConfig as SamplingConfig
159161
const sampler = new CustomSampler(config, samplerFn)
160162

161-
const baseAttributes = scenario.inputLog.attributes || {};
162-
const mergedAttributes = { ...baseAttributes, [LOG_MESSAGE_ATTRIBUTE]: scenario.inputLog.message, [LOG_SEVERITY_ATTRIBUTE]: scenario.inputLog.severityText }
163+
const baseAttributes = scenario.inputLog.attributes || {}
164+
const mergedAttributes = {
165+
...baseAttributes,
166+
[LOG_MESSAGE_ATTRIBUTE]: scenario.inputLog.message,
167+
[LOG_SEVERITY_ATTRIBUTE]: scenario.inputLog.severityText,
168+
}
163169

164170
const mockSpan = createMockSpan({
165171
name: LOG_SPAN_NAME,
166-
attributes: mergedAttributes
172+
attributes: mergedAttributes,
167173
})
168174

169175
const result = sampler.shouldSample(mockSpan)
170176

171177
expect(result.sample).toBe(samplerCase.expected_result.sample)
172178

173179
if (samplerCase.expected_result.attributes) {
174-
expect(result.attributes).toEqual(samplerCase.expected_result.attributes)
180+
expect(result.attributes).toEqual(
181+
samplerCase.expected_result.attributes,
182+
)
175183
} else {
176184
expect(result.attributes).toBeUndefined()
177185
}

0 commit comments

Comments
 (0)