mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-07-18 18:05:25 +00:00
add ebpf
This commit is contained in:
parent
91aeb45604
commit
493ec4bec2
@ -32,7 +32,7 @@ interface Option {
|
|||||||
const emit = defineEmits(["change"]);
|
const emit = defineEmits(["change"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
options: {
|
options: {
|
||||||
type: Array as PropType<(Option & { disabled: boolean })[]>,
|
type: Array as PropType<Option[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
@ -44,7 +44,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const selected = ref<string>(props.value);
|
const selected = ref<string>(props.value);
|
||||||
|
|
||||||
function checked(opt: string) {
|
function checked(opt: unknown) {
|
||||||
emit("change", opt);
|
emit("change", opt);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -0,0 +1,227 @@
|
|||||||
|
/**
|
||||||
|
* 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 { Duration, Option } from "@/types/app";
|
||||||
|
import { Endpoint } from "@/types/selector";
|
||||||
|
import {
|
||||||
|
TaskListItem,
|
||||||
|
SegmentSpan,
|
||||||
|
ProfileAnalyzationTrees,
|
||||||
|
TaskLog,
|
||||||
|
ProfileTaskCreationRequest,
|
||||||
|
} from "@/types/profile";
|
||||||
|
import { Trace, Span } from "@/types/trace";
|
||||||
|
import { store } from "@/store";
|
||||||
|
import graphql from "@/graphql";
|
||||||
|
import { AxiosResponse } from "axios";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
|
interface EbpfStore {
|
||||||
|
endpoints: Endpoint[];
|
||||||
|
taskEndpoints: Endpoint[];
|
||||||
|
durationTime: Duration;
|
||||||
|
condition: { serviceId: string; endpointName: string };
|
||||||
|
taskList: TaskListItem[];
|
||||||
|
segmentList: Trace[];
|
||||||
|
currentSegment: Trace | Record<string, never>;
|
||||||
|
segmentSpans: SegmentSpan[];
|
||||||
|
currentSpan: SegmentSpan | Record<string, never>;
|
||||||
|
analyzeTrees: ProfileAnalyzationTrees;
|
||||||
|
taskLogs: TaskLog[];
|
||||||
|
highlightTop: boolean;
|
||||||
|
labels: Option[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ebpfStore = defineStore({
|
||||||
|
id: "profile",
|
||||||
|
state: (): EbpfStore => ({
|
||||||
|
endpoints: [{ value: "", label: "All" }],
|
||||||
|
taskEndpoints: [{ value: "", label: "All" }],
|
||||||
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
|
condition: { serviceId: "", endpointName: "" },
|
||||||
|
taskList: [],
|
||||||
|
segmentList: [],
|
||||||
|
currentSegment: {},
|
||||||
|
segmentSpans: [],
|
||||||
|
currentSpan: {},
|
||||||
|
analyzeTrees: [],
|
||||||
|
taskLogs: [],
|
||||||
|
highlightTop: true,
|
||||||
|
labels: [{ value: "", label: "" }],
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
setConditions(data: { serviceId?: string; endpointName?: string }) {
|
||||||
|
this.condition = {
|
||||||
|
...this.condition,
|
||||||
|
...data,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
setCurrentSpan(span: Span) {
|
||||||
|
this.currentSpan = span;
|
||||||
|
},
|
||||||
|
setCurrentSegment(s: Trace) {
|
||||||
|
this.currentSegment = s;
|
||||||
|
},
|
||||||
|
setHighlightTop() {
|
||||||
|
this.highlightTop = !this.highlightTop;
|
||||||
|
},
|
||||||
|
async getEndpoints(serviceId: string, keyword?: string) {
|
||||||
|
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||||
|
serviceId,
|
||||||
|
duration: this.durationTime,
|
||||||
|
keyword: keyword || "",
|
||||||
|
});
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getTaskEndpoints(serviceId: string, keyword?: string) {
|
||||||
|
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||||
|
serviceId,
|
||||||
|
duration: this.durationTime,
|
||||||
|
keyword: keyword || "",
|
||||||
|
});
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskEndpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getTaskList() {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getProfileTaskList")
|
||||||
|
.params(this.condition);
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const list = res.data.data.taskList;
|
||||||
|
this.taskList = list;
|
||||||
|
if (!list.length) {
|
||||||
|
this.segmentList = [];
|
||||||
|
this.segmentSpans = [];
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.getSegmentList({ taskID: list[0].id });
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getSegmentList(params: { taskID: string }) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getProfileTaskSegmentList")
|
||||||
|
.params(params);
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
this.segmentList = [];
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const { segmentList } = res.data.data;
|
||||||
|
|
||||||
|
this.segmentList = segmentList;
|
||||||
|
if (!segmentList.length) {
|
||||||
|
this.segmentSpans = [];
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
if (segmentList[0]) {
|
||||||
|
this.currentSegment = segmentList[0];
|
||||||
|
this.getSegmentSpans({ segmentId: segmentList[0].segmentId });
|
||||||
|
} else {
|
||||||
|
this.currentSegment = null;
|
||||||
|
}
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getSegmentSpans(params: { segmentId: string }) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("queryProfileSegment")
|
||||||
|
.params(params);
|
||||||
|
if (res.data.errors) {
|
||||||
|
this.segmentSpans = [];
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const { segment } = res.data.data;
|
||||||
|
if (!segment) {
|
||||||
|
this.segmentSpans = [];
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.segmentSpans = segment.spans;
|
||||||
|
if (!(segment.spans && segment.spans.length)) {
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const index = segment.spans.length - 1 || 0;
|
||||||
|
this.currentSpan = segment.spans[index];
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getProfileAnalyze(params: {
|
||||||
|
segmentId: string;
|
||||||
|
timeRanges: Array<{ start: number; end: number }>;
|
||||||
|
}) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getProfileAnalyze")
|
||||||
|
.params(params);
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const { analyze, tip } = res.data.data;
|
||||||
|
if (tip) {
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!analyze) {
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.analyzeTrees = analyze.trees;
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async createTask(param: ProfileTaskCreationRequest) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("saveProfileTask")
|
||||||
|
.params({ creationRequest: param });
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.getTaskList();
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getTaskLogs(param: { taskID: string }) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getProfileTaskLogs")
|
||||||
|
.params(param);
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskLogs = res.data.data.taskLogs;
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useEbpfStore(): any {
|
||||||
|
return ebpfStore(store);
|
||||||
|
}
|
@ -32,6 +32,7 @@ import { useAppStoreWithOut } from "@/store/modules/app";
|
|||||||
|
|
||||||
interface ProfileState {
|
interface ProfileState {
|
||||||
endpoints: Endpoint[];
|
endpoints: Endpoint[];
|
||||||
|
taskEndpoints: Endpoint[];
|
||||||
durationTime: Duration;
|
durationTime: Duration;
|
||||||
condition: { serviceId: string; endpointName: string };
|
condition: { serviceId: string; endpointName: string };
|
||||||
taskList: TaskListItem[];
|
taskList: TaskListItem[];
|
||||||
@ -48,6 +49,7 @@ export const profileStore = defineStore({
|
|||||||
id: "profile",
|
id: "profile",
|
||||||
state: (): ProfileState => ({
|
state: (): ProfileState => ({
|
||||||
endpoints: [{ value: "", label: "All" }],
|
endpoints: [{ value: "", label: "All" }],
|
||||||
|
taskEndpoints: [{ value: "", label: "All" }],
|
||||||
durationTime: useAppStoreWithOut().durationTime,
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
condition: { serviceId: "", endpointName: "" },
|
condition: { serviceId: "", endpointName: "" },
|
||||||
taskList: [],
|
taskList: [],
|
||||||
@ -87,6 +89,18 @@ export const profileStore = defineStore({
|
|||||||
this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
async getTaskEndpoints(serviceId: string, keyword?: string) {
|
||||||
|
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||||
|
serviceId,
|
||||||
|
duration: this.durationTime,
|
||||||
|
keyword: keyword || "",
|
||||||
|
});
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskEndpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
async getTaskList() {
|
async getTaskList() {
|
||||||
const res: AxiosResponse = await graphql
|
const res: AxiosResponse = await graphql
|
||||||
.query("getProfileTaskList")
|
.query("getProfileTaskList")
|
||||||
|
@ -37,8 +37,8 @@ limitations under the License. -->
|
|||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import Header from "../related/profile/Header.vue";
|
import Header from "../related/ebpf/Header.vue";
|
||||||
import Content from "../related/profile/Content.vue";
|
import Content from "../related/ebpf/Content.vue";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
|
@ -122,6 +122,7 @@ import Trace from "./Trace.vue";
|
|||||||
import Profile from "./Profile.vue";
|
import Profile from "./Profile.vue";
|
||||||
import Log from "./Log.vue";
|
import Log from "./Log.vue";
|
||||||
import Text from "./Text.vue";
|
import Text from "./Text.vue";
|
||||||
|
import Ebpf from "./Ebpf.vue";
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
@ -132,7 +133,7 @@ const props = {
|
|||||||
};
|
};
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Tab",
|
name: "Tab",
|
||||||
components: { Topology, Widget, Trace, Profile, Log, Text },
|
components: { Topology, Widget, Trace, Profile, Log, Text, Ebpf },
|
||||||
props,
|
props,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
@ -21,5 +21,6 @@ import Trace from "./Trace.vue";
|
|||||||
import Profile from "./Profile.vue";
|
import Profile from "./Profile.vue";
|
||||||
import Log from "./Log.vue";
|
import Log from "./Log.vue";
|
||||||
import Text from "./Text.vue";
|
import Text from "./Text.vue";
|
||||||
|
import Ebpf from "./Ebpf.vue";
|
||||||
|
|
||||||
export default { Tab, Widget, Trace, Topology, Profile, Log, Text };
|
export default { Tab, Widget, Trace, Topology, Profile, Log, Text, Ebpf };
|
||||||
|
17
src/views/dashboard/related/ebpf/Content.vue
Normal file
17
src/views/dashboard/related/ebpf/Content.vue
Normal 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. -->
|
||||||
|
<template>
|
||||||
|
<div>content</div>
|
||||||
|
</template>
|
133
src/views/dashboard/related/ebpf/Header.vue
Normal file
133
src/views/dashboard/related/ebpf/Header.vue
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<!-- 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. -->
|
||||||
|
<template>
|
||||||
|
<div class="flex-h header">
|
||||||
|
<div class="mr-10">
|
||||||
|
<span class="grey mr-5">{{ t("endpointName") }}:</span>
|
||||||
|
<Selector
|
||||||
|
class="name"
|
||||||
|
size="small"
|
||||||
|
:value="endpointName"
|
||||||
|
:options="ebpfStore.endpoints"
|
||||||
|
placeholder="Select a endpoint"
|
||||||
|
:isRemote="true"
|
||||||
|
@change="changeEndpoint"
|
||||||
|
@query="searchEndpoints"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<el-button
|
||||||
|
class="search-btn"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="searchTasks"
|
||||||
|
>
|
||||||
|
{{ t("search") }}
|
||||||
|
</el-button>
|
||||||
|
<el-button class="search-btn" size="small" @click="createTask">
|
||||||
|
{{ t("newTask") }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
<el-dialog
|
||||||
|
v-model="newTask"
|
||||||
|
:destroy-on-close="true"
|
||||||
|
fullscreen
|
||||||
|
@closed="newTask = false"
|
||||||
|
>
|
||||||
|
<NewTask @close="newTask = false" />
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import NewTask from "./components/NewTask.vue";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { EntityType } from "../../data";
|
||||||
|
|
||||||
|
const ebpfStore = useEbpfStore();
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const endpointName = ref<string>("");
|
||||||
|
const newTask = ref<boolean>(false);
|
||||||
|
|
||||||
|
searchTasks();
|
||||||
|
searchEndpoints("");
|
||||||
|
|
||||||
|
async function searchEndpoints(keyword: string) {
|
||||||
|
if (!selectorStore.currentService) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const service = selectorStore.currentService.value;
|
||||||
|
const res = await ebpfStore.getEndpoints(service, keyword);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
endpointName.value = ebpfStore.endpoints[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeEndpoint(opt: any[]) {
|
||||||
|
endpointName.value = opt[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function searchTasks() {
|
||||||
|
ebpfStore.setConditions({
|
||||||
|
serviceId:
|
||||||
|
(selectorStore.currentService && selectorStore.currentService.id) || "",
|
||||||
|
endpointName: endpointName.value,
|
||||||
|
});
|
||||||
|
const res = await ebpfStore.getTaskList();
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTask() {
|
||||||
|
newTask.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => selectorStore.currentService,
|
||||||
|
() => {
|
||||||
|
searchTasks();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => appStore.durationTime,
|
||||||
|
() => {
|
||||||
|
if (dashboardStore.entity === EntityType[1].value) {
|
||||||
|
searchTasks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
width: 270px;
|
||||||
|
}
|
||||||
|
</style>
|
203
src/views/dashboard/related/ebpf/components/NewTask.vue
Normal file
203
src/views/dashboard/related/ebpf/components/NewTask.vue
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<!-- 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. -->
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="profile-task">
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("endpointName") }}</div>
|
||||||
|
<Selector
|
||||||
|
class="profile-input"
|
||||||
|
size="small"
|
||||||
|
:value="endpointName"
|
||||||
|
:options="eBPFStore.taskEndpoints"
|
||||||
|
placeholder="Select a endpoint"
|
||||||
|
:isRemote="true"
|
||||||
|
@change="changeEndpoint"
|
||||||
|
@query="searchEndpoints"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("monitorTime") }}</div>
|
||||||
|
<div>
|
||||||
|
<Radio
|
||||||
|
class="mb-5"
|
||||||
|
:value="monitorTime"
|
||||||
|
:options="InitTaskField.monitorTimeEn"
|
||||||
|
@change="changeMonitorTime"
|
||||||
|
/>
|
||||||
|
<span class="date">
|
||||||
|
<TimePicker
|
||||||
|
:value="time"
|
||||||
|
position="bottom"
|
||||||
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
@input="changeTimeRange"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("monitorDuration") }}</div>
|
||||||
|
<Radio
|
||||||
|
class="mb-5"
|
||||||
|
:value="monitorDuration"
|
||||||
|
:options="InitTaskField.monitorDuration"
|
||||||
|
@change="changeMonitorDuration"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("minThreshold") }} (ms)</div>
|
||||||
|
<el-input-number
|
||||||
|
size="small"
|
||||||
|
class="profile-input"
|
||||||
|
:min="0"
|
||||||
|
v-model="minThreshold"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("dumpPeriod") }}</div>
|
||||||
|
<Radio
|
||||||
|
class="mb-5"
|
||||||
|
:value="dumpPeriod"
|
||||||
|
:options="InitTaskField.dumpPeriod"
|
||||||
|
@change="changeDumpPeriod"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("maxSamplingCount") }}</div>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
:value="maxSamplingCount"
|
||||||
|
:options="InitTaskField.maxSamplingCount"
|
||||||
|
placeholder="Select a data"
|
||||||
|
@change="changeMaxSamplingCount"
|
||||||
|
class="profile-input"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button @click="createTask" type="primary" class="create-task-btn">
|
||||||
|
{{ t("createTask") }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { InitTaskField } from "./data";
|
||||||
|
/* global defineEmits */
|
||||||
|
const emits = defineEmits(["close"]);
|
||||||
|
const eBPFStore = useEbpfStore();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const endpointName = ref<string>("");
|
||||||
|
const monitorTime = ref<string>(InitTaskField.monitorTimeEn[0].value);
|
||||||
|
const monitorDuration = ref<string>(InitTaskField.monitorDuration[0].value);
|
||||||
|
const time = ref<Date>(appStore.durationRow.start);
|
||||||
|
const minThreshold = ref<number>(0);
|
||||||
|
const dumpPeriod = ref<string>(InitTaskField.dumpPeriod[0].value);
|
||||||
|
const maxSamplingCount = ref<string>(InitTaskField.maxSamplingCount[0].value);
|
||||||
|
|
||||||
|
async function searchEndpoints(keyword: string) {
|
||||||
|
if (!selectorStore.currentService) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const service = selectorStore.currentService.value;
|
||||||
|
const res = await eBPFStore.getEndpoints(service, keyword);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
endpointName.value = eBPFStore.taskEndpoints[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeMonitorTime(opt: string) {
|
||||||
|
monitorTime.value = opt;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeMonitorDuration(val: string) {
|
||||||
|
monitorDuration.value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDumpPeriod(val: string) {
|
||||||
|
dumpPeriod.value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeMaxSamplingCount(opt: any[]) {
|
||||||
|
maxSamplingCount.value = opt[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeEndpoint(opt: any[]) {
|
||||||
|
endpointName.value = opt[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createTask() {
|
||||||
|
emits("close");
|
||||||
|
const date =
|
||||||
|
monitorTime.value === "0" ? appStore.durationRow.start : time.value;
|
||||||
|
const params = {
|
||||||
|
serviceId: selectorStore.currentService.id,
|
||||||
|
endpointName: endpointName.value,
|
||||||
|
startTime: date.getTime(),
|
||||||
|
duration: Number(monitorDuration.value),
|
||||||
|
minDurationThreshold: Number(minThreshold.value),
|
||||||
|
dumpPeriod: Number(dumpPeriod.value),
|
||||||
|
maxSamplingCount: Number(maxSamplingCount.value),
|
||||||
|
};
|
||||||
|
const res = await eBPFStore.createTask(params);
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { tip } = res.data;
|
||||||
|
if (tip) {
|
||||||
|
ElMessage.error(tip);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ElMessage.success("Task created successfully");
|
||||||
|
}
|
||||||
|
function changeTimeRange(val: Date) {
|
||||||
|
time.value = val;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-task {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-input {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-task-btn {
|
||||||
|
width: 300px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
63
src/views/dashboard/related/ebpf/components/data.ts
Normal file
63
src/views/dashboard/related/ebpf/components/data.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
export const ProfileMode: any[] = [
|
||||||
|
{ label: "Include Children", value: "include" },
|
||||||
|
{ label: "Exclude Children", value: "exclude" },
|
||||||
|
];
|
||||||
|
export const NewTaskField = {
|
||||||
|
service: { key: "", label: "None" },
|
||||||
|
monitorTime: { key: "0", label: "monitor now" },
|
||||||
|
monitorDuration: { key: 5, label: "5 min" },
|
||||||
|
minThreshold: 0,
|
||||||
|
dumpPeriod: { key: 10, label: "10ms" },
|
||||||
|
endpointName: "",
|
||||||
|
maxSamplingCount: { key: 5, label: "5" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InitTaskField = {
|
||||||
|
serviceSource: [{ key: "", label: "None" }],
|
||||||
|
monitorTimeEn: [
|
||||||
|
{ value: "0", label: "monitor now" },
|
||||||
|
{ value: "1", label: "set start time" },
|
||||||
|
],
|
||||||
|
monitorTimeCn: [
|
||||||
|
{ value: "0", label: "此刻" },
|
||||||
|
{ value: "1", label: "设置时间" },
|
||||||
|
],
|
||||||
|
monitorDuration: [
|
||||||
|
{ value: "5", label: "5 min" },
|
||||||
|
{ value: "10", label: "10 min" },
|
||||||
|
{ value: "15", label: "15 min" },
|
||||||
|
],
|
||||||
|
dumpPeriod: [
|
||||||
|
{ value: "10", label: "10 ms" },
|
||||||
|
{ value: "20", label: "20 ms" },
|
||||||
|
{ value: "50", label: "50 ms" },
|
||||||
|
{ value: "100", label: "100 ms" },
|
||||||
|
],
|
||||||
|
maxSamplingCount: [
|
||||||
|
{ value: "1", label: "1" },
|
||||||
|
{ value: "2", label: "2" },
|
||||||
|
{ value: "3", label: "3" },
|
||||||
|
{ value: "4", label: "4" },
|
||||||
|
{ value: "5", label: "5" },
|
||||||
|
{ value: "6", label: "6" },
|
||||||
|
{ value: "7", label: "7" },
|
||||||
|
{ value: "8", label: "8" },
|
||||||
|
{ value: "9", label: "9" },
|
||||||
|
],
|
||||||
|
};
|
@ -17,7 +17,16 @@ limitations under the License. -->
|
|||||||
<div class="profile-task">
|
<div class="profile-task">
|
||||||
<div>
|
<div>
|
||||||
<div class="label">{{ t("endpointName") }}</div>
|
<div class="label">{{ t("endpointName") }}</div>
|
||||||
<el-input v-model="endpointName" class="profile-input" size="small" />
|
<Selector
|
||||||
|
class="profile-input"
|
||||||
|
size="small"
|
||||||
|
:value="endpointName"
|
||||||
|
:options="profileStore.taskEndpoints"
|
||||||
|
placeholder="Select a endpoint"
|
||||||
|
:isRemote="true"
|
||||||
|
@change="changeEndpoint"
|
||||||
|
@query="searchEndpoints"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="label">{{ t("monitorTime") }}</div>
|
<div class="label">{{ t("monitorTime") }}</div>
|
||||||
@ -105,6 +114,20 @@ const minThreshold = ref<number>(0);
|
|||||||
const dumpPeriod = ref<string>(InitTaskField.dumpPeriod[0].value);
|
const dumpPeriod = ref<string>(InitTaskField.dumpPeriod[0].value);
|
||||||
const maxSamplingCount = ref<string>(InitTaskField.maxSamplingCount[0].value);
|
const maxSamplingCount = ref<string>(InitTaskField.maxSamplingCount[0].value);
|
||||||
|
|
||||||
|
async function searchEndpoints(keyword: string) {
|
||||||
|
if (!selectorStore.currentService) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const service = selectorStore.currentService.value;
|
||||||
|
const res = await profileStore.getEndpoints(service, keyword);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
endpointName.value = profileStore.taskEndpoints[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
function changeMonitorTime(opt: string) {
|
function changeMonitorTime(opt: string) {
|
||||||
monitorTime.value = opt;
|
monitorTime.value = opt;
|
||||||
}
|
}
|
||||||
@ -121,6 +144,10 @@ function changeMaxSamplingCount(opt: any[]) {
|
|||||||
maxSamplingCount.value = opt[0].value;
|
maxSamplingCount.value = opt[0].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeEndpoint(opt: any[]) {
|
||||||
|
endpointName.value = opt[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
async function createTask() {
|
async function createTask() {
|
||||||
emits("close");
|
emits("close");
|
||||||
const date =
|
const date =
|
||||||
@ -153,7 +180,7 @@ function changeTimeRange(val: Date) {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.profile-task {
|
.profile-task {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 350px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
|
Loading…
Reference in New Issue
Block a user