refactor: optimize the attached events visualization in the trace widget (#234)

This commit is contained in:
Fine0830 2023-02-15 13:32:32 +08:00 committed by GitHub
parent efed817f73
commit a1066f09e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 51 deletions

View File

@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. -->
<template>
<div class="side-bar" v-if="showMenu" @click="isCollapse = false" @mouseleave="isCollapse = true">
<div class="side-bar" v-if="showMenu" @click="isCollapse = false" @mouseleave="closeMenu">
<div :class="isCollapse ? 'logo-icon-collapse' : 'logo-icon'">
<Icon :size="isCollapse ? 'xl' : 'logo'" :iconName="isCollapse ? 'logo' : 'logo-sw'" />
</div>
@ -81,6 +81,7 @@ limitations under the License. -->
const route = useRoute();
const isCollapse = ref(true);
const showMenu = ref(true);
const open = ref<boolean>(false);
if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
appStore.setIsMobile(true);
@ -97,7 +98,17 @@ limitations under the License. -->
return menus.filter((d) => d.meta && !d.meta.notShow);
};
function setCollapse() {
isCollapse.value = false;
open.value = true;
setTimeout(() => {
if (open.value) {
isCollapse.value = false;
}
open.value = false;
}, 1000);
}
function closeMenu() {
isCollapse.value = true;
open.value = false;
}
</script>

View File

@ -74,7 +74,7 @@ limitations under the License. -->
<h5 class="mb-10" v-if="currentSpan.attachedEvents && currentSpan.attachedEvents.length"> {{ t("events") }}. </h5>
<div
class="attach-events"
ref="timeline"
ref="eventGraph"
v-if="currentSpan.attachedEvents && currentSpan.attachedEvents.length"
></div>
<el-button class="popup-btn" type="primary" @click="getTaceLogs">
@ -131,8 +131,7 @@ limitations under the License. -->
import { useI18n } from "vue-i18n";
import type { PropType } from "vue";
import dayjs from "dayjs";
import { DataSet, Timeline } from "vis-timeline/standalone";
import "vis-timeline/styles/vis-timeline-graph2d.css";
import ListGraph from "../../utils/d3-trace-list";
import copy from "@/utils/copy";
import { ElMessage } from "element-plus";
import { dateFormat } from "@/utils/dateFormat";
@ -146,8 +145,6 @@ limitations under the License. -->
});
const { t } = useI18n();
const traceStore = useTraceStore();
const timeline = ref<Nullable<HTMLDivElement>>(null);
const visGraph = ref<Nullable<any>>(null);
const pageNum = ref<number>(1);
const showRelatedLogs = ref<boolean>(false);
const showEventDetail = ref<boolean>(false);
@ -156,6 +153,8 @@ limitations under the License. -->
const total = computed(() =>
traceStore.traceList.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value,
);
const tree = ref<any>(null);
const eventGraph = ref<Nullable<HTMLDivElement>>(null);
const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") => dayjs(date).format(pattern);
onMounted(() => {
@ -180,52 +179,46 @@ limitations under the License. -->
}
}
function visTimeline() {
if (!timeline.value) {
if (!eventGraph.value) {
return;
}
if (visGraph.value) {
visGraph.value.destroy();
}
const h = timeline.value.getBoundingClientRect().height;
const attachedEvents = props.currentSpan.attachedEvents || [];
const events: any[] = attachedEvents.map((d: SpanAttachedEvent, index: number) => {
let startTimeNanos = String(d.startTime.nanos).slice(-6).padStart(6, "0");
let endTimeNanos = String(d.endTime.nanos).slice(-6).padStart(6, "0");
endTimeNanos = toString(endTimeNanos);
startTimeNanos = toString(startTimeNanos);
return {
id: index + 1,
content: d.event,
start: new Date(Number(d.startTime.seconds * 1000 + d.startTime.nanos / 1000000)),
end: new Date(Number(d.endTime.seconds * 1000 + d.endTime.nanos / 1000000)),
...d,
startTime: d.startTime.seconds * 1000 + d.startTime.nanos / 1000000,
endTime: d.endTime.seconds * 1000 + d.endTime.nanos / 1000000,
className: "Normal",
startTimeNanos,
endTimeNanos,
};
});
const events: any[] = attachedEvents
.map((d: SpanAttachedEvent) => {
let startTimeNanos = String(d.startTime.nanos).slice(-6).padStart(6, "0");
let endTimeNanos = String(d.endTime.nanos).slice(-6).padStart(6, "0");
endTimeNanos = toString(endTimeNanos);
startTimeNanos = toString(startTimeNanos);
const startTime = d.startTime.seconds * 1000 + d.startTime.nanos / 1000000;
const endTime = d.endTime.seconds * 1000 + d.endTime.nanos / 1000000;
return {
label: d.event,
...d,
startTime,
endTime,
startTimeNanos,
endTimeNanos,
};
})
.sort((a: { startTime: number; endTime: number }, b: { startTime: number; endTime: number }) => {
return a.startTime - b.startTime;
});
const items = new DataSet(events);
const options: any = {
height: h,
width: "100%",
locale: "en",
groupHeightMode: "fitItems",
zoomMin: 80,
};
tree.value = new ListGraph(eventGraph.value, selectEvent);
tree.value.init(
{
children: events,
label: "",
},
events,
0,
);
tree.value.draw();
}
visGraph.value = new Timeline(timeline.value, items, options);
visGraph.value.on("select", (data: { items: number[] }) => {
const index = data.items[0];
currentEvent.value = events[index - 1 || 0] || {};
if (data.items.length) {
showEventDetail.value = true;
return;
}
showEventDetail.value = false;
});
function selectEvent(i: any) {
currentEvent.value = i.data;
showEventDetail.value = true;
}
function toString(str: string) {
return str.replace(/\d(?=(\d{3})+$)/g, "$&,");
@ -247,7 +240,8 @@ limitations under the License. -->
.attach-events {
width: 100%;
margin: 0 5px 5px 0;
height: 200px;
height: 400px;
overflow: auto;
}
.popup-btn {

View File

@ -18,6 +18,7 @@
import * as d3 from "d3";
import d3tip from "d3-tip";
import type { Trace } from "@/types/trace";
import dayjs from "dayjs";
export default class ListGraph {
private barHeight = 48;
@ -91,7 +92,6 @@ export default class ListGraph {
this.svg
.append("g")
.attr("class", "trace-xaxis")
.attr("transform", `translate(${this.width * 0.618 - 20},${30})`)
.call(this.xAxis);
this.sequentialScale = d3
@ -164,6 +164,7 @@ export default class ListGraph {
.attr("x", 35)
.attr("y", -6)
.attr("fill", "#333")
.style("font-size", "12px")
.html((d: any) => {
if (d.data.label === "TRACE_ROOT") {
return "";
@ -214,7 +215,16 @@ export default class ListGraph {
.attr("y", 12)
.attr("fill", "#ccc")
.style("font-size", "11px")
.text((d: any) => `${d.data.layer || ""} ${d.data.component ? "- " + d.data.component : d.data.component || ""}`);
.text(
(d: any) =>
`${d.data.layer || ""} ${
d.data.component
? "- " + d.data.component
: d.data.event
? this.visDate(d.data.startTime) + ":" + d.data.startTimeNanos
: ""
}`,
);
nodeEnter
.append("rect")
.attr("rx", 2)
@ -305,6 +315,9 @@ export default class ListGraph {
callback();
}
}
visDate(date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") {
return dayjs(date).format(pattern);
}
resize() {
if (!this.el) {
return;