feat: Implement task timeline and policy list widget for continous profiling (#280)

This commit is contained in:
Fine0830
2023-06-12 16:17:38 +08:00
committed by GitHub
parent 7738695601
commit 22db68646c
48 changed files with 2088 additions and 45 deletions

View File

@@ -38,4 +38,18 @@ export const TimeRangeConfig = {
text: "text",
};
export const ControlsTypes = ["Trace", "Profile", "Log", "DemandLog", "Ebpf", "NetworkProfiling", "ThirdPartyApp"];
export const ControlsTypes = [
"Trace",
"Profile",
"Log",
"DemandLog",
"Ebpf",
"NetworkProfiling",
"ThirdPartyApp",
"ContinuousProfiling",
"TaskTimeline",
];
export enum EBPFProfilingTriggerType {
FIXED_TIME = "FIXED_TIME",
CONTINUOUS_PROFILING = "CONTINUOUS_PROFILING",
}

View File

@@ -0,0 +1,146 @@
/**
* 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.
*/
import { defineStore } from "pinia";
import type { StrategyItem, CheckItems } from "@/types/continous-profiling";
import type { EBPFTaskList, EBPFProfilingSchedule, AnalyzationTrees } from "@/types/ebpf";
import type { Instance } from "@/types/selector";
import { store } from "@/store";
import graphql from "@/graphql";
import type { AxiosResponse } from "axios";
interface ContinousProfilingState {
strategyList: Array<Recordable<StrategyItem>>;
selectedStrategy: Recordable<StrategyItem>;
taskList: Array<Recordable<EBPFTaskList>>;
selectedTask: Recordable<EBPFTaskList>;
errorTip: string;
errorReason: string;
instances: Instance[];
instance: Nullable<Instance>;
eBPFSchedules: EBPFProfilingSchedule[];
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
analyzeTrees: AnalyzationTrees[];
ebpfTips: string;
aggregateType: string;
instancesLoading: boolean;
policyLoading: boolean;
}
export const continousProfilingStore = defineStore({
id: "continousProfiling",
state: (): ContinousProfilingState => ({
strategyList: [],
selectedStrategy: {},
taskList: [],
selectedTask: {},
errorReason: "",
errorTip: "",
ebpfTips: "",
instances: [],
eBPFSchedules: [],
currentSchedule: {},
analyzeTrees: [],
aggregateType: "COUNT",
instance: null,
instancesLoading: false,
policyLoading: false,
}),
actions: {
setSelectedStrategy(task: Recordable<StrategyItem>) {
this.selectedStrategy = task || {};
},
setselectedTask(task: Recordable<EBPFTaskList>) {
this.selectedTask = task || {};
},
setCurrentSchedule(s: EBPFProfilingSchedule) {
this.currentSchedule = s;
},
setAnalyzeTrees(tree: AnalyzationTrees[]) {
this.analyzeTrees = tree;
},
setCurrentInstance(instance: Nullable<Instance>) {
this.instance = instance;
},
async setContinuousProfilingPolicy(
serviceId: string,
targets: {
targetType: string;
checkItems: CheckItems[];
}[],
) {
const res: AxiosResponse = await graphql.query("editStrategy").params({
request: {
serviceId,
targets,
},
});
if (res.data.errors) {
return res.data;
}
return res.data;
},
async getStrategyList(params: { serviceId: string }) {
if (!params.serviceId) {
return new Promise((resolve) => resolve({}));
}
this.policyLoading = true;
const res: AxiosResponse = await graphql.query("getStrategyList").params(params);
this.policyLoading = false;
if (res.data.errors) {
return res.data;
}
this.strategyList = (res.data.data.strategyList || []).map((d: StrategyItem, index: number) => {
return {
...d,
id: index,
};
});
this.setSelectedStrategy(this.strategyList[0] || {});
if (!this.strategyList.length) {
this.taskList = [];
}
if (!this.selectedStrategy.type) {
return res.data;
}
this.getMonitoringInstances(params.serviceId);
return res.data;
},
async getMonitoringInstances(serviceId: string): Promise<Nullable<AxiosResponse>> {
this.instancesLoading = true;
if (!serviceId) {
return null;
}
const res: AxiosResponse = await graphql.query("getMonitoringInstances").params({
serviceId,
target: this.selectedStrategy.type,
});
this.instancesLoading = false;
if (!res.data.errors) {
this.instances = res.data.data.instances || [];
this.instance = this.instances[0] || null;
}
return res.data;
},
},
});
export function useContinousProfilingStore(): Recordable {
return continousProfilingStore(store);
}

View File

@@ -92,6 +92,7 @@ export const dashboardStore = defineStore({
metricTypes: [""],
metrics: [""],
};
if (type === "Widget") {
newItem.metricMode = MetricModes.Expression;
}

View File

@@ -20,6 +20,7 @@ import type { EBPFTaskCreationRequest, EBPFProfilingSchedule, EBPFTaskList, Anal
import { store } from "@/store";
import graphql from "@/graphql";
import type { AxiosResponse } from "axios";
import { EBPFProfilingTriggerType } from "../data";
interface EbpfState {
taskList: Array<Recordable<EBPFTaskList>>;
eBPFSchedules: EBPFProfilingSchedule[];
@@ -27,7 +28,7 @@ interface EbpfState {
analyzeTrees: AnalyzationTrees[];
labels: Option[];
couldProfiling: boolean;
tip: string;
ebpfTips: string;
selectedTask: Recordable<EBPFTaskList>;
aggregateType: string;
}
@@ -41,7 +42,7 @@ export const ebpfStore = defineStore({
analyzeTrees: [],
labels: [{ value: "", label: "" }],
couldProfiling: false,
tip: "",
ebpfTips: "",
selectedTask: {},
aggregateType: "COUNT",
}),
@@ -77,6 +78,7 @@ export const ebpfStore = defineStore({
this.getTaskList({
serviceId: param.serviceId,
targets: ["ON_CPU", "OFF_CPU"],
triggerType: EBPFProfilingTriggerType.FIXED_TIME,
});
return res.data;
},
@@ -86,7 +88,7 @@ export const ebpfStore = defineStore({
}
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
this.tip = "";
this.ebpfTips = "";
if (res.data.errors) {
return res.data;
}
@@ -103,13 +105,14 @@ export const ebpfStore = defineStore({
if (!params.taskId) {
return new Promise((resolve) => resolve({}));
}
const res: AxiosResponse = await graphql.query("getEBPFSchedules").params({ ...params });
if (res.data.errors) {
this.eBPFSchedules = [];
return res.data;
}
this.tip = "";
this.ebpfTips = "";
const { eBPFSchedules } = res.data.data;
this.eBPFSchedules = eBPFSchedules;
@@ -138,7 +141,7 @@ export const ebpfStore = defineStore({
return res.data;
}
const { analysisEBPFResult } = res.data.data;
this.tip = analysisEBPFResult.tip;
this.ebpfTips = analysisEBPFResult.tip;
if (!analysisEBPFResult) {
this.analyzeTrees = [];
return res.data;

View File

@@ -65,6 +65,12 @@ export const networkProfilingStore = defineStore({
setLink(link: Call) {
this.call = link;
},
seNodes(nodes: Node[]) {
this.nodes = nodes;
},
setLinks(links: Call[]) {
this.calls = links;
},
setMetricsLayout(layout: LayoutConfig[]) {
this.metricsLayout = layout;
},

View File

@@ -0,0 +1,131 @@
/**
* 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.
*/
import { defineStore } from "pinia";
import { ElMessage } from "element-plus";
import { store } from "@/store";
import graphql from "@/graphql";
import type { AxiosResponse } from "axios";
import { useAppStoreWithOut } from "@/store/modules/app";
import type { EBPFTaskList } from "@/types/ebpf";
import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
import { useSelectorStore } from "@/store/modules/selectors";
import { useEbpfStore } from "@/store/modules/ebpf";
import dateFormatStep from "@/utils/dateFormat";
import getLocalTime from "@/utils/localtime";
import { TargetTypes } from "@/views/dashboard/related/continuous-profiling/data";
interface taskTimelineState {
loading: boolean;
taskList: EBPFTaskList[];
selectedTask: Recordable<EBPFTaskList>;
}
export const taskTimelineStore = defineStore({
id: "taskTimeline",
state: (): taskTimelineState => ({
loading: false,
taskList: [],
selectedTask: {},
}),
actions: {
setSelectedTask(task: Recordable<EBPFTaskList>) {
this.selectedTask = task || {};
},
setTaskList(list: EBPFTaskList[]) {
this.taskList = list;
},
async getContinousTaskList(params: {
serviceId: string;
serviceInstanceId: string;
targets: string[];
triggerType: string;
}) {
if (!params.serviceId) {
return new Promise((resolve) => resolve({}));
}
this.loading = true;
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
this.loading = false;
this.errorTip = "";
if (res.data.errors) {
return res.data;
}
this.taskList = res.data.data.queryEBPFTasks || [];
// this.selectedTask = this.taskList[0] || {};
// await this.getGraphData();
return res.data;
},
async getGraphData() {
let res: any = {};
if (this.selectedTask.targetType === TargetTypes[2].value) {
res = await this.getTopology();
} else {
const ebpfStore = useEbpfStore();
res = await ebpfStore.getEBPFSchedules({
taskId: this.selectedTask.taskId,
});
}
if (res.errors) {
ElMessage.error(res.errors);
}
},
async getTopology() {
const networkProfilingStore = useNetworkProfilingStore();
const appStore = useAppStoreWithOut();
const selectorStore = useSelectorStore();
networkProfilingStore.setSelectedNetworkTask(this.selectedTask);
const { taskStartTime, fixedTriggerDuration } = this.selectedTask;
const startTime =
fixedTriggerDuration > 1800 ? taskStartTime + fixedTriggerDuration * 1000 - 30 * 60 * 1000 : taskStartTime;
let endTime = taskStartTime + fixedTriggerDuration * 1000;
if (taskStartTime + fixedTriggerDuration * 1000 > new Date().getTime()) {
endTime = new Date().getTime();
}
const resp = await networkProfilingStore.getProcessTopology({
serviceInstanceId: (selectorStore.currentPod || {}).id || "",
duration: {
start: dateFormatStep(getLocalTime(appStore.utc, new Date(startTime)), appStore.duration.step, true),
end: dateFormatStep(getLocalTime(appStore.utc, new Date(endTime)), appStore.duration.step, true),
step: appStore.duration.step,
},
});
if (resp.errors) {
ElMessage.error(resp.errors);
}
return resp;
},
async preAnalyzeTask() {
if (this.selectedStrategy.type === "NETWORK") {
const networkProfilingStore = useNetworkProfilingStore();
await networkProfilingStore.setSelectedNetworkTask(this.selectedTask);
return;
}
const res = await this.getEBPFSchedules({
taskId: this.selectedTask.taskId,
});
if (res.errors) {
ElMessage.error(res.errors);
}
},
},
});
export function useTaskTimelineStore(): Recordable {
return taskTimelineStore(store);
}