mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-01 17:44:48 +00:00
feat: sort spans with startTime
or spanId
in a segment (#100)
This commit is contained in:
parent
b34c0b0c72
commit
74cb089271
@ -35,6 +35,7 @@ interface EbpfStore {
|
|||||||
couldProfiling: boolean;
|
couldProfiling: boolean;
|
||||||
tip: string;
|
tip: string;
|
||||||
selectedTask: Recordable<EBPFTaskList>;
|
selectedTask: Recordable<EBPFTaskList>;
|
||||||
|
aggregateType: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ebpfStore = defineStore({
|
export const ebpfStore = defineStore({
|
||||||
@ -48,6 +49,7 @@ export const ebpfStore = defineStore({
|
|||||||
couldProfiling: false,
|
couldProfiling: false,
|
||||||
tip: "",
|
tip: "",
|
||||||
selectedTask: {},
|
selectedTask: {},
|
||||||
|
aggregateType: "COUNT",
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setSelectedTask(task: EBPFTaskList) {
|
setSelectedTask(task: EBPFTaskList) {
|
||||||
@ -131,6 +133,7 @@ export const ebpfStore = defineStore({
|
|||||||
timeRanges: Array<{ start: number; end: number }>;
|
timeRanges: Array<{ start: number; end: number }>;
|
||||||
aggregateType: string;
|
aggregateType: string;
|
||||||
}) {
|
}) {
|
||||||
|
this.aggregateType = params.aggregateType;
|
||||||
if (!params.scheduleIdList.length) {
|
if (!params.scheduleIdList.length) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
|
9
src/types/trace.d.ts
vendored
9
src/types/trace.d.ts
vendored
@ -46,8 +46,15 @@ export interface Span {
|
|||||||
children?: Span[];
|
children?: Span[];
|
||||||
tags?: Array<Map<string, string>>;
|
tags?: Array<Map<string, string>>;
|
||||||
logs?: log[];
|
logs?: log[];
|
||||||
|
parentSegmentId?: string;
|
||||||
|
refs?: Ref[];
|
||||||
}
|
}
|
||||||
|
export type Ref = {
|
||||||
|
type: string;
|
||||||
|
parentSegmentId: string;
|
||||||
|
parentSpanId: number;
|
||||||
|
traceId: string;
|
||||||
|
};
|
||||||
export interface log {
|
export interface log {
|
||||||
time: number;
|
time: number;
|
||||||
data: Map<string, string>;
|
data: Map<string, string>;
|
||||||
|
@ -17,13 +17,13 @@ limitations under the License. -->
|
|||||||
<div class="top-list" v-if="available">
|
<div class="top-list" v-if="available">
|
||||||
<div class="chart-slow-i" v-for="(i, index) in data[key]" :key="index">
|
<div class="chart-slow-i" v-for="(i, index) in data[key]" :key="index">
|
||||||
<div class="ell tools flex-h">
|
<div class="ell tools flex-h">
|
||||||
<div>
|
<div class="desc">
|
||||||
<span class="calls mr-10">{{ i.value }}</span>
|
<span class="calls mr-10">{{ i.value }}</span>
|
||||||
<span class="cp mr-20">
|
<span class="cp mr-20">
|
||||||
{{ i.name }}
|
{{ i.name }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="copy">
|
||||||
<Icon
|
<Icon
|
||||||
iconName="review-list"
|
iconName="review-list"
|
||||||
size="middle"
|
size="middle"
|
||||||
@ -103,6 +103,16 @@ function handleClick(i: string) {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
flex-grow: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy {
|
||||||
|
width: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
.calls {
|
.calls {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
padding: 0 5px;
|
padding: 0 5px;
|
||||||
|
@ -155,7 +155,7 @@ function getLabel(metric: string, index: string) {
|
|||||||
|
|
||||||
.value {
|
.value {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: calc(100% - 30px);
|
flex-grow: 2;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -38,7 +38,7 @@ import EBPFStack from "./components/EBPFStack.vue";
|
|||||||
|
|
||||||
.vis-graph {
|
.vis-graph {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: calc(100% - 300px);
|
flex-grow: 2;
|
||||||
min-width: 700px;
|
min-width: 700px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
@ -252,13 +252,6 @@ watch(
|
|||||||
min-width: 560px;
|
min-width: 560px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.schedules {
|
|
||||||
width: calc(100% - 5px);
|
|
||||||
margin: 0 5px 5px 0;
|
|
||||||
height: calc(100% - 60px);
|
|
||||||
min-height: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inputs {
|
.inputs {
|
||||||
width: 350px;
|
width: 350px;
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import d3tip from "d3-tip";
|
|||||||
import { flamegraph } from "d3-flame-graph";
|
import { flamegraph } from "d3-flame-graph";
|
||||||
import { useEbpfStore } from "@/store/modules/ebpf";
|
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||||
import { StackElement } from "@/types/ebpf";
|
import { StackElement } from "@/types/ebpf";
|
||||||
|
import { AggregateTypes } from "./data";
|
||||||
import "d3-flame-graph/dist/d3-flamegraph.css";
|
import "d3-flame-graph/dist/d3-flamegraph.css";
|
||||||
|
|
||||||
/*global Nullable*/
|
/*global Nullable*/
|
||||||
@ -86,10 +87,13 @@ function drawGraph() {
|
|||||||
const tip = (d3tip as any)()
|
const tip = (d3tip as any)()
|
||||||
.attr("class", "d3-tip")
|
.attr("class", "d3-tip")
|
||||||
.direction("w")
|
.direction("w")
|
||||||
.html(
|
.html((d: { data: StackElement }) => {
|
||||||
(d: { data: StackElement }) =>
|
const valStr =
|
||||||
`<div class="mb-5 name">Symbol: ${d.data.name}</div><div class="mb-5">Dump Count: ${d.data.dumpCount}</div>`
|
ebpfStore.aggregateType === AggregateTypes[0].value
|
||||||
)
|
? `<div class="mb-5">Dump Count: ${d.data.dumpCount}</div>`
|
||||||
|
: `<div class="mb-5">Duration: ${d.data.dumpCount} ns</div>`;
|
||||||
|
return `<div class="mb-5 name">Symbol: ${d.data.name}</div>${valStr}`;
|
||||||
|
})
|
||||||
.style("max-width", "500px");
|
.style("max-width", "500px");
|
||||||
flameChart.value.tooltip(tip);
|
flameChart.value.tooltip(tip);
|
||||||
d3.select("#graph-stack").datum(stackTree.value).call(flameChart.value);
|
d3.select("#graph-stack").datum(stackTree.value).call(flameChart.value);
|
||||||
|
@ -56,7 +56,7 @@ function loadTrees(l: boolean) {
|
|||||||
|
|
||||||
.item {
|
.item {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: calc(100% - 300px);
|
flex-grow: 2;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,6 @@ import { useI18n } from "vue-i18n";
|
|||||||
import { useTraceStore } from "@/store/modules/trace";
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import copy from "@/utils/copy";
|
import copy from "@/utils/copy";
|
||||||
import List from "./components/List.vue";
|
|
||||||
import graphs from "./components/index";
|
import graphs from "./components/index";
|
||||||
import LogTable from "@/views/dashboard/related/components/LogTable/Index.vue";
|
import LogTable from "@/views/dashboard/related/components/LogTable/Index.vue";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
@ -162,7 +161,6 @@ export default defineComponent({
|
|||||||
name: "TraceDetail",
|
name: "TraceDetail",
|
||||||
components: {
|
components: {
|
||||||
...graphs,
|
...graphs,
|
||||||
List,
|
|
||||||
LogTable,
|
LogTable,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
@ -182,14 +180,8 @@ export default defineComponent({
|
|||||||
dayjs(date).format(pattern);
|
dayjs(date).format(pattern);
|
||||||
const showTraceLogs = ref<boolean>(false);
|
const showTraceLogs = ref<boolean>(false);
|
||||||
|
|
||||||
function handleClick(ids: string[] | any) {
|
function handleClick() {
|
||||||
let copyValue = null;
|
copy(traceId.value || traceStore.currentTrace.traceIds[0].value);
|
||||||
if (ids.length === 1) {
|
|
||||||
copyValue = ids[0];
|
|
||||||
} else {
|
|
||||||
copyValue = ids.join(",");
|
|
||||||
}
|
|
||||||
copy(copyValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeTraceId(opt: Option[] | any) {
|
async function changeTraceId(opt: Option[] | any) {
|
||||||
@ -235,6 +227,7 @@ export default defineComponent({
|
|||||||
pageNum,
|
pageNum,
|
||||||
loading,
|
loading,
|
||||||
total,
|
total,
|
||||||
|
traceId,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -31,7 +31,7 @@ import _ from "lodash";
|
|||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import ListGraph from "../../utils/d3-trace-list";
|
import ListGraph from "../../utils/d3-trace-list";
|
||||||
import TreeGraph from "../../utils/d3-trace-tree";
|
import TreeGraph from "../../utils/d3-trace-tree";
|
||||||
import { Span } from "@/types/trace";
|
import { Span, Ref } from "@/types/trace";
|
||||||
import SpanDetail from "./SpanDetail.vue";
|
import SpanDetail from "./SpanDetail.vue";
|
||||||
|
|
||||||
/* global defineProps, Nullable, defineExpose*/
|
/* global defineProps, Nullable, defineExpose*/
|
||||||
@ -45,6 +45,7 @@ const showDetail = ref<boolean>(false);
|
|||||||
const fixSpansSize = ref<number>(0);
|
const fixSpansSize = ref<number>(0);
|
||||||
const segmentId = ref<any>([]);
|
const segmentId = ref<any>([]);
|
||||||
const currentSpan = ref<Array<Span>>([]);
|
const currentSpan = ref<Array<Span>>([]);
|
||||||
|
const refSpans = ref<Array<Ref>>([]);
|
||||||
const tree = ref<any>(null);
|
const tree = ref<any>(null);
|
||||||
const traceGraph = ref<Nullable<HTMLDivElement>>(null);
|
const traceGraph = ref<Nullable<HTMLDivElement>>(null);
|
||||||
defineExpose({
|
defineExpose({
|
||||||
@ -103,14 +104,17 @@ function changeTree() {
|
|||||||
segmentId.value = [];
|
segmentId.value = [];
|
||||||
const segmentGroup: any = {};
|
const segmentGroup: any = {};
|
||||||
const segmentIdGroup: any = [];
|
const segmentIdGroup: any = [];
|
||||||
const fixSpans: any[] = [];
|
const fixSpans: Span[] = [];
|
||||||
const segmentHeaders: any = [];
|
const segmentHeaders: Span[] = [];
|
||||||
for (const span of props.data) {
|
for (const span of props.data) {
|
||||||
|
if (span.refs.length) {
|
||||||
|
refSpans.value.push(...span.refs);
|
||||||
|
}
|
||||||
if (span.parentSpanId === -1) {
|
if (span.parentSpanId === -1) {
|
||||||
segmentHeaders.push(span);
|
segmentHeaders.push(span);
|
||||||
} else {
|
} else {
|
||||||
const index = props.data.findIndex(
|
const item = props.data.find(
|
||||||
(i: any) =>
|
(i: Span) =>
|
||||||
i.segmentId === span.segmentId && i.spanId === span.spanId - 1
|
i.segmentId === span.segmentId && i.spanId === span.spanId - 1
|
||||||
);
|
);
|
||||||
const fixSpanKeyContent = {
|
const fixSpanKeyContent = {
|
||||||
@ -119,7 +123,7 @@ function changeTree() {
|
|||||||
spanId: span.spanId - 1,
|
spanId: span.spanId - 1,
|
||||||
parentSpanId: span.spanId - 2,
|
parentSpanId: span.spanId - 2,
|
||||||
};
|
};
|
||||||
if (index === -1 && !_.find(fixSpans, fixSpanKeyContent)) {
|
if (!item && !_.find(fixSpans, fixSpanKeyContent)) {
|
||||||
fixSpans.push({
|
fixSpans.push({
|
||||||
...fixSpanKeyContent,
|
...fixSpanKeyContent,
|
||||||
refs: [],
|
refs: [],
|
||||||
@ -133,6 +137,8 @@ function changeTree() {
|
|||||||
layer: "Broken",
|
layer: "Broken",
|
||||||
tags: [],
|
tags: [],
|
||||||
logs: [],
|
logs: [],
|
||||||
|
startTime: 0,
|
||||||
|
endTime: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,6 +173,8 @@ function changeTree() {
|
|||||||
layer: "Broken",
|
layer: "Broken",
|
||||||
tags: [],
|
tags: [],
|
||||||
logs: [],
|
logs: [],
|
||||||
|
startTime: 0,
|
||||||
|
endTime: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// if root broken node is not exist, create a root broken node.
|
// if root broken node is not exist, create a root broken node.
|
||||||
@ -191,6 +199,8 @@ function changeTree() {
|
|||||||
layer: "Broken",
|
layer: "Broken",
|
||||||
tags: [],
|
tags: [],
|
||||||
logs: [],
|
logs: [],
|
||||||
|
startTime: 0,
|
||||||
|
endTime: 0,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,14 +278,28 @@ function changeTree() {
|
|||||||
}
|
}
|
||||||
function collapse(d: Span) {
|
function collapse(d: Span) {
|
||||||
if (d.children) {
|
if (d.children) {
|
||||||
|
const item = refSpans.value.find(
|
||||||
|
(s: Ref) =>
|
||||||
|
s.parentSpanId === d.spanId && s.parentSegmentId === d.segmentId
|
||||||
|
);
|
||||||
let dur = d.endTime - d.startTime;
|
let dur = d.endTime - d.startTime;
|
||||||
d.children.forEach((i: Span) => {
|
d.children.forEach((i: Span) => {
|
||||||
dur -= i.endTime - i.startTime;
|
dur -= i.endTime - i.startTime;
|
||||||
});
|
});
|
||||||
d.dur = dur < 0 ? 0 : dur;
|
d.dur = dur < 0 ? 0 : dur;
|
||||||
|
if (item) {
|
||||||
|
d.children = d.children.sort(compare("startTime"));
|
||||||
|
}
|
||||||
d.children.forEach((i: Span) => collapse(i));
|
d.children.forEach((i: Span) => collapse(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function compare(p: string) {
|
||||||
|
return (m: any, n: any) => {
|
||||||
|
const a = m[p];
|
||||||
|
const b = n[p];
|
||||||
|
return a - b;
|
||||||
|
};
|
||||||
|
}
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
d3.selectAll(".d3-tip").remove();
|
d3.selectAll(".d3-tip").remove();
|
||||||
window.removeEventListener("resize", resize);
|
window.removeEventListener("resize", resize);
|
||||||
|
@ -52,7 +52,7 @@ limitations under the License. -->
|
|||||||
class="grey link-hover cp ml-5"
|
class="grey link-hover cp ml-5"
|
||||||
@click="copy(i.value)"
|
@click="copy(i.value)"
|
||||||
>
|
>
|
||||||
<Icon iconName="review-list" />
|
<Icon size="middle" iconName="review-list" />
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user