diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.css b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.css
index 3a0150dd30..adc08aa338 100644
--- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.css
+++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.css
@@ -49,6 +49,32 @@ limitations under the License.
top: 45%;
height: 11%;
z-index: 2;
+ overflow: hidden;
+}
+
+.SpanBar--criticalPath::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ width: 10%;
+ height: 100%;
+ visibility: hidden;
+ background-color: white;
+ border: 1px solid white;
+}
+
+.SpanBar--criticalPath:hover::before {
+ visibility: visible;
+ animation: runOnce 2s forwards;
+}
+
+@keyframes runOnce {
+ 0% {
+ left: 0;
+ }
+ 100% {
+ left: 100%;
+ }
}
.SpanBar--label {
@@ -85,6 +111,8 @@ limitations under the License.
.SpanBar--logMarker:hover {
background-color: #000;
+ transform: scale(1.2);
+ transition: transform 0.3s ease;
}
.SpanBar--logMarker::before,
@@ -94,7 +122,7 @@ limitations under the License.
top: 0;
bottom: 0;
right: 0;
- border: 1px solid transparent;
+ border: 3px solid transparent;
}
.SpanBar--logMarker::after {
diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.tsx
index 5d08301040..7f9447ef8a 100644
--- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.tsx
+++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/SpanBar.tsx
@@ -13,7 +13,7 @@
// limitations under the License.
import React, { useState } from 'react';
-import { Popover } from 'antd';
+import { Popover, Tooltip } from 'antd';
import _groupBy from 'lodash/groupBy';
import AccordianLogs from './SpanDetail/AccordianLogs';
@@ -124,7 +124,7 @@ function SpanBar(props: TCommonProps) {
))}
@@ -146,16 +146,25 @@ function SpanBar(props: TCommonProps) {
const criticalPathViewEnd = critcalPathViewBounds.end;
const key = `${each.spanId}-${index}`;
return (
-
+
+ A segment on the critical path of the overall trace/request/workflow.
+
+ }
+ >
+
+
);
})}
diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js
index 34038f55f3..16c767ca35 100644
--- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js
+++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.test.js
@@ -13,6 +13,7 @@
// limitations under the License.
import React from 'react';
import { shallow, mount } from 'enzyme';
+import { render, screen } from '@testing-library/react';
import ListView from './ListView';
import SpanBarRow from './SpanBarRow';
@@ -25,6 +26,8 @@ import updateUiFindSpy from '../../../utils/update-ui-find';
import * as linkPatterns from '../../../model/link-patterns';
import memoizedTraceCriticalPath from '../CriticalPath/index';
+import criticalPathTest from '../CriticalPath/testCases/test2';
+
jest.mock('./SpanTreeOffset');
jest.mock('../../../utils/update-ui-find');
@@ -326,6 +329,26 @@ describe('', () => {
).toBe(true);
});
+ it('renders Critical Path segments when row is not collapsed', () => {
+ wrapper.setProps({
+ trace: criticalPathTest.trace,
+ criticalPath: criticalPathTest.criticalPathSections,
+ });
+ render(instance.renderRow('some-key', {}, 0, {}));
+ expect(screen.getAllByTestId('SpanBar--criticalPath').length).toBe(2);
+ });
+
+ it('renders Critical Path segments are merged if consecutive when row is collapased', () => {
+ const childrenHiddenIDs = new Set([criticalPathTest.trace.spans[0].spanID]);
+ wrapper.setProps({
+ childrenHiddenIDs,
+ trace: criticalPathTest.trace,
+ criticalPath: criticalPathTest.criticalPathSections,
+ });
+ render(instance.renderRow('some-key', {}, 0, {}));
+ expect(screen.getAllByTestId('SpanBar--criticalPath').length).toBe(1);
+ });
+
it('renders a SpanBarRow with a RPC span if the row is collapsed and a client span', () => {
const clientTags = [{ key: 'span.kind', value: 'client' }, ...trace.spans[0].tags];
const serverTags = [{ key: 'span.kind', value: 'server' }, ...trace.spans[1].tags];
diff --git a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx
index 0b1e5c21ea..e0cfbeecba 100644
--- a/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx
+++ b/packages/jaeger-ui/src/components/TracePage/TraceTimelineViewer/VirtualizedTraceView.tsx
@@ -158,6 +158,41 @@ function getCssClasses(currentViewRange: [number, number]) {
});
}
+function mergeChildrenCriticalPath(
+ trace: Trace,
+ spanID: string,
+ criticalPath: criticalPathSection[]
+): criticalPathSection[] {
+ // Define an array to store the IDs of the span and its descendants (if the span is collapsed)
+ const allRequiredSpanIds = [spanID];
+
+ // If the span is collapsed, recursively find all of its descendants.
+ const findAllDescendants = (currentChildSpanIds: string[]) => {
+ currentChildSpanIds.forEach(eachId => {
+ const currentChildSpan = trace.spans.find(a => a.spanID === eachId)!;
+ if (currentChildSpan.hasChildren) {
+ allRequiredSpanIds.push(...currentChildSpan.childSpanIds);
+ findAllDescendants(currentChildSpan.childSpanIds);
+ }
+ });
+ };
+ findAllDescendants(allRequiredSpanIds);
+
+ const criticalPathSections: criticalPathSection[] = [];
+ criticalPath.forEach(each => {
+ if (allRequiredSpanIds.includes(each.spanId)) {
+ if (criticalPathSections.length !== 0 && each.section_end === criticalPathSections[0].section_start) {
+ // Merge Critical Paths if they are consecutive
+ criticalPathSections[0].section_start = each.section_start;
+ } else {
+ criticalPathSections.unshift({ ...each });
+ }
+ }
+ });
+
+ return criticalPathSections;
+}
+
const memoizedGenerateRowStates = memoizeOne(generateRowStatesFromTrace);
const memoizedViewBoundsFunc = memoizeOne(createViewedBoundsFunc, _isEqual);
const memoizedGetCssClasses = memoizeOne(getCssClasses, _isEqual);
@@ -358,24 +393,9 @@ export class VirtualizedTraceViewImpl extends React.Component {
- if (isCollapsed) {
- const allChildSpanIds = [spanID, ...childSpanIds];
- // This function called recursively to find all descendants of a span
- const findAllDescendants = (currentChildSpanIds: string[]) => {
- currentChildSpanIds.forEach(eachId => {
- const currentChildSpan = trace.spans.find(a => a.spanID === eachId)!;
- if (currentChildSpan.hasChildren) {
- allChildSpanIds.push(...currentChildSpan.childSpanIds);
- findAllDescendants(currentChildSpan.childSpanIds);
- }
- });
- };
- findAllDescendants(childSpanIds);
- return allChildSpanIds.includes(each.spanId);
- }
- return each.spanId === spanID;
- });
+ const criticalPathSections = isCollapsed
+ ? mergeChildrenCriticalPath(trace, spanID, criticalPath)
+ : criticalPath.filter(each => each.spanId === spanID);
// Check for direct child "server" span if the span is a "client" span.
let rpc = null;
if (isCollapsed) {