Skip to content

Commit 0afbcd9

Browse files
adriancoleshakuzen
authored andcommitted
Restores temporal ordering of spans in trace view (openzipkin#2312)
1 parent 4a8481c commit 0afbcd9

File tree

2 files changed

+51
-0
lines changed

2 files changed

+51
-0
lines changed

zipkin-ui/js/component_ui/traceToMustache.js

+13
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,19 @@ export function traceToMustache(root, logsUrl) {
106106
modelview.spans.push(spanRow);
107107
}
108108

109+
// Sort by timestamp, root first in case of skew. This makes the trace diagram display in
110+
// increasing indent (temporal) order, which is a better experience than causal (topological)
111+
// order in the current UI.
112+
modelview.spans.sort((a, b) => {
113+
if (!a.parentId && b.parentId) { // a is root
114+
return -1;
115+
} else if (a.parentId && !b.parentId) { // b is root
116+
return 1;
117+
}
118+
119+
return a.timestamp - b.timestamp;
120+
});
121+
109122
modelview.serviceNameAndSpanCounts = Object.keys(serviceNameToCount).sort().map(serviceName =>
110123
({serviceName, spanCount: serviceNameToCount[serviceName]})
111124
);

zipkin-ui/test/component_ui/traceToMustache.test.js

+38
Original file line numberDiff line numberDiff line change
@@ -153,5 +153,43 @@ describe('traceToMustache', () => {
153153
{serviceName: 'frontend', spanCount: 1}
154154
]);
155155
});
156+
157+
/*
158+
* The following tree should not traverse in alphabetical order, as the UI intends to order by
159+
* timstamp, not by cause. The reason is that the UI is row based, and people are used to seeing
160+
* data descending to the right.
161+
*
162+
* a
163+
* / | \
164+
* b c d
165+
* /|\
166+
* e f 1
167+
* \
168+
* 2
169+
*/
170+
it('should order spans by timestamp, root first, not by cause', () => {
171+
const a = new SpanNode(clean({traceId: '1', id: 'a', timestamp: 8}));
172+
const b = new SpanNode(clean({traceId: '1', id: 'b', parentId: 'a', timestamp: 7}));
173+
const c = new SpanNode(clean({traceId: '1', id: 'c', parentId: 'a', timestamp: 6}));
174+
const d = new SpanNode(clean({traceId: '1', id: 'd', parentId: 'a', timestamp: 5}));
175+
// root(a) has children b, c, d
176+
a.addChild(b);
177+
a.addChild(c);
178+
a.addChild(d);
179+
const e = new SpanNode(clean({traceId: '1', id: 'e', parentId: 'b', timestamp: 4}));
180+
const f = new SpanNode(clean({traceId: '1', id: 'f', parentId: 'b', timestamp: 3}));
181+
const g = new SpanNode(clean({traceId: '1', id: '1', parentId: 'b', timestamp: 2}));
182+
// child(b) has children e, f, g
183+
b.addChild(e);
184+
b.addChild(f);
185+
b.addChild(g);
186+
const h = new SpanNode(clean({traceId: '1', id: '2', parentId: '1', timestamp: 1}));
187+
// f has no children
188+
// child(g) has child h
189+
g.addChild(h);
190+
191+
const {spans} = traceToMustache(a);
192+
expect(spans.map(s => s.timestamp)).to.eql([8, 1, 2, 3, 4, 5, 6, 7]);
193+
});
156194
});
157195

0 commit comments

Comments
 (0)