forked from openzipkin/zipkin
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds "View Saved Trace" screen (openzipkin#1884)
This is an alternative to saving on the backend or via a proxy Closes openzipkin#1747
- Loading branch information
Showing
11 changed files
with
792 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import {component} from 'flightjs'; | ||
import FullPageSpinnerUI from '../component_ui/fullPageSpinner'; | ||
import traceToMustache from '../../js/component_ui/traceToMustache'; | ||
import {SPAN_V1} from '../spanConverter'; | ||
|
||
function rootToFrontComparator(span1/* , span2*/) { | ||
return span1.parentId === undefined ? -1 : 0; | ||
} | ||
|
||
function sort(trace) { | ||
if (trace != null) { | ||
trace.sort(rootToFrontComparator); | ||
} | ||
} | ||
|
||
function ensureV1(trace) { | ||
if (trace == null || trace.length === 0 | ||
|| (trace[0].localEndpoint === undefined && trace[0].remoteEndpoint === undefined)) { | ||
return trace; | ||
} | ||
|
||
const newTrace = []; | ||
for (let i = 0; i < trace.length; i++) { | ||
newTrace.push(SPAN_V1.convert(trace[i])); | ||
} | ||
|
||
return newTrace; | ||
} | ||
|
||
export default component(function uploadTrace() { | ||
this.doUpload = function() { | ||
const files = this.node.files; | ||
if (files.length === 0) { | ||
return; | ||
} | ||
|
||
const reader = new FileReader(); | ||
reader.onload = evt => { | ||
let model; | ||
try { | ||
let trace = JSON.parse(evt.target.result); | ||
trace = ensureV1(trace); | ||
sort(trace); | ||
|
||
const modelview = traceToMustache(trace); | ||
model = {modelview, trace}; | ||
} catch (e) { | ||
this.trigger('uiServerError', | ||
{desc: 'Cannot parse file', message: e}); | ||
throw e; | ||
} finally { | ||
this.trigger(document, 'uiHideFullPageSpinner'); | ||
} | ||
|
||
this.trigger(document, 'traceViewerPageModelView', model); | ||
}; | ||
|
||
reader.onerror = evt => { | ||
this.trigger(document, 'uiHideFullPageSpinner'); | ||
this.trigger('uiServerError', | ||
{desc: 'Cannot load file', message: `${evt.target.error.name}`}); | ||
}; | ||
|
||
this.trigger(document, 'uiShowFullPageSpinner'); | ||
setTimeout(() => reader.readAsText(files[0]), 0); | ||
}; | ||
|
||
this.after('initialize', function() { | ||
this.on('change', this.doUpload); | ||
FullPageSpinnerUI.teardownAll(); | ||
FullPageSpinnerUI.attachTo('#fullPageSpinner'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import {component} from 'flightjs'; | ||
import $ from 'jquery'; | ||
import FilterAllServicesUI from '../component_ui/filterAllServices'; | ||
import JsonPanelUI from '../component_ui/jsonPanel'; | ||
import ServiceFilterSearchUI from '../component_ui/serviceFilterSearch'; | ||
import SpanPanelUI from '../component_ui/spanPanel'; | ||
import TraceUI from '../component_ui/trace'; | ||
import FilterLabelUI from '../component_ui/filterLabel'; | ||
import ZoomOut from '../component_ui/zoomOutSpans'; | ||
import UploadTraceUI from '../component_ui/uploadTrace'; | ||
import {traceViewerTemplate} from '../templates'; | ||
import {contextRoot} from '../publicPath'; | ||
|
||
const TraceViewerPageComponent = component(function TraceViewerPage() { | ||
this.render = function(model) { | ||
try { | ||
this.$node.html(traceViewerTemplate({ | ||
contextRoot, | ||
...model | ||
})); | ||
} catch (e) { | ||
this.trigger('uiServerError', | ||
{desc: 'Failed to render template', message: e.message}); | ||
} | ||
|
||
UploadTraceUI.attachTo('#traceFile'); | ||
}; | ||
|
||
this.attach = function() { | ||
FilterAllServicesUI.attachTo('#filterAllServices', { | ||
totalServices: $('.trace-details.services span').length | ||
}); | ||
JsonPanelUI.attachTo('#jsonPanel'); | ||
ServiceFilterSearchUI.attachTo('#serviceFilterSearch'); | ||
SpanPanelUI.attachTo('#spanPanel'); | ||
TraceUI.attachTo('#trace-container'); | ||
FilterLabelUI.attachTo('.service-filter-label'); | ||
ZoomOut.attachTo('#zoomOutSpans'); | ||
}; | ||
|
||
this.teardown = function() { | ||
ZoomOut.teardownAll(); | ||
FilterLabelUI.teardownAll(); | ||
TraceUI.teardownAll(); | ||
SpanPanelUI.teardownAll(); | ||
ServiceFilterSearchUI.teardownAll(); | ||
JsonPanelUI.teardownAll(); | ||
FilterAllServicesUI.teardownAll(); | ||
}; | ||
|
||
this.after('initialize', function() { | ||
window.document.title = 'Zipkin - Trace Viewer'; | ||
|
||
this.render({}); | ||
|
||
this.on(document, 'traceViewerPageModelView', function(ev, data) { | ||
this.teardown(); | ||
this.render(data.modelview); | ||
this.attach(); | ||
|
||
this.$node.find('#traceJsonLink').click(e => { | ||
e.preventDefault(); | ||
this.trigger('uiRequestJsonPanel', {title: `Trace ${data.modelview.traceId}`, | ||
obj: data.trace, | ||
link: `${contextRoot}traceViewer`}); | ||
}); | ||
|
||
$('.annotation:not(.core)').tooltip({placement: 'left'}); | ||
}); | ||
}); | ||
}); | ||
|
||
export default function initializeTrace(config) { | ||
TraceViewerPageComponent.attachTo('.content', {config}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
function toV1Endpoint(endpoint) { | ||
if (endpoint === undefined) { | ||
return undefined; | ||
} | ||
const res = { | ||
serviceName: endpoint.serviceName || '', // undefined is not allowed in v1 | ||
}; | ||
if (endpoint.ipv4) { | ||
res.ipv4 = endpoint.ipv4; | ||
} | ||
if (endpoint.port) { | ||
res.port = endpoint.port; | ||
} | ||
return res; | ||
} | ||
|
||
function toV1Annotation(ann, endpoint) { | ||
return { | ||
value: ann.value, | ||
timestamp: ann.timestamp, | ||
endpoint | ||
}; | ||
} | ||
|
||
// Copied from https://github.com/openzipkin/zipkin-js/blob/8018e441d01804b02d0d217f10cd82759e71e02a/packages/zipkin/src/jsonEncoder.js#L25 | ||
// Modified to correct assumption that 'annotations' always exist and ensure | ||
// that 'beginAnnotation' comes first timestamp/duration should always be copied over | ||
function convertV1(span) { | ||
const res = { | ||
traceId: span.traceId | ||
}; | ||
if (span.parentId) { // instead of writing "parentId": NULL | ||
res.parentId = span.parentId; | ||
} | ||
res.id = span.id; | ||
res.name = span.name || ''; // undefined is not allowed in v1 | ||
res.timestamp = span.timestamp; | ||
res.duration = span.duration; | ||
|
||
const jsonEndpoint = toV1Endpoint(span.localEndpoint); | ||
|
||
let beginAnnotation; | ||
let endAnnotation; | ||
let addressKey; | ||
switch (span.kind) { | ||
case 'CLIENT': | ||
beginAnnotation = span.timestamp ? 'cs' : undefined; | ||
endAnnotation = 'cr'; | ||
addressKey = 'sa'; | ||
break; | ||
case 'SERVER': | ||
beginAnnotation = span.timestamp ? 'sr' : undefined; | ||
endAnnotation = 'ss'; | ||
addressKey = 'ca'; | ||
break; | ||
default: | ||
} | ||
|
||
if (span.annotations !== undefined && span.annotations.length > 0 | ||
|| beginAnnotation) { // don't write empty array | ||
res.annotations = []; | ||
} | ||
|
||
if (beginAnnotation) { | ||
res.annotations.push({ | ||
value: beginAnnotation, | ||
timestamp: span.timestamp, | ||
endpoint: jsonEndpoint | ||
}); | ||
} | ||
|
||
if (span.annotations !== undefined && span.annotations.length > 0) { | ||
span.annotations.forEach((ann) => | ||
res.annotations.push(toV1Annotation(ann, jsonEndpoint)) | ||
); | ||
} | ||
|
||
if (beginAnnotation && span.duration) { | ||
res.annotations.push({ | ||
value: endAnnotation, | ||
timestamp: span.timestamp + span.duration, | ||
endpoint: jsonEndpoint | ||
}); | ||
} | ||
|
||
const keys = Object.keys(span.tags || {}); | ||
if (keys.length > 0 || span.remoteEndpoint) { // don't write empty array | ||
res.binaryAnnotations = keys.map(key => ({ | ||
key, | ||
value: span.tags[key], | ||
endpoint: jsonEndpoint | ||
})); | ||
} | ||
|
||
if (span.remoteEndpoint) { | ||
const address = { | ||
key: addressKey, | ||
value: true, | ||
endpoint: toV1Endpoint(span.remoteEndpoint) | ||
}; | ||
res.binaryAnnotations.push(address); | ||
} | ||
|
||
if (span.debug) { // instead of writing "debug": false | ||
res.debug = true; | ||
} | ||
return res; | ||
} | ||
|
||
module.exports.SPAN_V1 = { | ||
convert(span) { | ||
return convertV1(span); | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
nav.inves = Investigate system behavior | ||
nav.find = Find a trace | ||
nav.dep = Dependencies | ||
nav.search = Go to trace | ||
nav.search = Go to trace | ||
nav.viewSaved = View Saved Trace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.