Chore: Refactor span.js, trace.js & trace.fixture.js to TypeScript (#58006)

This commit is contained in:
Hamas Shafiq 2022-11-30 18:09:08 +00:00 committed by GitHub
parent ce630b2dc5
commit 5073839f8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 175 additions and 139 deletions

View File

@ -12,11 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { TraceResponse } from 'src/types';
import { TraceSpan, TraceSpanData } from 'src/types/trace';
import traceGenerator from '../demo/trace-generators';
import * as spanSelectors from './span';
const generatedTrace = traceGenerator.trace({ numberOfSpans: 45 });
const generatedTrace: TraceResponse = traceGenerator.trace({ numberOfSpans: 45 });
it('getSpanId() should return the name of the span', () => {
const span = generatedTrace.spans[0];
@ -46,8 +49,10 @@ it('getSpanReferences() should return the span reference array', () => {
expect(spanSelectors.getSpanReferences(generatedTrace.spans[0])).toEqual(generatedTrace.spans[0].references);
});
it('getSpanReferences() should return empty array for null references', () => {
expect(spanSelectors.getSpanReferences({ references: null })).toEqual([]);
it('getSpanReferences() should return an empty array when references is undefined', () => {
const span = generatedTrace.spans[0];
span.references = undefined;
expect(spanSelectors.getSpanReferences(span)).toEqual([]);
});
it('getSpanReferenceByType() should return the span reference requested', () => {
@ -55,7 +60,7 @@ it('getSpanReferenceByType() should return the span reference requested', () =>
spanSelectors.getSpanReferenceByType({
span: generatedTrace.spans[1],
type: 'CHILD_OF',
}).refType
})?.refType
).toBe('CHILD_OF');
});
@ -70,7 +75,7 @@ it('getSpanReferenceByType() should return undefined if one does not exist', ()
it('getSpanParentId() should return the spanID of the parent span', () => {
expect(spanSelectors.getSpanParentId(generatedTrace.spans[1])).toBe(
generatedTrace.spans[1].references.find(({ refType }) => refType === 'CHILD_OF').spanID
generatedTrace.spans[1].references!.find(({ refType }: { refType: string }) => refType === 'CHILD_OF')!.spanID
);
});
@ -85,16 +90,17 @@ it('getSpanProcessId() should return the processID of the span', () => {
});
it('getSpanProcess() should return the process of the span', () => {
const serviceName = 'bagel';
const span = {
...generatedTrace.spans[0],
process: {},
};
process: { serviceName },
} as TraceSpan;
expect(spanSelectors.getSpanProcess(span)).toBe(span.process);
});
it('getSpanProcess() should throw if no process exists', () => {
expect(() => spanSelectors.getSpanProcess(generatedTrace.spans[0])).toThrow();
expect(() => spanSelectors.getSpanProcess(generatedTrace.spans[0] as TraceSpan)).toThrow();
});
it('getSpanServiceName() should return the service name of the span', () => {
@ -102,7 +108,7 @@ it('getSpanServiceName() should return the service name of the span', () => {
const span = {
...generatedTrace.spans[0],
process: { serviceName },
};
} as TraceSpan;
expect(spanSelectors.getSpanServiceName(span)).toBe(serviceName);
});
@ -112,17 +118,17 @@ it('filterSpansForTimestamps() should return a filtered list of spans between th
const spans = [
{
startTime: now - 1000,
id: 'start-time-1',
spanID: 'start-time-1',
},
{
startTime: now,
id: 'start-time-2',
spanID: 'start-time-2',
},
{
startTime: now + 1000,
id: 'start-time-3',
spanID: 'start-time-3',
},
];
] as TraceSpanData[];
expect(
spanSelectors.filterSpansForTimestamps({
@ -164,23 +170,23 @@ it('filterSpansForText() should return a filtered list of spans between the time
process: {
serviceName: 'alpha',
},
id: 'start-time-1',
spanID: 'start-time-1',
},
{
operationName: 'GET /another',
process: {
serviceName: 'beta',
},
id: 'start-time-1',
spanID: 'start-time-1',
},
{
operationName: 'POST /mything',
process: {
serviceName: 'alpha',
},
id: 'start-time-1',
spanID: 'start-time-1',
},
];
] as TraceSpan[];
expect(
spanSelectors.filterSpansForText({

View File

@ -15,25 +15,27 @@
import fuzzy from 'fuzzy';
import { createSelector } from 'reselect';
import { TraceSpan, TraceSpanData, TraceSpanReference } from '../types/trace';
import { getProcessServiceName } from './process';
export const getSpanId = (span) => span.spanID;
export const getSpanName = (span) => span.operationName;
export const getSpanDuration = (span) => span.duration;
export const getSpanTimestamp = (span) => span.startTime;
export const getSpanProcessId = (span) => span.processID;
export const getSpanReferences = (span) => span.references || [];
export const getSpanId = (span: TraceSpanData) => span.spanID;
export const getSpanName = (span: TraceSpanData) => span.operationName;
export const getSpanDuration = (span: TraceSpanData) => span.duration;
export const getSpanTimestamp = (span: TraceSpanData) => span.startTime;
export const getSpanProcessId = (span: TraceSpanData) => span.processID;
export const getSpanReferences = (span: TraceSpanData) => span.references || [];
export const getSpanReferenceByType = createSelector(
createSelector(({ span }) => span, getSpanReferences),
({ type }) => type,
(references, type) => references.find((ref) => ref.refType === type)
createSelector(({ span }: { span: TraceSpanData }) => span, getSpanReferences),
({ type }: { type: string }) => type,
(references, type) => references.find((ref: TraceSpanReference) => ref.refType === type)
);
export const getSpanParentId = createSelector(
(span) => getSpanReferenceByType({ span, type: 'CHILD_OF' }),
(span: TraceSpanData) => getSpanReferenceByType({ span, type: 'CHILD_OF' }),
(childOfRef) => (childOfRef ? childOfRef.spanID : null)
);
export const getSpanProcess = (span) => {
export const getSpanProcess = (span: TraceSpan) => {
if (!span.process) {
throw new Error(
`
@ -42,23 +44,22 @@ export const getSpanProcess = (span) => {
`
);
}
return span.process;
};
export const getSpanServiceName = createSelector(getSpanProcess, getProcessServiceName);
export const filterSpansForTimestamps = createSelector(
({ spans }) => spans,
({ leftBound }) => leftBound,
({ rightBound }) => rightBound,
({ spans }: { spans: TraceSpanData[] }) => spans,
({ leftBound }: { leftBound: number }) => leftBound,
({ rightBound }: { rightBound: number }) => rightBound,
(spans, leftBound, rightBound) =>
spans.filter((span) => getSpanTimestamp(span) >= leftBound && getSpanTimestamp(span) <= rightBound)
);
export const filterSpansForText = createSelector(
({ spans }) => spans,
({ text }) => text,
({ spans }: { spans: TraceSpan[] }) => spans,
({ text }: { text: string }) => text,
(spans, text) =>
fuzzy
.filter(text, spans, {
@ -67,7 +68,7 @@ export const filterSpansForText = createSelector(
.map(({ original }) => original)
);
const getTextFilterdSpansAsMap = createSelector(filterSpansForText, (matchingSpans) =>
const getTextFilteredSpansAsMap = createSelector(filterSpansForText, (matchingSpans) =>
matchingSpans.reduce(
(obj, span) => ({
...obj,
@ -77,11 +78,12 @@ const getTextFilterdSpansAsMap = createSelector(filterSpansForText, (matchingSpa
)
);
// TODO: delete this function as it is not used?
export const highlightSpansForTextFilter = createSelector(
({ spans }) => spans,
getTextFilterdSpansAsMap,
(spans, textFilteredSpansMap) =>
spans.map((span) => ({
({ spans }: { spans: TraceSpanData[] }) => spans,
getTextFilteredSpansAsMap,
(spans, textFilteredSpansMap: { [key: string]: TraceSpanData }) =>
spans.map((span: TraceSpanData) => ({
...span,
muted: !textFilteredSpansMap[getSpanId(span)],
}))

View File

@ -14,6 +14,16 @@
// See https://github.com/jaegertracing/jaeger-ui/issues/115 for details.
import { TraceSpanReference } from '../types/trace';
const references: TraceSpanReference[] = [
{
refType: 'FOLLOWS_FROM',
spanID: 'ea7cfaca83f0724b',
traceID: '2992f2a5b5d037a8aabffd08ef384237',
},
];
export const followsFromRef = {
processes: {
p1: {
@ -28,13 +38,7 @@ export const followsFromRef = {
logs: [],
operationName: 'thread',
processID: 'p1',
references: [
{
refType: 'FOLLOWS_FROM',
spanID: 'ea7cfaca83f0724b',
traceID: '2992f2a5b5d037a8aabffd08ef384237',
},
],
references: references,
spanID: '1bdf4201221bb2ac',
startTime: 1509533706521220,
tags: [],

View File

@ -13,8 +13,10 @@
// limitations under the License.
import { values as _values } from 'lodash';
import TreeNode from 'src/utils/TreeNode';
import traceGenerator from '../demo/trace-generators';
import { TraceResponse, TraceSpan, TraceSpanData } from '../types/trace';
import { numberSortComparator } from '../utils/sort';
import {
@ -29,7 +31,7 @@ import {
import * as traceSelectors from './trace';
import { followsFromRef } from './trace.fixture';
const generatedTrace = traceGenerator.trace({ numberOfSpans: 45 });
const generatedTrace: TraceResponse = traceGenerator.trace({ numberOfSpans: 45 });
it('getTraceId() should return the traceID', () => {
expect(traceSelectors.getTraceId(generatedTrace)).toBe(generatedTrace.traceID);
@ -39,7 +41,7 @@ it('hydrateSpansWithProcesses() should return the trace with processes on each s
const hydratedTrace = traceSelectors.hydrateSpansWithProcesses(generatedTrace);
hydratedTrace.spans.forEach((span) =>
expect(getSpanProcess(span)).toBe(generatedTrace.processes[getSpanProcessId(span)])
expect(getSpanProcess(span as TraceSpan)).toBe(generatedTrace.processes[getSpanProcessId(span)])
);
});
@ -55,7 +57,7 @@ describe('getTraceSpanIdsAsTree()', () => {
const tree = traceSelectors.getTraceSpanIdsAsTree(generatedTrace);
const spanMap = traceSelectors.getTraceSpansAsMap(generatedTrace);
tree.walk((value, node) => {
tree.walk((value: string | number | undefined, node: TreeNode) => {
const expectedParentValue = value === traceSelectors.TREE_ROOT_ID ? null : value;
node.children.forEach((childNode) => {
expect(getSpanParentId(spanMap.get(childNode.value))).toBe(expectedParentValue);
@ -98,7 +100,7 @@ it('getParentSpan() should return the first span if there are multiple parents',
references: [],
},
],
};
} as unknown as TraceResponse;
expect(traceSelectors.getParentSpan(trace)).toBe(firstSpan);
});
@ -131,14 +133,14 @@ it('getTraceDepth() should determine the total depth of the trace tree', () => {
});
it('getSpanDepthForTrace() should determine the depth of a given span in the parent', () => {
function testDepthCalc(span) {
function testDepthCalc(span: TraceSpanData) {
let depth = 2;
let currentId = getSpanParentId(span);
const findCurrentSpanById = (item) => getSpanId(item) === currentId;
const findCurrentSpanById = (item: TraceSpanData) => getSpanId(item) === currentId;
while (currentId !== getSpanId(generatedTrace.spans[0])) {
depth++;
currentId = getSpanParentId(generatedTrace.spans.find(findCurrentSpanById));
currentId = getSpanParentId(generatedTrace.spans.find(findCurrentSpanById)!);
}
// console.log('hypothetical depth', depth);
@ -183,10 +185,13 @@ it('formatDurationForUnit() should use the formatters to return the proper value
});
it('formatDurationForTrace() should return a ms value for traces shorter than a second', () => {
const firstSpan = generatedTrace.spans[0];
firstSpan.duration = 600000;
expect(
traceSelectors.formatDurationForTrace({
trace: {
spans: [{ duration: 600000 }],
...generatedTrace,
spans: [firstSpan],
},
duration: 302000,
})
@ -266,14 +271,17 @@ it('getTreeSizeForTraceSpan() should return the size for a child span', () => {
trace: generatedTrace,
span: generatedTrace.spans[1],
})
).toBe(traceSelectors.getTraceSpanIdsAsTree(generatedTrace).find(generatedTrace.spans[1].spanID).size - 1);
).toBe(traceSelectors.getTraceSpanIdsAsTree(generatedTrace).find(generatedTrace.spans[1].spanID)!.size - 1);
});
it('getTreeSizeForTraceSpan() should return -1 for an absent span', () => {
const absentSpan = generatedTrace.spans[0];
absentSpan.spanID = 'whatever';
expect(
traceSelectors.getTreeSizeForTraceSpan({
trace: generatedTrace,
span: { spanID: 'whatever' },
span: absentSpan,
})
).toBe(-1);
});
@ -287,7 +295,7 @@ it('getTraceName() should return the trace name based on the parentSpan', () =>
it('omitCollapsedSpans() should filter out collapsed spans', () => {
const span = generatedTrace.spans[1];
const size = traceSelectors.getTraceSpanIdsAsTree(generatedTrace).find(span.spanID).size - 1;
const size = traceSelectors.getTraceSpanIdsAsTree(generatedTrace).find(span.spanID)!.size - 1;
expect(
traceSelectors.omitCollapsedSpans({
@ -299,15 +307,13 @@ it('omitCollapsedSpans() should filter out collapsed spans', () => {
});
it('getTicksForTrace() should return a list of ticks given interval parameters', () => {
const trace = generatedTrace;
const timestamp = new Date().getTime() * 1000;
const trace = {
spans: [
{
startTime: timestamp,
duration: 3000000,
},
],
};
trace.spans.forEach((span) => {
span.duration = 3000000;
span.startTime = timestamp;
});
expect(
traceSelectors.getTicksForTrace({
@ -325,14 +331,20 @@ it('getTicksForTrace() should return a list of ticks given interval parameters',
it('getTicksForTrace() should use defaults', () => {
const timestamp = new Date().getTime() * 1000;
const trace = {
spans: [
{
startTime: timestamp,
duration: 4000000,
},
],
};
const trace = traceGenerator.trace({ numberOfSpans: 1 });
trace.spans = [
{
traceID: '5031233a-d0b5-5d41-9b4b-4c072bcf5020',
processID: 'b5f4e0ff-7318-5017-a3f3-9c7b423a82aa',
spanID: 'e871771f-f1b4-54af-9e9d-826259c2915e',
flags: 0,
logs: [],
operationName: 'POST',
startTime: timestamp,
duration: 4000000,
},
];
expect(traceSelectors.getTicksForTrace({ trace })).toEqual([
{ timestamp, width: traceSelectors.DEFAULT_TICK_WIDTH },

View File

@ -14,6 +14,7 @@
import { createSelector, createStructuredSelector } from 'reselect';
import { Trace, TraceData, TraceProcess, TraceResponse, TraceSpan, TraceSpanData } from '../types/trace';
import TreeNode from '../utils/TreeNode';
import { formatMillisecondTime, formatSecondTime, ONE_SECOND } from '../utils/date';
import { numberSortComparator } from '../utils/sort';
@ -28,15 +29,13 @@ import {
getSpanProcessId,
} from './span';
export const getTraceId = (trace) => trace.traceID;
export const getTraceSpans = (trace) => trace.spans;
const getTraceProcesses = (trace) => trace.processes;
export const getTraceId = (trace: TraceData) => trace.traceID;
export const getTraceSpans = (trace: TraceResponse) => trace.spans;
const getTraceProcesses = (trace: TraceData | Trace) => trace.processes;
const getSpanWithProcess = createSelector(
(state) => state.span,
(state) => state.processes,
(state: { span: TraceSpanData; processes: Record<string, TraceProcess> }) => state.span,
(state: { span: TraceSpanData; processes: Record<string, TraceProcess> }) => state.processes,
(span, processes) => ({
...span,
process: processes[getSpanProcessId(span)],
@ -44,7 +43,7 @@ const getSpanWithProcess = createSelector(
);
export const getTraceSpansAsMap = createSelector(getTraceSpans, (spans) =>
spans.reduce((map, span) => map.set(getSpanId(span), span), new Map())
spans.reduce((map, span: TraceSpanData) => map.set(getSpanId(span), span), new Map())
);
export const TREE_ROOT_ID = '__root__';
@ -63,17 +62,17 @@ export const TREE_ROOT_ID = '__root__';
* @return {TreeNode} A tree of spanIDs derived from the relationships
* between spans in the trace.
*/
export function getTraceSpanIdsAsTree(trace) {
const nodesById = new Map(trace.spans.map((span) => [span.spanID, new TreeNode(span.spanID)]));
const spansById = new Map(trace.spans.map((span) => [span.spanID, span]));
export function getTraceSpanIdsAsTree(trace: TraceResponse) {
const nodesById = new Map(trace.spans.map((span: TraceSpanData) => [span.spanID, new TreeNode(span.spanID)]));
const spansById = new Map(trace.spans.map((span: TraceSpanData) => [span.spanID, span]));
const root = new TreeNode(TREE_ROOT_ID);
trace.spans.forEach((span) => {
const node = nodesById.get(span.spanID);
trace.spans.forEach((span: TraceSpanData) => {
const node = nodesById.get(span.spanID)!;
if (Array.isArray(span.references) && span.references.length) {
const { refType, spanID: parentID } = span.references[0];
if (refType === 'CHILD_OF' || refType === 'FOLLOWS_FROM') {
const parent = nodesById.get(parentID) || root;
parent.children.push(node);
parent.children?.push(node);
} else {
throw new Error(`Unrecognized ref type: ${refType}`);
}
@ -81,15 +80,15 @@ export function getTraceSpanIdsAsTree(trace) {
root.children.push(node);
}
});
const comparator = (nodeA, nodeB) => {
const a = spansById.get(nodeA.value);
const b = spansById.get(nodeB.value);
return +(a.startTime > b.startTime) || +(a.startTime === b.startTime) - 1;
const comparator = (nodeA: TreeNode | undefined, nodeB: TreeNode | undefined) => {
const a: TraceSpanData | undefined = nodeA?.value ? spansById.get(nodeA.value.toString()) : undefined;
const b: TraceSpanData | undefined = nodeB?.value ? spansById.get(nodeB.value.toString()) : undefined;
return +(a?.startTime! > b?.startTime!) || +(a?.startTime === b?.startTime) - 1;
};
trace.spans.forEach((span) => {
const node = nodesById.get(span.spanID);
if (node.children.length > 1) {
node.children.sort(comparator);
trace.spans.forEach((span: TraceSpanData) => {
const node: TreeNode | undefined = nodesById.get(span.spanID);
if (node!.children.length > 1) {
node?.children.sort(comparator);
}
});
root.children.sort(comparator);
@ -97,13 +96,13 @@ export function getTraceSpanIdsAsTree(trace) {
}
// attach "process" as an object to each span.
export const hydrateSpansWithProcesses = (trace) => {
export const hydrateSpansWithProcesses = (trace: TraceResponse) => {
const spans = getTraceSpans(trace);
const processes = getTraceProcesses(trace);
return {
...trace,
spans: spans.map((span) => getSpanWithProcess({ span, processes })),
spans: spans.map((span: TraceSpanData) => getSpanWithProcess({ span, processes })),
};
};
@ -111,25 +110,26 @@ export const getTraceSpanCount = createSelector(getTraceSpans, (spans) => spans.
export const getTraceTimestamp = createSelector(getTraceSpans, (spans) =>
spans.reduce(
(prevTimestamp, span) => (prevTimestamp ? Math.min(prevTimestamp, getSpanTimestamp(span)) : getSpanTimestamp(span)),
null
(prevTimestamp: number, span: TraceSpanData) =>
prevTimestamp ? Math.min(prevTimestamp, getSpanTimestamp(span)) : getSpanTimestamp(span),
0
)
);
export const getTraceDuration = createSelector(getTraceSpans, getTraceTimestamp, (spans, timestamp) =>
spans.reduce(
(prevDuration, span) =>
(prevDuration: number, span: TraceSpanData) =>
prevDuration
? Math.max(getSpanTimestamp(span) - timestamp + getSpanDuration(span), prevDuration)
? Math.max(getSpanTimestamp(span) - timestamp! + getSpanDuration(span), prevDuration)
: getSpanDuration(span),
null
0
)
);
export const getTraceEndTimestamp = createSelector(
getTraceTimestamp,
getTraceDuration,
(timestamp, duration) => timestamp + duration
(timestamp: number, duration: number) => timestamp! + duration
);
export const getParentSpan = createSelector(
@ -137,16 +137,18 @@ export const getParentSpan = createSelector(
getTraceSpansAsMap,
(tree, spanMap) =>
tree.children
.map((node) => spanMap.get(node.value))
.sort((spanA, spanB) => numberSortComparator(getSpanTimestamp(spanA), getSpanTimestamp(spanB)))[0]
.map((node: TreeNode) => spanMap.get(node.value))
.sort((spanA: TraceSpanData, spanB: TraceSpanData) =>
numberSortComparator(getSpanTimestamp(spanA), getSpanTimestamp(spanB))
)[0]
);
export const getTraceDepth = createSelector(getTraceSpanIdsAsTree, (spanTree) => spanTree.depth - 1);
export const getSpanDepthForTrace = createSelector(
createSelector((state) => state.trace, getTraceSpanIdsAsTree),
createSelector((state) => state.span, getSpanId),
(node, spanID) => node.getPath(spanID).length - 1
createSelector((state: { trace: TraceResponse }) => state.trace, getTraceSpanIdsAsTree),
createSelector((state: { span: TraceSpanData }) => state.span, getSpanId),
(node, spanID) => node.getPath(spanID)!.length - 1
);
export const getTraceServices = createSelector(getTraceProcesses, (processes) =>
@ -165,26 +167,34 @@ export const DURATION_FORMATTERS = {
s: formatSecondTime,
};
const getDurationFormatterForTrace = createSelector(getTraceDuration, (totalDuration) =>
const getDurationFormatterForTrace = createSelector(getTraceDuration, (totalDuration: number) =>
totalDuration >= ONE_SECOND ? DURATION_FORMATTERS.s : DURATION_FORMATTERS.ms
);
export const formatDurationForUnit = createSelector(
({ duration }) => duration,
({ unit }) => DURATION_FORMATTERS[unit],
({ duration }: { duration: number }) => duration,
({ unit }: { unit: 'ms' | 's' }) => DURATION_FORMATTERS[unit],
(duration, formatter) => formatter(duration)
);
export const formatDurationForTrace = createSelector(
({ duration }) => duration,
createSelector(({ trace }) => trace, getDurationFormatterForTrace),
({ duration }: { duration: number }) => duration,
createSelector(({ trace }: { trace: TraceResponse }) => trace, getDurationFormatterForTrace),
(duration, formatter) => formatter(duration)
);
export const getSortedSpans = createSelector(
({ trace }) => trace,
({ spans }) => spans,
({ sort }) => sort,
({ trace }: { trace: TraceResponse }) => trace,
({ spans }: { spans: TraceSpanData[] }) => spans,
({
sort,
}: {
sort: {
dir: number;
comparator: (itemA: number, itemB: number) => number;
selector: (itemA: TraceSpanData, itemB: TraceResponse) => number;
};
}) => sort,
(trace, spans, { dir, comparator, selector }) =>
[...spans].sort((spanA, spanB) => dir * comparator(selector(spanA, trace), selector(spanB, trace)))
);
@ -192,13 +202,13 @@ export const getSortedSpans = createSelector(
const getTraceSpansByHierarchyPosition = createSelector(getTraceSpanIdsAsTree, (tree) => {
const hierarchyPositionMap = new Map();
let i = 0;
tree.walk((spanID) => hierarchyPositionMap.set(spanID, i++));
tree.walk((spanID: string | number | undefined) => hierarchyPositionMap.set(spanID, i++));
return hierarchyPositionMap;
});
export const getTreeSizeForTraceSpan = createSelector(
createSelector((state) => state.trace, getTraceSpanIdsAsTree),
createSelector((state) => state.span, getSpanId),
createSelector((state: { trace: TraceResponse }) => state.trace, getTraceSpanIdsAsTree),
createSelector((state: { span: TraceSpanData }) => state.span, getSpanId),
(tree, spanID) => {
const node = tree.find(spanID);
if (!node) {
@ -209,8 +219,8 @@ export const getTreeSizeForTraceSpan = createSelector(
);
export const getSpanHierarchySortPositionForTrace = createSelector(
createSelector(({ trace }) => trace, getTraceSpansByHierarchyPosition),
({ span }) => span,
createSelector(({ trace }: { trace: Trace }) => trace, getTraceSpansByHierarchyPosition),
({ span }: { span: TraceSpan }) => span,
(hierarchyPositionMap, span) => hierarchyPositionMap.get(getSpanId(span))
);
@ -222,16 +232,16 @@ export const getTraceName = createSelector(
serviceName: getSpanServiceName,
})
),
({ name, serviceName }) => `${serviceName}: ${name}`
({ name, serviceName }: { name: string; serviceName: string }) => `${serviceName}: ${name}`
);
export const omitCollapsedSpans = createSelector(
({ spans }) => spans,
createSelector(({ trace }) => trace, getTraceSpanIdsAsTree),
({ collapsed }) => collapsed,
({ spans }: { spans: TraceSpanData[] }) => spans,
createSelector(({ trace }: { trace: TraceResponse }) => trace, getTraceSpanIdsAsTree),
({ collapsed }: { collapsed: string[] }) => collapsed,
(spans, tree, collapse) => {
const hiddenSpanIds = collapse.reduce((result, collapsedSpanId) => {
tree.find(collapsedSpanId).walk((id) => id !== collapsedSpanId && result.add(id));
tree.find(collapsedSpanId)!.walk((id: string | number | undefined) => id !== collapsedSpanId && result.add(id));
return result;
}, new Set());
@ -242,13 +252,13 @@ export const omitCollapsedSpans = createSelector(
export const DEFAULT_TICK_INTERVAL = 4;
export const DEFAULT_TICK_WIDTH = 3;
export const getTicksForTrace = createSelector(
({ trace }) => trace,
({ interval = DEFAULT_TICK_INTERVAL }) => interval,
({ width = DEFAULT_TICK_WIDTH }) => width,
({ trace }: { trace: TraceResponse }) => trace,
({ interval = DEFAULT_TICK_INTERVAL }: { interval?: number }) => interval,
({ width = DEFAULT_TICK_WIDTH }: { width?: number }) => width,
(
trace,
interval,
width
interval: number,
width: number
// timestamps will be spaced over the interval, starting from the initial timestamp
) =>
[...Array(interval + 1).keys()].map((num) => ({
@ -260,14 +270,16 @@ export const getTicksForTrace = createSelector(
// TODO: delete this when the backend can ensure uniqueness
/* istanbul ignore next */
export const enforceUniqueSpanIds = createSelector(
/* istanbul ignore next */ (trace) => trace,
/* istanbul ignore next */ (trace: Trace) => trace,
getTraceSpans,
/* istanbul ignore next */ (trace, spans) => {
const map = new Map();
const spanArray: TraceSpanData[] = [];
return {
...trace,
spans: spans.reduce((result, span) => {
spans: spans.reduce((result: TraceSpanData[], span: TraceSpanData) => {
const spanID = map.has(getSpanId(span)) ? `${getSpanId(span)}_${map.get(getSpanId(span))}` : getSpanId(span);
const updatedSpan = { ...span, spanID };
@ -280,17 +292,17 @@ export const enforceUniqueSpanIds = createSelector(
map.set(getSpanId(span), (map.get(getSpanId(span)) || 0) + 1);
return result.concat([updatedSpan]);
}, []),
}, spanArray),
};
}
);
// TODO: delete this when the backend can ensure uniqueness
export const dropEmptyStartTimeSpans = createSelector(
/* istanbul ignore next */ (trace) => trace,
/* istanbul ignore next */ (trace: Trace) => trace,
getTraceSpans,
/* istanbul ignore next */ (trace, spans) => ({
...trace,
spans: spans.filter((span) => !!getSpanTimestamp(span)),
spans: spans.filter((span: TraceSpanData) => !!getSpanTimestamp(span)),
})
);

View File

@ -22,7 +22,7 @@ export default class TreeNode {
return (node: TreeNode) => fn(node.value, node, depth);
}
static searchFunction(search: TreeNode | number | SearchFn) {
static searchFunction(search: TreeNode | number | SearchFn | string) {
if (typeof search === 'function') {
return search;
}
@ -51,7 +51,7 @@ export default class TreeNode {
return this;
}
find(search: TreeNode | number | SearchFn): TreeNode | null {
find(search: TreeNode | number | SearchFn | string): TreeNode | null {
const searchFn = TreeNode.iterFunction(TreeNode.searchFunction(search));
if (searchFn(this)) {
return this;
@ -65,7 +65,7 @@ export default class TreeNode {
return null;
}
getPath(search: TreeNode) {
getPath(search: TreeNode | string) {
const searchFn = TreeNode.iterFunction(TreeNode.searchFunction(search));
const findPath = (currentNode: TreeNode, currentPath: TreeNode[]): TreeNode[] | null => {