Skip to content

Commit

Permalink
feat: allow 'SpanMatchDefinition' in computed spans/values
Browse files Browse the repository at this point in the history
  • Loading branch information
niieani committed Nov 25, 2024
1 parent ce05c42 commit ea7e568
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 38 deletions.
34 changes: 34 additions & 0 deletions src/v3/ensureMatcherFn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import {
type SpanMatch,
type SpanMatchDefinition,
type SpanMatcherFn,
fromDefinition,
} from './matchSpan'
import type { ScopeBase } from './types'
import type { ArrayWithAtLeastOneElement } from './typeUtils'

export function ensureMatcherFn<
ScopeT extends ScopeBase,
MatcherInputT extends
| SpanMatcherFn<ScopeT>
| SpanMatchDefinition<ScopeT>
| string,
>(
matcherFnOrDefinition: MatcherInputT,
): MatcherInputT extends string ? MatcherInputT : SpanMatcherFn<ScopeT> {
return (
typeof matcherFnOrDefinition === 'function' ||
typeof matcherFnOrDefinition === 'string'
? matcherFnOrDefinition
: fromDefinition(matcherFnOrDefinition)
) as MatcherInputT extends string ? MatcherInputT : SpanMatcherFn<ScopeT>
}
export function convertMatchersToFns<ScopeT extends ScopeBase>(
matchers: SpanMatch<ScopeT>[] | undefined,
): ArrayWithAtLeastOneElement<SpanMatcherFn<ScopeT>> | undefined {
return matchers && matchers.length > 0
? (matchers.map((m) => ensureMatcherFn(m)) as ArrayWithAtLeastOneElement<
SpanMatcherFn<ScopeT>
>)
: undefined
}
53 changes: 19 additions & 34 deletions src/v3/traceManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ActiveTrace } from './ActiveTrace'
import { convertMatchersToFns, ensureMatcherFn } from './ensureMatcherFn'
import { ensureTimestamp } from './ensureTimestamp'
import { type SpanMatcherFn, fromDefinition } from './matchSpan'
import { type SpanMatcherFn } from './matchSpan'
import type { SpanAnnotationRecord } from './spanAnnotationTypes'
import type { Span, StartTraceConfig } from './spanTypes'
import type { TraceRecording } from './traceRecordingTypes'
Expand All @@ -14,7 +15,6 @@ import type {
TraceManagerConfig,
Tracer,
} from './types'
import type { ArrayWithAtLeastOneElement } from './typeUtils'

/**
* Class representing the centralized trace performance manager.
Expand All @@ -35,38 +35,21 @@ export class TraceManager<ScopeT extends ScopeBase> {
ScopeT,
SpanMatcherFn<ScopeT>[]
>[] = []
const requiredToEnd =
traceDefinition.requiredToEnd && traceDefinition.requiredToEnd.length > 0
? (traceDefinition.requiredToEnd.map((matcherFnOrDefinition) =>
typeof matcherFnOrDefinition === 'function'
? matcherFnOrDefinition
: fromDefinition(matcherFnOrDefinition),
) as ArrayWithAtLeastOneElement<SpanMatcherFn<ScopeT>>)
: undefined

const requiredToEnd = convertMatchersToFns<ScopeT>(
traceDefinition.requiredToEnd,
)

if (!requiredToEnd) {
throw new Error(
'requiredToEnd must be defined, as a trace will never end otherwise',
)
}

const debounceOn =
traceDefinition.debounceOn && traceDefinition.debounceOn.length > 0
? (traceDefinition.debounceOn.map((matcherFnOrDefinition) =>
typeof matcherFnOrDefinition === 'function'
? matcherFnOrDefinition
: fromDefinition(matcherFnOrDefinition),
) as ArrayWithAtLeastOneElement<SpanMatcherFn<ScopeT>>)
: undefined

const interruptOn =
traceDefinition.interruptOn && traceDefinition.interruptOn.length > 0
? (traceDefinition.interruptOn.map((matcherFnOrDefinition) =>
typeof matcherFnOrDefinition === 'function'
? matcherFnOrDefinition
: fromDefinition(matcherFnOrDefinition),
) as ArrayWithAtLeastOneElement<SpanMatcherFn<ScopeT>>)
: undefined
const debounceOn = convertMatchersToFns<ScopeT>(traceDefinition.debounceOn)
const interruptOn = convertMatchersToFns<ScopeT>(
traceDefinition.interruptOn,
)

const completeTraceDefinition: CompleteTraceDefinition<ScopeT> = {
...traceDefinition,
Expand All @@ -79,15 +62,17 @@ export class TraceManager<ScopeT extends ScopeBase> {

return {
defineComputedSpan: (definition) => {
computedSpanDefinitions.push(definition)
computedSpanDefinitions.push({
...definition,
startSpan: ensureMatcherFn(definition.startSpan),
endSpan: ensureMatcherFn(definition.endSpan),
})
},
defineComputedValue: (definition) => {
computedValueDefinitions.push(
definition as ComputedValueDefinition<
ScopeT,
SpanMatcherFn<ScopeT>[]
>,
)
computedValueDefinitions.push({
...definition,
matches: definition.matches.map((m) => ensureMatcherFn(m)),
} as ComputedValueDefinition<ScopeT, SpanMatcherFn<ScopeT>[]>)
},
start: (input) => this.startTrace(completeTraceDefinition, input),
}
Expand Down
40 changes: 36 additions & 4 deletions src/v3/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { CPUIdleProcessorOptions } from './firstCPUIdle'
import type { SpanMatch, SpanMatcherFn } from './matchSpan'
import type { SpanMatch, SpanMatchDefinition, SpanMatcherFn } from './matchSpan'
import type { SpanAndAnnotation } from './spanAnnotationTypes'
import type { SpanStatus, SpanType, StartTraceConfig } from './spanTypes'
import type { TraceRecording } from './traceRecordingTypes'
Expand Down Expand Up @@ -53,11 +53,13 @@ export interface Tracer<ScopeT extends ScopeBase> {
start: (input: StartTraceConfig<ScopeT>) => string

defineComputedSpan: (
computedSpanDefinition: ComputedSpanDefinition<ScopeT>,
computedSpanDefinition: ComputedSpanDefinitionInput<ScopeT>,
) => void

defineComputedValue: <MatchersT extends SpanMatcherFn<ScopeT>[]>(
computedValueDefinition: ComputedValueDefinition<ScopeT, MatchersT>,
defineComputedValue: <
MatchersT extends (SpanMatcherFn<ScopeT> | SpanMatchDefinition<ScopeT>)[],
>(
computedValueDefinition: ComputedValueDefinitionInput<ScopeT, MatchersT>,
) => void
}

Expand Down Expand Up @@ -147,3 +149,33 @@ export interface ComputedValueDefinition<
...matches: MapTuple<MatchersT, SpanAndAnnotation<ScopeT>[]>
) => number | string | boolean
}

/**
* Definition of custom spans input
*/
export interface ComputedSpanDefinitionInput<ScopeT extends ScopeBase> {
name: string
startSpan:
| SpanMatcherFn<ScopeT>
| SpanMatchDefinition<ScopeT>
| 'operation-start'
endSpan:
| SpanMatcherFn<ScopeT>
| SpanMatchDefinition<ScopeT>
| 'operation-end'
| 'interactive'
}

/**
* Definition of custom values input
*/
export interface ComputedValueDefinitionInput<
ScopeT extends ScopeBase,
MatchersT extends (SpanMatcherFn<ScopeT> | SpanMatchDefinition<ScopeT>)[],
> {
name: string
matches: [...MatchersT]
computeValueFromMatches: (
...matches: MapTuple<MatchersT, SpanAndAnnotation<ScopeT>[]>
) => number | string | boolean
}

0 comments on commit ea7e568

Please sign in to comment.