Skip to content

Commit b39f720

Browse files
committed
feat: allow passing in custom 'fn' in span matcher definition
1 parent 5702de0 commit b39f720

File tree

4 files changed

+84
-46
lines changed

4 files changed

+84
-46
lines changed

src/v3/matchSpan.test.ts

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,11 @@ import type {
1010
TicketIdRelationSchemasFixture,
1111
UserIdRelationSchemasFixture,
1212
} from './testUtility/fixtures/relationSchemas'
13-
import type { CompleteTraceDefinition, MapSchemaToTypes } from './types'
13+
import type {
14+
CompleteTraceDefinition,
15+
DraftTraceContext,
16+
MapSchemaToTypes,
17+
} from './types'
1418

1519
const mockRelations: MapSchemaToTypes<
1620
TicketIdRelationSchemasFixture['ticket']
@@ -74,10 +78,7 @@ const mockContext = {
7478
epoch: Date.now(),
7579
},
7680
variant: 'origin',
77-
} satisfies ActiveTraceInput<
78-
TicketIdRelationSchemasFixture['ticket'],
79-
'origin'
80-
>,
81+
},
8182
definition: {
8283
name: 'test',
8384
type: 'operation',
@@ -89,12 +90,13 @@ const mockContext = {
8990
variants: {
9091
origin: { timeout: 10_000 },
9192
},
92-
} satisfies CompleteTraceDefinition<
93-
'ticket',
94-
TicketIdRelationSchemasFixture,
95-
'origin'
96-
>,
97-
} as const
93+
},
94+
recordedItemsByLabel: {},
95+
} as const satisfies DraftTraceContext<
96+
'ticket',
97+
TicketIdRelationSchemasFixture,
98+
'origin'
99+
>
98100

99101
type MockOrigin = (typeof mockContext)['input']['variant']
100102

@@ -447,6 +449,40 @@ describe('matchSpan', () => {
447449
})
448450
})
449451

452+
describe('fn', () => {
453+
it('should return true when the custom function matches', () => {
454+
const matcher = matchSpan.fromDefinition<
455+
'ticket',
456+
TicketIdRelationSchemasFixture,
457+
MockOrigin
458+
>({
459+
fn: ({ span }) => span.name.startsWith('test'),
460+
})
461+
462+
const mockSpanAndAnnotation = {
463+
span: mockEntryBase,
464+
annotation: mockAnnotation,
465+
}
466+
expect(matcher(mockSpanAndAnnotation, mockContext)).toBe(true)
467+
})
468+
469+
it('should return false when the custom function does not match', () => {
470+
const matcher = matchSpan.fromDefinition<
471+
'ticket',
472+
TicketIdRelationSchemasFixture,
473+
MockOrigin
474+
>({
475+
fn: ({ span }) => span.name === 'nonMatchingEntry',
476+
})
477+
478+
const mockSpanAndAnnotation = {
479+
span: mockEntryBase,
480+
annotation: mockAnnotation,
481+
}
482+
expect(matcher(mockSpanAndAnnotation, mockContext)).toBe(false)
483+
})
484+
})
485+
450486
describe('fromDefinition', () => {
451487
it('should correctly handle standard definition objects', () => {
452488
const matcher = matchSpan.fromDefinition<

src/v3/matchSpan.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export type NameMatcher<RelationSchemaT> =
3838
export interface SpanMatchDefinitionCombinator<
3939
SelectedRelationNameT extends keyof RelationSchemasT,
4040
RelationSchemasT,
41+
VariantsT extends string,
4142
> {
4243
name?: NameMatcher<RelationSchemasT[SelectedRelationNameT]>
4344
performanceEntryName?: NameMatcher<RelationSchemasT[SelectedRelationNameT]>
@@ -50,15 +51,25 @@ export interface SpanMatchDefinitionCombinator<
5051
occurrence?: number | ((occurrence: number) => boolean)
5152
isIdle?: boolean
5253
label?: string
54+
fn?: SpanMatcherFn<SelectedRelationNameT, RelationSchemasT, VariantsT>
5355
}
5456

5557
export type SpanMatchDefinition<
5658
SelectedRelationNameT extends keyof RelationSchemasT,
5759
RelationSchemasT,
60+
VariantsT extends string,
5861
> =
59-
| SpanMatchDefinitionCombinator<SelectedRelationNameT, RelationSchemasT>
62+
| SpanMatchDefinitionCombinator<
63+
SelectedRelationNameT,
64+
RelationSchemasT,
65+
VariantsT
66+
>
6067
| {
61-
oneOf: SpanMatchDefinition<SelectedRelationNameT, RelationSchemasT>[]
68+
oneOf: SpanMatchDefinition<
69+
SelectedRelationNameT,
70+
RelationSchemasT,
71+
VariantsT
72+
>[]
6273
}
6374

6475
export type SpanMatch<
@@ -67,7 +78,7 @@ export type SpanMatch<
6778
VariantsT extends string,
6879
> =
6980
| SpanMatcherFn<SelectedRelationNameT, RelationSchemasT, VariantsT>
70-
| SpanMatchDefinition<SelectedRelationNameT, RelationSchemasT>
81+
| SpanMatchDefinition<SelectedRelationNameT, RelationSchemasT, VariantsT>
7182

7283
/**
7384
* The common name of the span to match. Can be a string, RegExp, or function.
@@ -328,7 +339,11 @@ export function fromDefinition<
328339
const RelationSchemasT,
329340
const VariantsT extends string,
330341
>(
331-
definition: SpanMatchDefinition<SelectedRelationNameT, RelationSchemasT>,
342+
definition: SpanMatchDefinition<
343+
SelectedRelationNameT,
344+
RelationSchemasT,
345+
VariantsT
346+
>,
332347
): SpanMatcherFn<SelectedRelationNameT, RelationSchemasT, VariantsT> {
333348
// Check if definition has oneOf property
334349
if ('oneOf' in definition) {
@@ -372,10 +387,12 @@ export function fromDefinition<
372387
if (definition.isIdle) {
373388
matchers.push(whenIdle(definition.isIdle))
374389
}
375-
376390
if (definition.label) {
377391
matchers.push(withLabel(definition.label))
378392
}
393+
if (definition.fn) {
394+
matchers.push(definition.fn)
395+
}
379396

380397
return withAllConditions(...matchers)
381398
}

src/v3/recordingComputeUtils.ts

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ export function getComputedValues<
3939
RelationSchemasT,
4040
const VariantsT extends string,
4141
>({
42-
definition: traceDefinition,
4342
recordedItems,
44-
input,
43+
...context
4544
}: ComputeRecordingData<
4645
SelectedRelationNameT,
4746
RelationSchemasT,
@@ -52,10 +51,10 @@ export function getComputedValues<
5251
RelationSchemasT
5352
>['computedValues'] = {}
5453

55-
for (const [name, definition] of Object.entries(
56-
traceDefinition.computedValueDefinitions,
54+
for (const [name, computedValueDefinition] of Object.entries(
55+
context.definition.computedValueDefinitions,
5756
)) {
58-
const { matches, computeValueFromMatches } = definition
57+
const { matches, computeValueFromMatches } = computedValueDefinition
5958

6059
// Initialize arrays to hold matches for each matcher
6160
const matchingEntriesByMatcher: SpanAndAnnotation<RelationSchemasT>[][] =
@@ -64,7 +63,7 @@ export function getComputedValues<
6463
// Single pass through recordedItems
6564
for (const item of recordedItems) {
6665
matches.forEach((doesSpanMatch, index) => {
67-
if (doesSpanMatch(item, { input, definition: traceDefinition })) {
66+
if (doesSpanMatch(item, context)) {
6867
matchingEntriesByMatcher[index]!.push(item)
6968
}
7069
})
@@ -91,9 +90,8 @@ export function getComputedSpans<
9190
RelationSchemasT,
9291
const VariantsT extends string,
9392
>({
94-
definition: traceDefinition,
9593
recordedItems,
96-
input,
94+
...context
9795
}: ComputeRecordingData<
9896
SelectedRelationNameT,
9997
RelationSchemasT,
@@ -105,24 +103,21 @@ export function getComputedSpans<
105103
RelationSchemasT
106104
>['computedSpans'] = {}
107105

108-
for (const [name, definition] of Object.entries(
109-
traceDefinition.computedSpanDefinitions,
106+
for (const [name, computedSpanDefinition] of Object.entries(
107+
context.definition.computedSpanDefinitions,
110108
)) {
111-
const { startSpan: startSpanMatcher, endSpan } = definition
109+
const { startSpan: startSpanMatcher, endSpan } = computedSpanDefinition
112110

113111
const matchingStartEntry =
114112
typeof startSpanMatcher === 'function'
115113
? recordedItems.find((spanAndAnnotation) =>
116-
startSpanMatcher(spanAndAnnotation, {
117-
input,
118-
definition: traceDefinition,
119-
}),
114+
startSpanMatcher(spanAndAnnotation, context),
120115
)
121116
: startSpanMatcher
122117

123118
const matchingStartTime =
124119
matchingStartEntry === 'operation-start'
125-
? input.startTime.now
120+
? context.input.startTime.now
126121
: matchingStartEntry?.span.startTime.now
127122

128123
const endSpanMatcher =
@@ -132,13 +127,8 @@ export function getComputedSpans<
132127
? markedInteractive
133128
: endSpan
134129

135-
const matchingEndEntry = findLast(
136-
recordedItems,
137-
(spanAndAnnotation) =>
138-
endSpanMatcher(spanAndAnnotation, {
139-
input,
140-
definition: traceDefinition,
141-
})!,
130+
const matchingEndEntry = findLast(recordedItems, (spanAndAnnotation) =>
131+
endSpanMatcher(spanAndAnnotation, context),
142132
)
143133

144134
const matchingEndTime = matchingEndEntry
@@ -160,7 +150,7 @@ export function getComputedSpans<
160150
// -----E------S (computed val is negative)
161151
// this way the `endOffset` can be derived as follows:
162152
// endOffset = computedSpan.startOffset + computedSpan.duration
163-
startOffset: matchingStartTime - input.startTime.now,
153+
startOffset: matchingStartTime - context.input.startTime.now,
164154
}
165155
}
166156
}

src/v3/types.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -567,12 +567,7 @@ export interface DraftTraceContext<
567567
SelectedRelationNameT extends keyof RelationSchemasT,
568568
RelationSchemasT,
569569
VariantsT extends string,
570-
> {
571-
readonly definition: CompleteTraceDefinition<
572-
SelectedRelationNameT,
573-
RelationSchemasT,
574-
VariantsT
575-
>
570+
> extends TraceContext<SelectedRelationNameT, RelationSchemasT, VariantsT> {
576571
readonly input: DraftTraceInput<
577572
RelationSchemasT[SelectedRelationNameT],
578573
VariantsT

0 commit comments

Comments
 (0)