UNPKG

@zendesk/retrace

Version:

define and capture Product Operation Traces along with computed metrics with an optional friendly React beacon API

121 lines 6.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ensureSpanHasInheritedAttributes = ensureSpanHasInheritedAttributes; exports.createParentSpanResolver = createParentSpanResolver; const constants_1 = require("./constants"); const matchSpan_1 = require("./matchSpan"); const spanTypes_1 = require("./spanTypes"); const TickParentResolver_1 = require("./TickParentResolver"); function ensureSpanHasInheritedAttributes(span, heritableSpanAttributes) { let allRequestedAttributesInheritedFromLineage = true; for (const [key, value] of Object.entries(span.attributes)) { const inheritanceType = value === constants_1.INHERIT_FROM_PARENT ? 'span-request' : heritableSpanAttributes?.includes(key) ? 'always-requested' : undefined; if (!inheritanceType) { // eslint-disable-next-line no-continue continue; } allRequestedAttributesInheritedFromLineage = false; let ancestorSpan = span; const lineageRequiringAttributes = []; // eslint-disable-next-line no-cond-assign while ((ancestorSpan = ancestorSpan[spanTypes_1.PARENT_SPAN])) { if (ancestorSpan.attributes[key] === constants_1.INHERIT_FROM_PARENT || inheritanceType === 'always-requested') { // parent also requests inheritance, so we need to keep going lineageRequiringAttributes.push(ancestorSpan); } else if (ancestorSpan.attributes[key] !== undefined) { // found an ancestor with the attribute, let's assign it // eslint-disable-next-line no-param-reassign span.attributes[key] = ancestorSpan.attributes[key]; // let's also assign it to all the intermediary ancestors that requested inheritance // as a performance optimization (less work to do later) for (const ancestor of lineageRequiringAttributes) { ancestor.attributes[key] = ancestorSpan.attributes[key]; } allRequestedAttributesInheritedFromLineage = true; break; } } } return allRequestedAttributesInheritedFromLineage; } function createParentSpanResolver(span, parentSpanMatcher, heritableSpanAttributes) { let shouldAttemptToResolveParentAgain = true; let inheritedRequestedAttributes = false; return (context, recursive) => { const getParentSpan = () => { if (span[spanTypes_1.PARENT_SPAN] || !parentSpanMatcher) { // short-circuit if we have the parent span, or if there is nowhere to search for it return span[spanTypes_1.PARENT_SPAN]; } if (!shouldAttemptToResolveParentAgain) { return undefined; } const tickSource = parentSpanMatcher.search === 'span-created-tick' || !context.traceContext ? context.thisSpanAndAnnotation.span[TickParentResolver_1.TICK_META] : parentSpanMatcher.search === 'span-ended-tick' ? context.thisSpanAndAnnotation.span[TickParentResolver_1.TICK_META_END] : undefined; if (tickSource?.spansInCurrentTick.tickCompleted) { // do not attempt to resolve parent span again - if we haven't found in this iteration, // we will not find it, because now more data will be added to the tick shouldAttemptToResolveParentAgain = false; } const spanAndAnnotations = tickSource ? tickSource?.spansInCurrentTick.map((sp) => context.traceContext?.recordedItems.get(sp.id) ?? { span: sp }) ?? [] : // note: parentSpanMatcher.search === 'entire-recording' only works if the traceContext is available [...context.traceContext.recordedItems.values()]; const parentSpanMatchFn = typeof parentSpanMatcher.match === 'object' ? (0, matchSpan_1.fromDefinition)(parentSpanMatcher.match) : parentSpanMatcher.match; // memoize the matcher function to avoid re-creating it on every call // eslint-disable-next-line no-param-reassign parentSpanMatcher.match = parentSpanMatchFn; const thisSpanIndex = parentSpanMatcher.search === 'entire-recording' ? spanAndAnnotations.findIndex((spanAndAnnotation) => spanAndAnnotation.span.id === span.id) : tickSource?.thisSpanInCurrentTickIndex ?? -1; if (thisSpanIndex === -1) { // invalid return undefined; } const found = (0, matchSpan_1.findMatchingSpan)(parentSpanMatchFn, spanAndAnnotations, context.traceContext, { ...(parentSpanMatcher.searchDirection === 'after-self' && { nthMatch: 0, lowestIndexToConsider: thisSpanIndex + 1, }), ...(parentSpanMatcher.searchDirection === 'before-self' && { nthMatch: -1, highestIndexToConsider: thisSpanIndex - 1, }), }); if (found) { // cache the found parent span on the span itself // so we don't have to search for it again // eslint-disable-next-line no-param-reassign span[spanTypes_1.PARENT_SPAN] = found.span; return found.span; } return undefined; }; const parentSpan = getParentSpan(); if (parentSpan) { if (recursive) { parentSpan.getParentSpan?.({ traceContext: context.traceContext, thisSpanAndAnnotation: context.traceContext?.recordedItems.get(parentSpan.id) ?? { span: parentSpan }, }, recursive); } if (!inheritedRequestedAttributes) { inheritedRequestedAttributes = ensureSpanHasInheritedAttributes(span, heritableSpanAttributes); } } return parentSpan; }; } //# sourceMappingURL=createParentSpanResolver.js.map