feat: event widget associates with trace and log widget (#130)

This commit is contained in:
Fine0830 2022-07-29 16:34:36 +08:00 committed by GitHub
parent dc8e4bf273
commit 3b3e790dd9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 260 additions and 104 deletions

View File

@ -0,0 +1,17 @@
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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. -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M7.406 8.578l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z"></path>
</svg>

After

Width:  |  Height:  |  Size: 946 B

View File

@ -0,0 +1,17 @@
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
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. -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M7.406 15.422l-1.406-1.406 6-6 6 6-1.406 1.406-4.594-4.594z"></path>
</svg>

After

Width:  |  Height:  |  Size: 948 B

View File

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

View File

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

View File

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

View File

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

View File

@ -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<string>(
(props.data.filters && props.data.filters.traceId) || ""
);
const duration = ref<DurationTime>(
(props.data.filters && props.data.filters.duration) || appStore.durationTime
);
const keywordsOfContent = ref<string[]>([]);
const excludingKeywordsOfContent = ref<string[]>([]);
const tagsList = ref<string[]>([]);
@ -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();
}
}

View File

@ -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<DurationTime>(
(props.data.filters && props.data.filters.duration) || appStore.durationTime
);
const minTraceDuration = ref<number>();
const maxTraceDuration = ref<number>();
const tagsList = ref<string[]>([]);
@ -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();
}
}