feat: sort spans with startTime or spanId in a segment (#100)

This commit is contained in:
Fine0830 2022-05-26 13:04:43 +08:00 committed by GitHub
parent b34c0b0c72
commit 74cb089271
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 68 additions and 34 deletions

View File

@ -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({}));
} }

View File

@ -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>;

View File

@ -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;

View File

@ -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>

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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);

View File

@ -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;
} }

View File

@ -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,
}; };
}, },
}); });

View File

@ -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);

View File

@ -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>