From 3b3e790dd9c4d918765b79d603b959a6e9c2e34a Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Fri, 29 Jul 2022 16:34:36 +0800 Subject: [PATCH] feat: event widget associates with trace and log widget (#130) --- src/assets/icons/keyboard_arrow_down.svg | 17 ++ src/assets/icons/keyboard_arrow_up.svg | 17 ++ src/components/Graph.vue | 122 +++++++----- src/store/modules/log.ts | 3 +- src/store/modules/trace.ts | 5 +- src/views/dashboard/related/event/Content.vue | 179 +++++++++++++----- src/views/dashboard/related/log/Header.vue | 11 +- src/views/dashboard/related/trace/Filter.vue | 10 +- 8 files changed, 260 insertions(+), 104 deletions(-) create mode 100644 src/assets/icons/keyboard_arrow_down.svg create mode 100644 src/assets/icons/keyboard_arrow_up.svg diff --git a/src/assets/icons/keyboard_arrow_down.svg b/src/assets/icons/keyboard_arrow_down.svg new file mode 100644 index 00000000..73d197b8 --- /dev/null +++ b/src/assets/icons/keyboard_arrow_down.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/assets/icons/keyboard_arrow_up.svg b/src/assets/icons/keyboard_arrow_up.svg new file mode 100644 index 00000000..11cba421 --- /dev/null +++ b/src/assets/icons/keyboard_arrow_up.svg @@ -0,0 +1,17 @@ + + + + diff --git a/src/components/Graph.vue b/src/components/Graph.vue index 6b87334a..200cb1d8 100644 --- a/src/components/Graph.vue +++ b/src/components/Graph.vue @@ -94,6 +94,71 @@ onMounted(async () => { }, 1000); }); +function updateOptions() { + const instance = getInstance(); + if (!instance) { + return; + } + if (!props.filters) { + return; + } + if (props.filters.isRange) { + const options = eventAssociate(); + setOptions(options || props.option); + } else { + instance.dispatchAction({ + type: "showTip", + dataIndex: props.filters.dataIndex, + seriesIndex: 0, + }); + } +} + +function eventAssociate() { + if (!props.filters) { + return; + } + if (!props.filters.duration) { + return props.option; + } + if (!props.option.series[0]) { + return; + } + const list = props.option.series[0].data.map( + (d: (number | string)[]) => d[0] + ); + if (!list.includes(props.filters.duration.endTime)) { + return; + } + const markArea = { + silent: true, + itemStyle: { + opacity: 0.3, + }, + data: [ + [ + { + xAxis: props.filters.duration.startTime, + }, + { + xAxis: props.filters.duration.endTime, + }, + ], + ], + }; + const series = (window as any).structuredClone(props.option.series); + for (const [key, temp] of series.entries()) { + if (key === 0) { + temp.markArea = markArea; + } + } + const options = { + ...props.option, + series, + }; + return options; +} + watch( () => props.option, (newVal, oldVal) => { @@ -103,62 +168,17 @@ watch( if (JSON.stringify(newVal) === JSON.stringify(oldVal)) { return; } - setOptions(newVal); + let options; + if (props.filters && props.filters.isRange) { + options = eventAssociate(); + } + setOptions(options || props.option); } ); watch( () => props.filters, () => { - const instance = getInstance(); - if (!instance) { - return; - } - if (props.filters) { - if (props.filters.isRange) { - const list = props.option.series[0].data.map( - (d: (number | string)[]) => d[0] - ); - if (!list.includes(props.filters.duration.endTime)) { - return; - } - const markArea = { - silent: true, - itemStyle: { - opacity: 0.3, - }, - data: [ - [ - { - xAxis: props.filters.duration.startTime, - }, - { - xAxis: props.filters.duration.endTime, - }, - ], - ], - }; - const series = (window as any).structuredClone(props.option.series); - for (const [key, temp] of series.entries()) { - if (key === 0) { - temp.markArea = markArea; - } - } - const options = { - ...props.option, - series, - }; - if (JSON.stringify(options) === JSON.stringify(props.option)) { - return; - } - setOptions(options); - return; - } - instance.dispatchAction({ - type: "showTip", - dataIndex: props.filters.dataIndex, - seriesIndex: 0, - }); - } + updateOptions(); } ); diff --git a/src/store/modules/log.ts b/src/store/modules/log.ts index 241297de..ea0c9c0f 100644 --- a/src/store/modules/log.ts +++ b/src/store/modules/log.ts @@ -53,7 +53,8 @@ export const logStore = defineStore({ setLogCondition(data: any) { this.conditions = { ...this.conditions, ...data }; }, - resetCondition() { + resetState() { + this.logs = []; this.conditions = { queryDuration: useAppStoreWithOut().durationTime, paging: { pageNum: 1, pageSize: 15 }, diff --git a/src/store/modules/trace.ts b/src/store/modules/trace.ts index 16aa422b..36c55dd4 100644 --- a/src/store/modules/trace.ts +++ b/src/store/modules/trace.ts @@ -63,7 +63,10 @@ export const traceStore = defineStore({ setTraceSpans(spans: Span) { this.traceSpans = spans; }, - resetCondition() { + resetState() { + this.traceSpans = []; + this.traceList = []; + this.currentTrace = {}; this.conditions = { queryDuration: useAppStoreWithOut().durationTime, paging: { pageNum: 1, pageSize: 20 }, diff --git a/src/views/dashboard/related/event/Content.vue b/src/views/dashboard/related/event/Content.vue index 5dc8c501..a8a71f8c 100644 --- a/src/views/dashboard/related/event/Content.vue +++ b/src/views/dashboard/related/event/Content.vue @@ -26,8 +26,9 @@ import { DataSet, Timeline } from "vis-timeline/standalone"; import "vis-timeline/styles/vis-timeline-graph2d.css"; import { useDashboardStore } from "@/store/modules/dashboard"; import getDashboard from "@/hooks/useDashboardsSession"; -import { dateFormatTime } from "@/utils/dateFormat"; import { useAppStoreWithOut } from "@/store/modules/app"; +import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat"; +import getLocalTime from "@/utils/localtime"; const eventStore = useEventStore(); /*global defineProps, Nullable */ @@ -105,53 +106,139 @@ function visTimeline() { return; } dashboardStore.selectWidget(props.data); - const all = getDashboard(dashboardStore.currentDashboard).widgets; - const widgets = all.filter( - (d: { value: string; label: string } & LayoutConfig) => { - const isLinear = ["Bar", "Line", "Area"].includes( - (d.graph && d.graph.type) || "" - ); - if (isLinear) { - return d; - } - } - ); - const index = properties.items[0]; - const i = events[index - 1 || 0]; - - for (const widget of widgets) { - let end = i.end; - if (!isNaN(index)) { - let diff = 60000; - switch (appStore.duration.step) { - case "MINUTE": - diff = 60000; - break; - case "HOUR": - diff = 3600000; - break; - case "DAY": - diff = 3600000 * 24; - break; - } - if (!i.end || i.end.getTime() - i.start.getTime() < diff) { - end = i.start.getTime() + diff; - } - } - const startTime = dateFormatTime(i.start, appStore.duration.step); - const endTime = dateFormatTime(new Date(end), appStore.duration.step); - widget.filters = { - sourceId: dashboardStore.selectedGrid.id || "", - isRange: true, - duration: { - startTime, - endTime, - }, - }; - dashboardStore.setWidget(widget); - } + const dashboard = getDashboard(dashboardStore.currentDashboard).widgets; + associateMetrics(properties.items, events, dashboard); + associateTraceLog(properties.items, events, dashboard); }); } +function associateTraceLog( + items: number[], + events: { + id: number; + content: string; + start: Date; + end: Date; + data: unknown; + className: string; + }[], + dashboard: LayoutConfig[] +) { + const widgets = dashboard.filter((d: { type: string }) => + ["Trace", "Log"].includes(d.type) + ); + const index = items[0]; + const i = events[index - 1 || 0]; + for (const widget of widgets) { + if (isNaN(index)) { + const item = { + ...widget, + filters: { + sourceId: props.data.id || "", + duration: null, + }, + }; + dashboardStore.setWidget(item); + } else { + const { start, end } = setEndTime(i.start, i.end); + const item = { + ...widget, + filters: { + sourceId: props.data.id || "", + duration: { + start: dateFormatStep( + getLocalTime(appStore.utc, start), + appStore.duration.step, + true + ), + end: dateFormatStep( + getLocalTime(appStore.utc, end), + appStore.duration.step, + true + ), + step: appStore.duration.step, + }, + }, + }; + dashboardStore.setWidget(item); + } + } +} +function associateMetrics( + items: number[], + events: { + id: number; + content: string; + start: Date; + end: Date; + data: unknown; + className: string; + }[], + dashboard: LayoutConfig[] +) { + const widgets = dashboard.filter((d: LayoutConfig) => { + const isLinear = ["Bar", "Line", "Area"].includes( + (d.graph && d.graph.type) || "" + ); + if (isLinear) { + return d; + } + }); + const index = items[0]; + const i = events[index - 1 || 0]; + + for (const widget of widgets) { + if (isNaN(index)) { + const item = { + ...widget, + filters: { + sourceId: dashboardStore.selectedGrid.id || "", + isRange: true, + duration: { + startTime: null, + endTime: null, + }, + }, + }; + dashboardStore.setWidget(item); + } else { + const { start, end } = setEndTime(i.start, i.end); + const startTime = dateFormatTime(start, appStore.duration.step); + const endTime = dateFormatTime(end, appStore.duration.step); + const item = { + ...widget, + filters: { + sourceId: dashboardStore.selectedGrid.id || "", + isRange: true, + duration: { + startTime, + endTime, + }, + }, + }; + dashboardStore.setWidget(item); + } + } +} +function setEndTime(start: Date, end: Date) { + let time: Date | number = end; + let diff = 60000; + switch (appStore.duration.step) { + case "MINUTE": + diff = 60000; + break; + case "HOUR": + diff = 3600000; + break; + case "DAY": + diff = 3600000 * 24; + break; + } + if (!end || end.getTime() - start.getTime() < diff) { + time = start.getTime() + diff; + } + return { start, end: new Date(time) }; +} + function resize() { const observer = new ResizeObserver((entries) => { const entry = entries[0]; diff --git a/src/views/dashboard/related/log/Header.vue b/src/views/dashboard/related/log/Header.vue index 7b16c4d6..33732011 100644 --- a/src/views/dashboard/related/log/Header.vue +++ b/src/views/dashboard/related/log/Header.vue @@ -143,6 +143,7 @@ import { ElMessage } from "element-plus"; import { EntityType } from "../../data"; import { ErrorCategory } from "./data"; import { LayoutConfig } from "@/types/dashboard"; +import { DurationTime } from "@/types/app"; /*global defineProps, Recordable */ const props = defineProps({ @@ -160,6 +161,9 @@ const logStore = useLogStore(); const traceId = ref( (props.data.filters && props.data.filters.traceId) || "" ); +const duration = ref( + (props.data.filters && props.data.filters.duration) || appStore.durationTime +); const keywordsOfContent = ref([]); const excludingKeywordsOfContent = ref([]); const tagsList = ref([]); @@ -252,7 +256,7 @@ function searchLogs() { pagePathId: endpoint || state.endpoint.id || undefined, serviceVersionId: instance || state.instance.id || undefined, paging: { pageNum: 1, pageSize: 15 }, - queryDuration: appStore.durationTime, + queryDuration: duration, category: state.category.value, }); } else { @@ -339,13 +343,14 @@ function removeExcludeContent(index: number) { excludingContentStr.value = ""; } onUnmounted(() => { - logStore.resetCondition(); + logStore.resetState(); const item = { ...props.data, filters: undefined, }; dashboardStore.setWidget(item); traceId.value = ""; + duration.value = appStore.durationTime; }); watch( () => selectorStore.currentService, @@ -375,12 +380,12 @@ watch( watch( () => props.data.filters, (newJson, oldJson) => { - console.log(props.data.filters); if (props.data.filters) { if (JSON.stringify(newJson) === JSON.stringify(oldJson)) { return; } traceId.value = props.data.filters.traceId || ""; + duration.value = props.data.filters.duration || appStore.durationTime; init(); } } diff --git a/src/views/dashboard/related/trace/Filter.vue b/src/views/dashboard/related/trace/Filter.vue index 77753b4a..cb351e99 100644 --- a/src/views/dashboard/related/trace/Filter.vue +++ b/src/views/dashboard/related/trace/Filter.vue @@ -105,6 +105,7 @@ import ConditionTags from "@/views/components/ConditionTags.vue"; import { ElMessage } from "element-plus"; import { EntityType } from "../../data"; import { LayoutConfig } from "@/types/dashboard"; +import { DurationTime } from "@/types/app"; /*global defineProps, Recordable */ const props = defineProps({ @@ -122,6 +123,9 @@ const appStore = useAppStoreWithOut(); const selectorStore = useSelectorStore(); const dashboardStore = useDashboardStore(); const traceStore = useTraceStore(); +const duration = ref( + (props.data.filters && props.data.filters.duration) || appStore.durationTime +); const minTraceDuration = ref(); const maxTraceDuration = ref(); const tagsList = ref([]); @@ -198,7 +202,7 @@ function searchTraces() { endpointId: endpoint || state.endpoint.id || undefined, serviceInstanceId: instance || state.instance.id || undefined, traceState: state.status.value || "ALL", - queryDuration: appStore.durationTime, + queryDuration: duration.value, minTraceDuration: Number(minTraceDuration.value), maxTraceDuration: Number(maxTraceDuration.value), queryOrder: "BY_DURATION", @@ -231,13 +235,14 @@ async function searchEndpoints(keyword: string) { } } onUnmounted(() => { - traceStore.resetCondition(); + traceStore.resetState(); const item = { ...props.data, filters: undefined, }; dashboardStore.setWidget(item); traceId.value = ""; + duration.value = appStore.durationTime; }); watch( () => [selectorStore.currentPod], @@ -273,6 +278,7 @@ watch( return; } traceId.value = props.data.filters.traceId || ""; + duration.value = props.data.filters.duration || appStore.durationTime; init(); } }