mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-07 18:52:54 +00:00
Compare commits
50 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0c2cfa5630 | ||
![]() |
5e6e5aa737 | ||
![]() |
a4cd265d45 | ||
![]() |
0ef6b57cae | ||
![]() |
687ae07bb0 | ||
![]() |
0775bf0034 | ||
![]() |
5c322d960f | ||
![]() |
df2d07f508 | ||
![]() |
105450071e | ||
![]() |
39b4626317 | ||
![]() |
0ea8335fee | ||
![]() |
0d2bedf529 | ||
![]() |
b525f84fa0 | ||
![]() |
1fe58f5f6c | ||
![]() |
012ae1db6c | ||
![]() |
79ec865ee7 | ||
![]() |
9ab8ac44bc | ||
![]() |
7a690e6704 | ||
![]() |
65607a5540 | ||
![]() |
5bb4218bfe | ||
![]() |
2b6f3ecaa8 | ||
![]() |
2246a9a045 | ||
![]() |
9318d32b0b | ||
![]() |
8ea50c8680 | ||
![]() |
55b3867bea | ||
![]() |
c33d6c4180 | ||
![]() |
70ea9fd06f | ||
![]() |
2fca7a79a2 | ||
![]() |
f5cfb030a3 | ||
![]() |
fbeeca8d9a | ||
![]() |
ea0f5e5f62 | ||
![]() |
8771ce4a19 | ||
![]() |
99a2461734 | ||
![]() |
fb0817eed8 | ||
![]() |
e164d87209 | ||
![]() |
5c92a46569 | ||
![]() |
aff69c057f | ||
![]() |
7338cec6b4 | ||
![]() |
536df8c052 | ||
![]() |
64d4a2b59b | ||
![]() |
6e1a6cf19b | ||
![]() |
aeddb39637 | ||
![]() |
14fa5d65b6 | ||
![]() |
224e761d70 | ||
![]() |
4c60f69aef | ||
![]() |
0007e3e3ae | ||
![]() |
b6522f4555 | ||
![]() |
bddbe40974 | ||
![]() |
61449f4b17 | ||
![]() |
a92365efcf |
2
.github/workflows/nodejs.yml
vendored
2
.github/workflows/nodejs.yml
vendored
@ -37,7 +37,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [16.x, 18.x, 20.x]
|
node-version: [18.x, 20.x, 22.x]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
- name: Use Node.js ${{ matrix.node-version }}
|
- name: Use Node.js ${{ matrix.node-version }}
|
||||||
|
7514
package-lock.json
generated
7514
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
23
package.json
23
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "skywalking-booster-ui",
|
"name": "skywalking-booster-ui",
|
||||||
"version": "9.4.0",
|
"version": "10.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
@ -18,19 +18,17 @@
|
|||||||
"check-components-types": "if (! git diff --quiet -U0 ./src/types); then echo 'type files are not updated correctly'; git diff -U0 ./src/types; exit 1; fi"
|
"check-components-types": "if (! git diff --quiet -U0 ./src/types); then echo 'type files are not updated correctly'; git diff -U0 ./src/types; exit 1; fi"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.7.5",
|
|
||||||
"d3": "^7.3.0",
|
"d3": "^7.3.0",
|
||||||
"d3-flame-graph": "^4.1.3",
|
"d3-flame-graph": "^4.1.3",
|
||||||
"d3-tip": "^0.9.1",
|
"d3-tip": "^0.9.1",
|
||||||
"echarts": "^5.2.2",
|
"echarts": "^5.2.2",
|
||||||
"element-plus": "^2.2.5",
|
"element-plus": "^2.9.4",
|
||||||
"lodash": "^4.17.21",
|
|
||||||
"monaco-editor": "^0.34.1",
|
"monaco-editor": "^0.34.1",
|
||||||
"pinia": "^2.0.28",
|
"pinia": "^2.0.28",
|
||||||
"vis-timeline": "^7.5.1",
|
"vis-timeline": "^7.5.1",
|
||||||
"vue": "^3.2.45",
|
"vue": "^3.2.45",
|
||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.14.3",
|
||||||
"vue-router": "^4.1.6",
|
"vue-router": "^4.1.6",
|
||||||
"vue-types": "^4.1.1"
|
"vue-types": "^4.1.1"
|
||||||
},
|
},
|
||||||
@ -42,11 +40,10 @@
|
|||||||
"@types/d3-tip": "^3.5.5",
|
"@types/d3-tip": "^3.5.5",
|
||||||
"@types/echarts": "^4.9.12",
|
"@types/echarts": "^4.9.12",
|
||||||
"@types/jsdom": "^20.0.1",
|
"@types/jsdom": "^20.0.1",
|
||||||
"@types/lodash": "^4.14.179",
|
|
||||||
"@types/node": "^18.11.12",
|
"@types/node": "^18.11.12",
|
||||||
"@types/three": "^0.131.0",
|
"@types/three": "^0.131.0",
|
||||||
"@vitejs/plugin-vue": "^4.0.0",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||||
"@vue/eslint-config-prettier": "^7.0.0",
|
"@vue/eslint-config-prettier": "^7.0.0",
|
||||||
"@vue/eslint-config-typescript": "^11.0.0",
|
"@vue/eslint-config-typescript": "^11.0.0",
|
||||||
"@vue/test-utils": "^2.2.6",
|
"@vue/test-utils": "^2.2.6",
|
||||||
@ -64,21 +61,21 @@
|
|||||||
"postcss-html": "^1.3.0",
|
"postcss-html": "^1.3.0",
|
||||||
"postcss-scss": "^4.0.2",
|
"postcss-scss": "^4.0.2",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"sass": "^1.56.1",
|
"sass": "^1.85.0",
|
||||||
"start-server-and-test": "^2.0.5",
|
"start-server-and-test": "^2.0.5",
|
||||||
"stylelint": "15.9.0",
|
"stylelint": "15.9.0",
|
||||||
"stylelint-config-html": "^1.0.0",
|
"stylelint-config-html": "^1.0.0",
|
||||||
"stylelint-config-prettier": "9.0.4",
|
"stylelint-config-prettier": "9.0.4",
|
||||||
"stylelint-config-standard": "^33.0.0",
|
"stylelint-config-standard": "^33.0.0",
|
||||||
"stylelint-order": "^6.0.3",
|
"stylelint-order": "^6.0.3",
|
||||||
"typescript": "~4.7.4",
|
"typescript": "^5.7.3",
|
||||||
"unplugin-auto-import": "^0.18.2",
|
"unplugin-auto-import": "^0.18.2",
|
||||||
"unplugin-vue-components": "^0.27.3",
|
"unplugin-vue-components": "^0.27.3",
|
||||||
"vite": "^4.5.3",
|
"vite": "^6.3.4",
|
||||||
"vite-plugin-monaco-editor": "^1.1.0",
|
"vite-plugin-monaco-editor": "^1.1.0",
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vitest": "^0.25.6",
|
"vitest": "^3.0.5",
|
||||||
"vue-tsc": "^1.8.27"
|
"vue-tsc": "^2.2.2"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
|
18
src/assets/icons/async_profiling.svg
Normal file
18
src/assets/icons/async_profiling.svg
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<!-- 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 class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M512 992c-83.2 0-166.4-19.2-243.2-64-89.6-51.2-160-134.4-204.8-230.4C25.6 601.6 19.2 486.4 51.2 390.4c25.6-102.4 89.6-192 172.8-256C307.2 70.4 409.6 38.4 518.4 38.4c19.2 0 32 12.8 32 32s-19.2 25.6-38.4 25.6c-89.6 0-179.2 32-256 83.2S128 313.6 108.8 403.2s-12.8 185.6 19.2 268.8c32 83.2 96 153.6 179.2 198.4 76.8 44.8 172.8 64 262.4 51.2 89.6-12.8 172.8-51.2 236.8-115.2s108.8-147.2 115.2-236.8c12.8-89.6-6.4-185.6-51.2-262.4-6.4-12.8-6.4-32 12.8-44.8 12.8-12.8 38.4-6.4 44.8 12.8 51.2 89.6 76.8 198.4 57.6 300.8-12.8 102.4-64 204.8-134.4 275.2-76.8 76.8-172.8 121.6-275.2 134.4-19.2 6.4-44.8 6.4-64 6.4z" p-id="8538"></path><path d="M512 480c-19.2 0-32-12.8-32-32V64c0-19.2 12.8-32 32-32s32 12.8 32 32v384c0 19.2-12.8 32-32 32z" p-id="8539"></path><path d="M512 608c-12.8 0-25.6 0-38.4-6.4-12.8-6.4-19.2-12.8-32-19.2-6.4-12.8-12.8-19.2-19.2-32-6.4-12.8-6.4-25.6-6.4-38.4 0-25.6 12.8-51.2 25.6-70.4 38.4-38.4 102.4-38.4 134.4 0 19.2 19.2 32 44.8 32 70.4 0 25.6-12.8 51.2-25.6 70.4-19.2 12.8-44.8 25.6-70.4 25.6z m0-128c-6.4 0-19.2 6.4-25.6 6.4 0 6.4-6.4 19.2-6.4 25.6v12.8c0 6.4 6.4 6.4 6.4 12.8 0 0 6.4 6.4 12.8 6.4 12.8 6.4 25.6 0 32-6.4 6.4-6.4 12.8-19.2 12.8-25.6 0-6.4-6.4-19.2-6.4-25.6-6.4 0-19.2-6.4-25.6-6.4z" p-id="8540"></path><path d="M512 800c-51.2 0-102.4-12.8-147.2-38.4-57.6-32-96-83.2-121.6-140.8-19.2-57.6-25.6-121.6-6.4-185.6 19.2-64 51.2-115.2 102.4-153.6C384 243.2 448 224 512 224c19.2 0 32 12.8 32 32s-12.8 32-32 32c-51.2 0-96 19.2-134.4 44.8-38.4 32-70.4 76.8-83.2 121.6s-6.4 96 12.8 140.8c19.2 44.8 51.2 83.2 96 108.8 44.8 25.6 89.6 32 140.8 25.6 51.2-6.4 96-32 128-64s57.6-83.2 64-128c6.4-51.2-6.4-96-25.6-140.8-12.8-12.8-6.4-32 6.4-38.4 12.8-6.4 32-6.4 44.8 12.8 32 57.6 44.8 121.6 38.4 179.2-6.4 64-38.4 121.6-83.2 166.4-44.8 44.8-102.4 76.8-166.4 83.2H512z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
38
src/assets/icons/data_processing_engine.svg
Normal file
38
src/assets/icons/data_processing_engine.svg
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<!-- 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 width="2400" height="2400" viewBox="0 0 200 100" version="1.1" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
|
||||||
|
<defs>
|
||||||
|
<marker id="arrowhead" markerWidth="8" markerHeight="8" refX="2" refY="2.5" orient="auto">
|
||||||
|
<polygon points="0 0, 3 2.5, 0 5" fill="white" />
|
||||||
|
</marker>
|
||||||
|
</defs>
|
||||||
|
|
||||||
|
<line x1="0" y1="20" x2="42" y2="20" stroke="white" stroke-width="7" marker-end="url(#arrowhead)" />
|
||||||
|
<line x1="0" y1="50" x2="42" y2="50" stroke="white" stroke-width="7" marker-end="url(#arrowhead)" />
|
||||||
|
<line x1="0" y1="80" x2="42" y2="80" stroke="white" stroke-width="7" marker-end="url(#arrowhead)" />
|
||||||
|
|
||||||
|
|
||||||
|
<line x1="49" y1="10" x2="139" y2="10" stroke="white" stroke-width="7" />
|
||||||
|
<line x1="49" y1="90" x2="139" y2="90" stroke="white" stroke-width="7" />
|
||||||
|
<line x1="49" y1="10" x2="50" y2="90" stroke="white" stroke-width="7" />
|
||||||
|
|
||||||
|
<ellipse cx="140" cy="50" rx="10" ry="40" fill="none" stroke="white" stroke-width="7" />
|
||||||
|
|
||||||
|
<line x1="147" y1="20" x2="190" y2="20" stroke="white" stroke-width="7" marker-end="url(#arrowhead)" />
|
||||||
|
<line x1="149" y1="50" x2="190" y2="50" stroke="white" stroke-width="7" marker-end="url(#arrowhead)" />
|
||||||
|
<line x1="147" y1="80" x2="190" y2="80" stroke="white" stroke-width="7" marker-end="url(#arrowhead)" />
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -13,6 +13,13 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
|
<SelectorLegend
|
||||||
|
:data="option.legend.data"
|
||||||
|
:show="legendSelector.isSelector"
|
||||||
|
:isConfigPage="legendSelector.isConfigPage"
|
||||||
|
:colors="option.color"
|
||||||
|
@change="changeLegend"
|
||||||
|
/>
|
||||||
<div class="chart" ref="chartRef" :style="`height:${height};width:${width};`">
|
<div class="chart" ref="chartRef" :style="`height:${height};width:${width};`">
|
||||||
<div v-if="!available" class="no-data">No Data</div>
|
<div v-if="!available" class="no-data">No Data</div>
|
||||||
<div
|
<div
|
||||||
@ -54,6 +61,7 @@ limitations under the License. -->
|
|||||||
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
||||||
import associateProcessor from "@/hooks/useAssociateProcessor";
|
import associateProcessor from "@/hooks/useAssociateProcessor";
|
||||||
import { WidgetType } from "@/views/dashboard/data";
|
import { WidgetType } from "@/views/dashboard/data";
|
||||||
|
import SelectorLegend from "./Legend.vue";
|
||||||
|
|
||||||
/*global Nullable, defineProps, defineEmits, Indexable*/
|
/*global Nullable, defineProps, defineEmits, Indexable*/
|
||||||
const emits = defineEmits(["select"]);
|
const emits = defineEmits(["select"]);
|
||||||
@ -84,6 +92,10 @@ limitations under the License. -->
|
|||||||
type: Array as PropType<{ widgetId: string }[]>,
|
type: Array as PropType<{ widgetId: string }[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
|
legendSelector: {
|
||||||
|
type: Object as PropType<Indexable>,
|
||||||
|
default: () => ({ isConfigPage: false, isSelector: false }),
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const available = computed(
|
const available = computed(
|
||||||
() =>
|
() =>
|
||||||
@ -103,6 +115,7 @@ limitations under the License. -->
|
|||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
instance.on("click", (params: EventParams) => {
|
instance.on("click", (params: EventParams) => {
|
||||||
currentParams.value = params;
|
currentParams.value = params;
|
||||||
if (props.option.series.type === "sankey") {
|
if (props.option.series.type === "sankey") {
|
||||||
@ -203,6 +216,23 @@ limitations under the License. -->
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeLegend(names: string[]) {
|
||||||
|
const instance = getInstance();
|
||||||
|
for (const item of props.option.legend.data) {
|
||||||
|
if (names.includes(item.name)) {
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "legendSelect",
|
||||||
|
name: item.name,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "legendUnSelect",
|
||||||
|
name: item.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.option,
|
() => props.option,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
74
src/components/Graph/Legend.vue
Normal file
74
src/components/Graph/Legend.vue
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<!-- 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>
|
||||||
|
<Selector
|
||||||
|
class="mb-10"
|
||||||
|
multiple
|
||||||
|
:value="legend"
|
||||||
|
size="small"
|
||||||
|
:options="Options"
|
||||||
|
@change="changeLegend"
|
||||||
|
filterable
|
||||||
|
collapseTags
|
||||||
|
collapseTagsTooltip
|
||||||
|
v-if="show"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch } from "vue";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import type { Option } from "@/types/app";
|
||||||
|
import Selector from "./Selector.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Array as PropType<{ name: string }[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
colors: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
isConfigPage: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const emits = defineEmits(["change"]);
|
||||||
|
const legend = ref<string[]>([]);
|
||||||
|
const Options = computed(() =>
|
||||||
|
props.data.map((d: { name: string }, index: number) => ({
|
||||||
|
label: d.name,
|
||||||
|
value: d.name,
|
||||||
|
color: props.colors[index % props.colors.length],
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
|
||||||
|
function changeLegend(opt: Option[]) {
|
||||||
|
legend.value = opt.map((d: Option) => d.value);
|
||||||
|
emits("change", legend.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.data,
|
||||||
|
() => {
|
||||||
|
legend.value = props.data.map((d) => d.name);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
107
src/components/Graph/Selector.vue
Normal file
107
src/components/Graph/Selector.vue
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<!-- 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>
|
||||||
|
<el-select
|
||||||
|
:size="size"
|
||||||
|
v-model="selected"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
@change="changeSelected"
|
||||||
|
:multiple="multiple"
|
||||||
|
:disabled="disabled"
|
||||||
|
:style="{ borderRadius }"
|
||||||
|
:clearable="clearable"
|
||||||
|
:remote="isRemote"
|
||||||
|
:reserve-keyword="isRemote"
|
||||||
|
:remote-method="remoteMethod"
|
||||||
|
:filterable="filterable"
|
||||||
|
:collapse-tags="collapseTags"
|
||||||
|
:collapse-tags-tooltip="collapseTagsTooltip"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="(item, index) in options"
|
||||||
|
:key="`${item.value}${index}`"
|
||||||
|
:label="item.label || ''"
|
||||||
|
:value="item.value || ''"
|
||||||
|
:disabled="item.disabled || false"
|
||||||
|
>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<el-tag :color="item.color" class="mr-5" size="small" />
|
||||||
|
<span :style="{ color: item.color }">{{ item.label }}</span>
|
||||||
|
</div>
|
||||||
|
</el-option>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
|
||||||
|
/*global defineProps, defineEmits, Indexable*/
|
||||||
|
const emit = defineEmits(["change", "query"]);
|
||||||
|
const props = defineProps({
|
||||||
|
options: {
|
||||||
|
type: Array as PropType<
|
||||||
|
({
|
||||||
|
label: string | number;
|
||||||
|
value: string | number;
|
||||||
|
color: string;
|
||||||
|
} & { disabled?: boolean })[]
|
||||||
|
>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: [Array, String, Number, undefined] as PropType<any>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
size: { type: null, default: "default" },
|
||||||
|
placeholder: {
|
||||||
|
type: [String, undefined] as PropType<string>,
|
||||||
|
default: "Select a option",
|
||||||
|
},
|
||||||
|
borderRadius: { type: Number, default: 3 },
|
||||||
|
multiple: { type: Boolean, default: false },
|
||||||
|
disabled: { type: Boolean, default: false },
|
||||||
|
clearable: { type: Boolean, default: false },
|
||||||
|
isRemote: { type: Boolean, default: false },
|
||||||
|
filterable: { type: Boolean, default: true },
|
||||||
|
collapseTags: { type: Boolean, default: false },
|
||||||
|
collapseTagsTooltip: { type: Boolean, default: false },
|
||||||
|
});
|
||||||
|
|
||||||
|
const selected = ref<string[] | string>(props.value);
|
||||||
|
function changeSelected() {
|
||||||
|
const options = props.options.filter((d: Indexable) =>
|
||||||
|
props.multiple ? selected.value.includes(d.value) : selected.value === d.value,
|
||||||
|
);
|
||||||
|
emit("change", options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function remoteMethod(query: string) {
|
||||||
|
if (props.isRemote) {
|
||||||
|
emit("query", query);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(data) => {
|
||||||
|
selected.value = data;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.el-input__inner {
|
||||||
|
border-radius: unset !important;
|
||||||
|
}
|
||||||
|
</style>
|
@ -26,6 +26,8 @@ limitations under the License. -->
|
|||||||
:reserve-keyword="isRemote"
|
:reserve-keyword="isRemote"
|
||||||
:remote-method="remoteMethod"
|
:remote-method="remoteMethod"
|
||||||
:filterable="filterable"
|
:filterable="filterable"
|
||||||
|
:collapse-tags="collapseTags"
|
||||||
|
:collapse-tags-tooltip="collapseTagsTooltip"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="(item, index) in options"
|
v-for="(item, index) in options"
|
||||||
@ -41,11 +43,6 @@ limitations under the License. -->
|
|||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
|
|
||||||
// interface Option {
|
|
||||||
// label: string | number;
|
|
||||||
// value: string | number;
|
|
||||||
// }
|
|
||||||
|
|
||||||
/*global defineProps, defineEmits, Indexable*/
|
/*global defineProps, defineEmits, Indexable*/
|
||||||
const emit = defineEmits(["change", "query"]);
|
const emit = defineEmits(["change", "query"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -73,6 +70,8 @@ limitations under the License. -->
|
|||||||
clearable: { type: Boolean, default: false },
|
clearable: { type: Boolean, default: false },
|
||||||
isRemote: { type: Boolean, default: false },
|
isRemote: { type: Boolean, default: false },
|
||||||
filterable: { type: Boolean, default: true },
|
filterable: { type: Boolean, default: true },
|
||||||
|
collapseTags: { type: Boolean, default: false },
|
||||||
|
collapseTagsTooltip: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
|
||||||
const selected = ref<string[] | string>(props.value);
|
const selected = ref<string[] | string>(props.value);
|
||||||
|
@ -18,7 +18,7 @@ import type { App } from "vue";
|
|||||||
import Icon from "./Icon.vue";
|
import Icon from "./Icon.vue";
|
||||||
import TimePicker from "./TimePicker.vue";
|
import TimePicker from "./TimePicker.vue";
|
||||||
import Selector from "./Selector.vue";
|
import Selector from "./Selector.vue";
|
||||||
import Graph from "./Graph.vue";
|
import Graph from "./Graph/Graph.vue";
|
||||||
import Radio from "./Radio.vue";
|
import Radio from "./Radio.vue";
|
||||||
import SelectSingle from "./SelectSingle.vue";
|
import SelectSingle from "./SelectSingle.vue";
|
||||||
import Tags from "./Tags.vue";
|
import Tags from "./Tags.vue";
|
||||||
|
75
src/graphql/base.ts
Normal file
75
src/graphql/base.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to 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. Apache Software Foundation (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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const Timeout = 2 * 60 * 1000;
|
||||||
|
export let globalAbortController = new AbortController();
|
||||||
|
export function abortRequestsAndUpdate() {
|
||||||
|
globalAbortController.abort(`Request timeout ${Timeout}ms`);
|
||||||
|
globalAbortController = new AbortController();
|
||||||
|
}
|
||||||
|
class HTTPError extends Error {
|
||||||
|
response;
|
||||||
|
|
||||||
|
constructor(response: Response, detailText = "") {
|
||||||
|
super(detailText || response.statusText);
|
||||||
|
|
||||||
|
this.name = "HTTPError";
|
||||||
|
this.response = response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const BasePath = `/graphql`;
|
||||||
|
|
||||||
|
export async function httpQuery({
|
||||||
|
path = "",
|
||||||
|
method = "GET",
|
||||||
|
json,
|
||||||
|
headers = {},
|
||||||
|
}: {
|
||||||
|
path?: string;
|
||||||
|
method: string;
|
||||||
|
json: unknown;
|
||||||
|
headers: Recordable;
|
||||||
|
}) {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
abortRequestsAndUpdate();
|
||||||
|
}, Timeout);
|
||||||
|
const url = `${BasePath}${path}`;
|
||||||
|
const response: Response = await fetch(url, {
|
||||||
|
method,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
accept: "application/json",
|
||||||
|
...headers,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(json),
|
||||||
|
signal: globalAbortController.signal,
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
throw new HTTPError(error);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
});
|
||||||
|
if (response.ok) {
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
console.error(new HTTPError(response));
|
||||||
|
}
|
||||||
|
}
|
@ -14,20 +14,18 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import type { AxiosResponse } from "axios";
|
import { httpQuery } from "./base";
|
||||||
import axios from "axios";
|
|
||||||
import { cancelToken } from "@/utils/cancelToken";
|
|
||||||
|
|
||||||
async function query(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
async function fetchQuery(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
||||||
const res: AxiosResponse = await axios.post(
|
const response = await httpQuery({
|
||||||
"/graphql",
|
method: "post",
|
||||||
{ query: param.queryStr, variables: { ...param.conditions } },
|
json: { query: param.queryStr, variables: { ...param.conditions } },
|
||||||
{ cancelToken: cancelToken() },
|
headers: {},
|
||||||
);
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
res.data.errors = res.data.errors.map((e: { message: string }) => e.message).join(" ");
|
response.errors = response.errors.map((e: { message: string }) => e.message).join(" ");
|
||||||
}
|
}
|
||||||
return res;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default query;
|
export default fetchQuery;
|
||||||
|
@ -24,6 +24,7 @@ export const Alarm = {
|
|||||||
message
|
message
|
||||||
startTime
|
startTime
|
||||||
scope
|
scope
|
||||||
|
name
|
||||||
tags {
|
tags {
|
||||||
key
|
key
|
||||||
value
|
value
|
||||||
@ -43,6 +44,35 @@ export const Alarm = {
|
|||||||
startTime
|
startTime
|
||||||
endTime
|
endTime
|
||||||
}
|
}
|
||||||
|
snapshot {
|
||||||
|
expression
|
||||||
|
metrics {
|
||||||
|
name
|
||||||
|
results {
|
||||||
|
metric {
|
||||||
|
labels {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values {
|
||||||
|
id
|
||||||
|
owner {
|
||||||
|
scope
|
||||||
|
serviceID
|
||||||
|
serviceName
|
||||||
|
normal
|
||||||
|
serviceInstanceID
|
||||||
|
serviceInstanceName
|
||||||
|
endpointID
|
||||||
|
endpointName
|
||||||
|
}
|
||||||
|
value
|
||||||
|
traceID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
80
src/graphql/fragments/async-profile.ts
Normal file
80
src/graphql/fragments/async-profile.ts
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/**
|
||||||
|
* 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 GetAsyncTaskList = {
|
||||||
|
variable: "$request: AsyncProfilerTaskListRequest!",
|
||||||
|
query: `
|
||||||
|
asyncTaskList: queryAsyncProfilerTaskList(request: $request) {
|
||||||
|
errorReason
|
||||||
|
tasks {
|
||||||
|
id
|
||||||
|
serviceId
|
||||||
|
serviceInstanceIds
|
||||||
|
createTime
|
||||||
|
events
|
||||||
|
duration
|
||||||
|
execArgs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GetAsyncProfileTaskProcess = {
|
||||||
|
variable: "$taskId: String!",
|
||||||
|
query: `
|
||||||
|
taskProgress: queryAsyncProfilerTaskProgress(taskId: $taskId) {
|
||||||
|
logs {
|
||||||
|
id
|
||||||
|
instanceId
|
||||||
|
instanceName
|
||||||
|
operationType
|
||||||
|
operationTime
|
||||||
|
}
|
||||||
|
errorInstanceIds
|
||||||
|
successInstanceIds
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CreateAsyncProfileTask = {
|
||||||
|
variable: "$asyncProfilerTaskCreationRequest: AsyncProfilerTaskCreationRequest!",
|
||||||
|
query: `
|
||||||
|
task: createAsyncProfilerTask(asyncProfilerTaskCreationRequest: $asyncProfilerTaskCreationRequest) {
|
||||||
|
id
|
||||||
|
errorReason
|
||||||
|
code
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GetAsyncProfileAnalyze = {
|
||||||
|
variable: "$request: AsyncProfilerAnalyzationRequest!",
|
||||||
|
query: `
|
||||||
|
analysisResult: queryAsyncProfilerAnalyze(request: $request) {
|
||||||
|
tree {
|
||||||
|
type
|
||||||
|
elements {
|
||||||
|
id
|
||||||
|
parentId
|
||||||
|
symbol: codeSignature
|
||||||
|
dumpCount: total
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
@ -14,22 +14,6 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
export const TypeOfMetrics = {
|
|
||||||
variable: "$name: String!",
|
|
||||||
query: `typeOfMetrics(name: $name)`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const listMetrics = {
|
|
||||||
variable: "$regex: String",
|
|
||||||
query: `
|
|
||||||
metrics: listMetrics(regex: $regex) {
|
|
||||||
value: name
|
|
||||||
label: name
|
|
||||||
type
|
|
||||||
catalog
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAllTemplates = {
|
export const getAllTemplates = {
|
||||||
query: `
|
query: `
|
||||||
|
@ -73,9 +73,9 @@ export const Processes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Endpoints = {
|
export const Endpoints = {
|
||||||
variable: "$serviceId: ID!, $keyword: String!",
|
variable: "$serviceId: ID!, $keyword: String!, $duration: Duration, $limit: Int!",
|
||||||
query: `
|
query: `
|
||||||
pods: findEndpoint(serviceId: $serviceId, keyword: $keyword, limit: 20) {
|
pods: findEndpoint(serviceId: $serviceId, keyword: $keyword, limit: $limit, duration: $duration) {
|
||||||
id
|
id
|
||||||
value: name
|
value: name
|
||||||
label: name
|
label: name
|
||||||
|
@ -14,9 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import type { AxiosPromise, AxiosResponse } from "axios";
|
import { httpQuery } from "./base";
|
||||||
import axios from "axios";
|
|
||||||
import { cancelToken } from "@/utils/cancelToken";
|
|
||||||
import * as app from "./query/app";
|
import * as app from "./query/app";
|
||||||
import * as selector from "./query/selector";
|
import * as selector from "./query/selector";
|
||||||
import * as dashboard from "./query/dashboard";
|
import * as dashboard from "./query/dashboard";
|
||||||
@ -28,6 +26,7 @@ import * as alarm from "./query/alarm";
|
|||||||
import * as event from "./query/event";
|
import * as event from "./query/event";
|
||||||
import * as ebpf from "./query/ebpf";
|
import * as ebpf from "./query/ebpf";
|
||||||
import * as demandLog from "./query/demand-log";
|
import * as demandLog from "./query/demand-log";
|
||||||
|
import * as asyncProfile from "./query/async-profile";
|
||||||
|
|
||||||
const query: { [key: string]: string } = {
|
const query: { [key: string]: string } = {
|
||||||
...app,
|
...app,
|
||||||
@ -41,32 +40,27 @@ const query: { [key: string]: string } = {
|
|||||||
...event,
|
...event,
|
||||||
...ebpf,
|
...ebpf,
|
||||||
...demandLog,
|
...demandLog,
|
||||||
|
...asyncProfile,
|
||||||
};
|
};
|
||||||
class Graphql {
|
class Graphql {
|
||||||
private queryData = "";
|
queryData = "";
|
||||||
public query(queryData: string) {
|
query(data: string) {
|
||||||
this.queryData = queryData;
|
this.queryData = data;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
public params(variablesData: unknown): AxiosPromise<void> {
|
async params(variables: unknown) {
|
||||||
return axios
|
const response = await httpQuery({
|
||||||
.post(
|
method: "post",
|
||||||
"/graphql",
|
headers: {},
|
||||||
{
|
json: {
|
||||||
query: query[this.queryData],
|
query: query[this.queryData],
|
||||||
variables: variablesData,
|
variables,
|
||||||
},
|
},
|
||||||
{ cancelToken: cancelToken() },
|
});
|
||||||
)
|
if (response.errors) {
|
||||||
.then((res: AxiosResponse) => {
|
response.errors = response.errors.map((e: { message: string }) => e.message).join(" ");
|
||||||
if (res.data.errors) {
|
}
|
||||||
res.data.errors = res.data.errors.map((e: { message: string }) => e.message).join(" ");
|
return response;
|
||||||
}
|
|
||||||
return res;
|
|
||||||
})
|
|
||||||
.catch((err: Error) => {
|
|
||||||
throw err;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
src/graphql/query/async-profile.ts
Normal file
31
src/graphql/query/async-profile.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
GetAsyncTaskList,
|
||||||
|
GetAsyncProfileTaskProcess,
|
||||||
|
CreateAsyncProfileTask,
|
||||||
|
GetAsyncProfileAnalyze,
|
||||||
|
} from "../fragments/async-profile";
|
||||||
|
|
||||||
|
export const getAsyncTaskList = `query getAsyncTaskList(${GetAsyncTaskList.variable}) {${GetAsyncTaskList.query}}`;
|
||||||
|
|
||||||
|
export const getAsyncProfileTaskProcess = `query getAsyncProfileTaskProcess(${GetAsyncProfileTaskProcess.variable}) {${GetAsyncProfileTaskProcess.query}}`;
|
||||||
|
|
||||||
|
export const saveAsyncProfileTask = `mutation createAsyncProfileTask(${CreateAsyncProfileTask.variable}) {${CreateAsyncProfileTask.query}}`;
|
||||||
|
|
||||||
|
export const getAsyncProfileAnalyze = `query getAsyncProfileAnalyze(${GetAsyncProfileAnalyze.variable}) {${GetAsyncProfileAnalyze.query}}`;
|
@ -14,18 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import {
|
import { getAllTemplates, addTemplate, changeTemplate, deleteTemplate } from "../fragments/dashboard";
|
||||||
TypeOfMetrics,
|
|
||||||
listMetrics,
|
|
||||||
getAllTemplates,
|
|
||||||
addTemplate,
|
|
||||||
changeTemplate,
|
|
||||||
deleteTemplate,
|
|
||||||
} from "../fragments/dashboard";
|
|
||||||
|
|
||||||
export const queryTypeOfMetrics = `query typeOfMetrics(${TypeOfMetrics.variable}) {${TypeOfMetrics.query}}`;
|
|
||||||
|
|
||||||
export const queryMetrics = `query queryData(${listMetrics.variable}) {${listMetrics.query}}`;
|
|
||||||
|
|
||||||
export const addNewTemplate = `mutation template(${addTemplate.variable}) {${addTemplate.query}}`;
|
export const addNewTemplate = `mutation template(${addTemplate.variable}) {${addTemplate.query}}`;
|
||||||
|
|
||||||
|
@ -57,6 +57,16 @@ export const RespFields: Indexable = {
|
|||||||
name: id
|
name: id
|
||||||
value
|
value
|
||||||
refId: traceID
|
refId: traceID
|
||||||
|
owner {
|
||||||
|
scope
|
||||||
|
serviceID
|
||||||
|
serviceName
|
||||||
|
normal
|
||||||
|
serviceInstanceID
|
||||||
|
serviceInstanceName
|
||||||
|
endpointID
|
||||||
|
endpointName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
error
|
error
|
||||||
@ -102,3 +112,5 @@ export const LightChartColors = [
|
|||||||
"#546570",
|
"#546570",
|
||||||
"#c4ccd3",
|
"#c4ccd3",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const MaxQueryLength = 120;
|
||||||
|
@ -47,11 +47,11 @@ export function createBreakpointListen(fn?: (opt: CreateCallbackParams) => void)
|
|||||||
|
|
||||||
function getWindowWidth() {
|
function getWindowWidth() {
|
||||||
const width = document.body.clientWidth;
|
const width = document.body.clientWidth;
|
||||||
const xs = screenMap.get(sizeEnum.XS) || "";
|
const xs = screenMap.get(sizeEnum.XS) || 0;
|
||||||
const sm = screenMap.get(sizeEnum.SM) || "";
|
const sm = screenMap.get(sizeEnum.SM) || 0;
|
||||||
const md = screenMap.get(sizeEnum.MD) || "";
|
const md = screenMap.get(sizeEnum.MD) || 0;
|
||||||
const lg = screenMap.get(sizeEnum.LG) || "";
|
const lg = screenMap.get(sizeEnum.LG) || 0;
|
||||||
const xl = screenMap.get(sizeEnum.XL) || "";
|
const xl = screenMap.get(sizeEnum.XL) || 0;
|
||||||
if (width < xs) {
|
if (width < xs) {
|
||||||
screenRef.value = sizeEnum.XS;
|
screenRef.value = sizeEnum.XS;
|
||||||
} else if (width < sm) {
|
} else if (width < sm) {
|
||||||
|
@ -14,9 +14,10 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { RespFields, MaximumEntities } from "./data";
|
import { RespFields, MaximumEntities, MaxQueryLength } from "./data";
|
||||||
import { EntityType, ExpressionResultType } from "@/views/dashboard/data";
|
import { EntityType, ExpressionResultType } from "@/views/dashboard/data";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
import { useTopologyStore } from "@/store/modules/topology";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
@ -24,6 +25,14 @@ import type { MetricConfigOpt } from "@/types/dashboard";
|
|||||||
import type { Instance, Endpoint, Service } from "@/types/selector";
|
import type { Instance, Endpoint, Service } from "@/types/selector";
|
||||||
import type { Node, Call } from "@/types/topology";
|
import type { Node, Call } from "@/types/topology";
|
||||||
|
|
||||||
|
function chunkArray(array: any[], chunkSize: number) {
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < array.length; i += chunkSize) {
|
||||||
|
result.push(array.slice(i, i + chunkSize));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
export async function useDashboardQueryProcessor(configList: Indexable[]) {
|
export async function useDashboardQueryProcessor(configList: Indexable[]) {
|
||||||
function expressionsGraphql(config: Indexable, idx: number) {
|
function expressionsGraphql(config: Indexable, idx: number) {
|
||||||
if (!(config.metrics && config.metrics[0])) {
|
if (!(config.metrics && config.metrics[0])) {
|
||||||
@ -100,12 +109,12 @@ export async function useDashboardQueryProcessor(configList: Indexable[]) {
|
|||||||
return { source: {}, tips: [], typesOfMQE: [] };
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
}
|
}
|
||||||
const tips: string[] = [];
|
const tips: string[] = [];
|
||||||
const source: { [key: string]: unknown } = {};
|
const source: Indexable<unknown> = {};
|
||||||
const keys = Object.keys(resp.data);
|
const keys = Object.keys(resp.data);
|
||||||
const typesOfMQE: string[] = [];
|
const typesOfMQE: string[] = [];
|
||||||
|
|
||||||
for (let i = 0; i < config.metrics.length; i++) {
|
for (let i = 0; i < config.metrics.length; i++) {
|
||||||
const c: MetricConfigOpt = (config.metricConfig && config.metricConfig[i]) || {};
|
const metricConfig: MetricConfigOpt = (config.metricConfig && config.metricConfig[i]) || {};
|
||||||
const obj = resp.data[keys[i]] || {};
|
const obj = resp.data[keys[i]] || {};
|
||||||
const results = obj.results || [];
|
const results = obj.results || [];
|
||||||
const name = config.metrics[i];
|
const name = config.metrics[i];
|
||||||
@ -116,15 +125,15 @@ export async function useDashboardQueryProcessor(configList: Indexable[]) {
|
|||||||
if (!obj.error) {
|
if (!obj.error) {
|
||||||
if ([ExpressionResultType.SINGLE_VALUE, ExpressionResultType.TIME_SERIES_VALUES].includes(type)) {
|
if ([ExpressionResultType.SINGLE_VALUE, ExpressionResultType.TIME_SERIES_VALUES].includes(type)) {
|
||||||
for (const item of results) {
|
for (const item of results) {
|
||||||
const label =
|
let label =
|
||||||
item.metric &&
|
item.metric &&
|
||||||
item.metric.labels.map((d: { key: string; value: string }) => `${d.key}=${d.value}`).join(",");
|
item.metric.labels.map((d: { key: string; value: string }) => `${d.key}=${d.value}`).join(",");
|
||||||
const values = item.values.map((d: { value: unknown }) => d.value) || [];
|
const values = item.values.map((d: { value: unknown }) => d.value) || [];
|
||||||
if (results.length === 1) {
|
if (results.length === 1) {
|
||||||
source[label || c.label || name] = values;
|
// If the metrics label does not exist, use the configuration label or expression
|
||||||
} else {
|
label = label ? `${metricConfig.label || name}, ${label}` : metricConfig.label || name;
|
||||||
source[label] = values;
|
|
||||||
}
|
}
|
||||||
|
source[label] = values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (([ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST] as string[]).includes(type)) {
|
if (([ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST] as string[]).includes(type)) {
|
||||||
@ -139,7 +148,7 @@ export async function useDashboardQueryProcessor(configList: Indexable[]) {
|
|||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const variables: string[] = [`$duration: Duration!`];
|
const variables: string[] = [`$duration: Duration!`];
|
||||||
let fragments = "";
|
let fragments = "";
|
||||||
let conditions: Recordable = {
|
let conditions: Recordable<unknown> = {
|
||||||
duration: appStore.durationTime,
|
duration: appStore.durationTime,
|
||||||
};
|
};
|
||||||
for (let i = 0; i < configArr.length; i++) {
|
for (let i = 0; i < configArr.length; i++) {
|
||||||
@ -181,13 +190,6 @@ export async function useDashboardQueryProcessor(configList: Indexable[]) {
|
|||||||
return { 0: { source: {}, tips: [], typesOfMQE: [] } };
|
return { 0: { source: {}, tips: [], typesOfMQE: [] } };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function chunkArray(array: any[], chunkSize: number) {
|
|
||||||
const result = [];
|
|
||||||
for (let i = 0; i < array.length; i += chunkSize) {
|
|
||||||
result.push(array.slice(i, i + chunkSize));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const partArr = chunkArray(configList, 6);
|
const partArr = chunkArray(configList, 6);
|
||||||
const promiseArr = partArr.map((d: Array<Indexable>) => fetchMetrics(d));
|
const promiseArr = partArr.map((d: Array<Indexable>) => fetchMetrics(d));
|
||||||
@ -394,7 +396,7 @@ export function useQueryTopologyExpressionsProcessor(metrics: string[], instance
|
|||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
function getExpressionQuery() {
|
function getExpressionQuery(partMetrics?: string[]) {
|
||||||
const conditions: { [key: string]: unknown } = {
|
const conditions: { [key: string]: unknown } = {
|
||||||
duration: appStore.durationTime,
|
duration: appStore.durationTime,
|
||||||
};
|
};
|
||||||
@ -448,7 +450,7 @@ export function useQueryTopologyExpressionsProcessor(metrics: string[], instance
|
|||||||
};
|
};
|
||||||
variables.push(`$entity${index}: Entity!`);
|
variables.push(`$entity${index}: Entity!`);
|
||||||
conditions[`entity${index}`] = entity;
|
conditions[`entity${index}`] = entity;
|
||||||
const f = metrics.map((name: string, idx: number) => {
|
const f = (partMetrics || metrics).map((name: string, idx: number) => {
|
||||||
if (index === 0) {
|
if (index === 0) {
|
||||||
variables.push(`$expression${idx}: String!`);
|
variables.push(`$expression${idx}: String!`);
|
||||||
conditions[`expression${idx}`] = name;
|
conditions[`expression${idx}`] = name;
|
||||||
@ -462,19 +464,19 @@ export function useQueryTopologyExpressionsProcessor(metrics: string[], instance
|
|||||||
|
|
||||||
return { queryStr, conditions };
|
return { queryStr, conditions };
|
||||||
}
|
}
|
||||||
function handleExpressionValues(resp: { [key: string]: any }) {
|
function handleExpressionValues(partMetrics: string[], resp: { [key: string]: any }) {
|
||||||
const obj: any = {};
|
const obj: Indexable = {};
|
||||||
for (let idx = 0; idx < instances.length; idx++) {
|
for (let idx = 0; idx < instances.length; idx++) {
|
||||||
for (let index = 0; index < metrics.length; index++) {
|
for (let index = 0; index < partMetrics.length; index++) {
|
||||||
const k = "expression" + idx + index;
|
const k = "expression" + idx + index;
|
||||||
if (metrics[index]) {
|
if (partMetrics[index]) {
|
||||||
if (!obj[metrics[index]]) {
|
if (!obj[partMetrics[index]]) {
|
||||||
obj[metrics[index]] = {
|
obj[partMetrics[index]] = {
|
||||||
values: [],
|
values: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
obj[metrics[index]].values.push({
|
obj[partMetrics[index]].values.push({
|
||||||
value: resp[k].results[0] && resp[k].results[0].values[0].value,
|
value: resp[k] && resp[k].results[0] && resp[k].results[0].values[0].value,
|
||||||
id: instances[idx].id,
|
id: instances[idx].id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -482,6 +484,31 @@ export function useQueryTopologyExpressionsProcessor(metrics: string[], instance
|
|||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
async function fetchMetrics(partMetrics: string[]) {
|
||||||
|
const topologyStore = useTopologyStore();
|
||||||
|
const param = getExpressionQuery(partMetrics);
|
||||||
|
const res = await topologyStore.getTopologyExpressionValue(param);
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return handleExpressionValues(partMetrics, res.data);
|
||||||
|
}
|
||||||
|
|
||||||
return { getExpressionQuery, handleExpressionValues };
|
async function getMetrics() {
|
||||||
|
const count = Math.floor(MaxQueryLength / instances.length);
|
||||||
|
const metricsArr = chunkArray(metrics, count);
|
||||||
|
const promiseArr = metricsArr.map((d: string[]) => fetchMetrics(d));
|
||||||
|
const responseList = await Promise.all(promiseArr);
|
||||||
|
let resp = {};
|
||||||
|
for (const item of responseList) {
|
||||||
|
resp = {
|
||||||
|
...resp,
|
||||||
|
...item,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { getMetrics, getExpressionQuery };
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ export default function useLegendProcess(legend?: LegendOptions) {
|
|||||||
if (keys.length === 1) {
|
if (keys.length === 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (legend && legend.asTable) {
|
if (legend && (legend.asTable || legend.asSelector)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
47
src/hooks/useSnapshot.ts
Normal file
47
src/hooks/useSnapshot.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* 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 type { MetricsResults } from "@/types/dashboard";
|
||||||
|
|
||||||
|
export function useSnapshot(metrics: { name: string; results: MetricsResults[] }[]) {
|
||||||
|
function processResults() {
|
||||||
|
const sources = metrics.map((metric: { name: string; results: MetricsResults[] }) => {
|
||||||
|
const values = metric.results.map(
|
||||||
|
(r: { values: { value: string }[]; metric: { labels: { key: string; value: string }[] } }) => {
|
||||||
|
const arr = r.values.map((v: { value: string }) => Number(v.value));
|
||||||
|
if (!r.metric.labels.length) {
|
||||||
|
return { values: arr };
|
||||||
|
}
|
||||||
|
const name = r.metric.labels
|
||||||
|
.map(
|
||||||
|
(label: { key: string; value: string }) =>
|
||||||
|
`${metric.name}${label ? "{" : ""}${label.key}=${label.value}${label ? "}" : ""}`,
|
||||||
|
)
|
||||||
|
.join(",");
|
||||||
|
return { name, values: arr };
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
return { name: metric.name, values };
|
||||||
|
});
|
||||||
|
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
processResults,
|
||||||
|
};
|
||||||
|
}
|
@ -61,7 +61,7 @@ limitations under the License. -->
|
|||||||
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
|
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
|
||||||
</span>
|
</span>
|
||||||
<span class="version ml-5 cp">
|
<span class="version ml-5 cp">
|
||||||
<el-popover trigger="hover" width="250" placement="bottom" :content="appStore.version">
|
<el-popover trigger="hover" :width="250" placement="bottom" :content="appStore.version">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<span>
|
<span>
|
||||||
<Icon iconName="info_outline" size="middle" />
|
<Icon iconName="info_outline" size="middle" />
|
||||||
|
@ -50,7 +50,7 @@ limitations under the License. -->
|
|||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-menu-item-group>
|
</el-menu-item-group>
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
<el-menu-item :index="String(menu.name)" @click="changePage(menu)" v-else>
|
<el-menu-item :index="String(menu.name)" v-else>
|
||||||
<el-icon class="menu-icons" :style="{ marginRight: '12px' }" @mouseover="setCollapse">
|
<el-icon class="menu-icons" :style="{ marginRight: '12px' }" @mouseover="setCollapse">
|
||||||
<router-link class="items menu-title" :to="menu.children[0].path">
|
<router-link class="items menu-title" :to="menu.children[0].path">
|
||||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||||
@ -83,7 +83,6 @@ limitations under the License. -->
|
|||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const name = ref<string>(String(router.currentRoute.value.name));
|
const name = ref<string>(String(router.currentRoute.value.name));
|
||||||
const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "") ? ref("light") : ref("black");
|
|
||||||
const routes = ref<RouteRecordRaw[] | any>(
|
const routes = ref<RouteRecordRaw[] | any>(
|
||||||
(router.options.routes || []).filter((d: any) => d.meta && d.meta.activate),
|
(router.options.routes || []).filter((d: any) => d.meta && d.meta.activate),
|
||||||
);
|
);
|
||||||
@ -100,9 +99,7 @@ limitations under the License. -->
|
|||||||
if (route.name === "ViewWidget") {
|
if (route.name === "ViewWidget") {
|
||||||
showMenu.value = false;
|
showMenu.value = false;
|
||||||
}
|
}
|
||||||
const changePage = (menu: RouteRecordRaw) => {
|
|
||||||
theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name)) ? "light" : "black";
|
|
||||||
};
|
|
||||||
const filterMenus = (menus: Recordable[]) => {
|
const filterMenus = (menus: Recordable[]) => {
|
||||||
return menus.filter((d) => d.meta && !d.meta.notShow && d.meta.activate);
|
return menus.filter((d) => d.meta && !d.meta.notShow && d.meta.activate);
|
||||||
};
|
};
|
||||||
|
@ -139,7 +139,6 @@ const msg = {
|
|||||||
enableAssociate: "Enable association",
|
enableAssociate: "Enable association",
|
||||||
text: "Text",
|
text: "Text",
|
||||||
query: "Query",
|
query: "Query",
|
||||||
endpointTips: "The table shows up to 20 pieces of endpoints.",
|
|
||||||
viewTrace: "View Related Traces",
|
viewTrace: "View Related Traces",
|
||||||
relatedTraceOptions: "Related Trace Options",
|
relatedTraceOptions: "Related Trace Options",
|
||||||
setLatencyDuration: "Latency Related Metrics",
|
setLatencyDuration: "Latency Related Metrics",
|
||||||
@ -154,6 +153,7 @@ const msg = {
|
|||||||
legendOptions: "Legend Options",
|
legendOptions: "Legend Options",
|
||||||
showLegend: "Show Legend",
|
showLegend: "Show Legend",
|
||||||
asTable: "As Table",
|
asTable: "As Table",
|
||||||
|
asSelector: "As Selector",
|
||||||
toTheRight: "To The Right",
|
toTheRight: "To The Right",
|
||||||
legendValues: "Legend Values",
|
legendValues: "Legend Values",
|
||||||
minDuration: "Minimal Request Duration",
|
minDuration: "Minimal Request Duration",
|
||||||
@ -386,5 +386,16 @@ const msg = {
|
|||||||
tabExpressions: "Tab Expressions",
|
tabExpressions: "Tab Expressions",
|
||||||
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
|
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
|
||||||
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
|
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
|
||||||
|
valueMappings: "Value Mappings",
|
||||||
|
mappingTip: "Notice: The mapping key is a Regex string, e.g. ^([0-9])$",
|
||||||
|
valueDashboard: "Data Value Related Dashboard",
|
||||||
|
viewValueDashboard: "View Dashboard",
|
||||||
|
errorInstances: "Error Instances",
|
||||||
|
successInstances: "Success Instances",
|
||||||
|
profilingEvents: "Async Profiling Events",
|
||||||
|
execArgs: "Exec Args",
|
||||||
|
instances: "Instances",
|
||||||
|
snapshot: "Snapshot",
|
||||||
|
expression: "Expression",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@ -138,7 +138,6 @@ const msg = {
|
|||||||
"El nombre sólo admite chino e inglés, líneas horizontales y subrayado, y la longitud del nombre no excederá de 300 caracteres",
|
"El nombre sólo admite chino e inglés, líneas horizontales y subrayado, y la longitud del nombre no excederá de 300 caracteres",
|
||||||
enableAssociate: "Activar asociación",
|
enableAssociate: "Activar asociación",
|
||||||
query: "Consulta",
|
query: "Consulta",
|
||||||
endpointTips: "Aquí, la tabla muestra hasta 20 punto final.",
|
|
||||||
queryOrder: "Consulta por duración",
|
queryOrder: "Consulta por duración",
|
||||||
setOrder: "Orden de consulta",
|
setOrder: "Orden de consulta",
|
||||||
latency: "Retraso",
|
latency: "Retraso",
|
||||||
@ -386,5 +385,17 @@ const msg = {
|
|||||||
tabExpressions: "Tab Expressions",
|
tabExpressions: "Tab Expressions",
|
||||||
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
|
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
|
||||||
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
|
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
|
||||||
|
valueMappings: "Value Mappings",
|
||||||
|
mappingTip: "Aviso: La clave de mapeo es una cadena Regex, p. ej. ^([0-9])$",
|
||||||
|
valueDashboard: "Data Value Related Dashboard",
|
||||||
|
viewValueDashboard: "View Dashboard",
|
||||||
|
errorInstances: "Error Instances",
|
||||||
|
successInstances: "Success Instances",
|
||||||
|
profilingEvents: "Async Profiling Events",
|
||||||
|
execArgs: "Exec Args",
|
||||||
|
instances: "Instances",
|
||||||
|
snapshot: "Snapshot",
|
||||||
|
expression: "Expression",
|
||||||
|
asSelector: "As Selector",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@ -128,11 +128,20 @@ const titles = {
|
|||||||
self_observability_java_agent: "SkyWalking Java Agent",
|
self_observability_java_agent: "SkyWalking Java Agent",
|
||||||
self_observability_java_agent_desc:
|
self_observability_java_agent_desc:
|
||||||
"The self observability of SkyWalking Java Agent, which provides the abilities to measure the tracing performance and error statistics of plugins.",
|
"The self observability of SkyWalking Java Agent, which provides the abilities to measure the tracing performance and error statistics of plugins.",
|
||||||
|
self_observability_go_agent: "SkyWalking Go Agent",
|
||||||
|
self_observability_go_agent_desc:
|
||||||
|
"The self observability of SkyWalking Go Agent, which provides the abilities to measure the tracing performance and error statistics of plugins.",
|
||||||
cilium: "Cilium",
|
cilium: "Cilium",
|
||||||
cilium_desc:
|
cilium_desc:
|
||||||
"Cilium is a CNI plugin for Kubernetes that provides eBPF-based networking, security, and load balancing.",
|
"Cilium is a CNI plugin for Kubernetes that provides eBPF-based networking, security, and load balancing.",
|
||||||
cilium_service: "Cilium Service",
|
cilium_service: "Cilium Service",
|
||||||
cilium_service_desc: "Observe Service status and resources from Cilium Hubble.",
|
cilium_service_desc: "Observe Service status and resources from Cilium Hubble.",
|
||||||
|
data_processing_engine: "Data Processing Engine",
|
||||||
|
data_processing_engine_desc:
|
||||||
|
"A data processing engine is a system designed to efficiently process, transform, and analyze large-scale data in real time or batch mode.",
|
||||||
|
data_processing_engine_flink: "Flink",
|
||||||
|
data_processing_engine_flink_desc:
|
||||||
|
"Apache Flink is a framework and distributed processing engine for stateful computations over unbounded and bounded data streams. Flink has been designed to run in all common cluster environments, perform computations at in-memory speed and at any scale.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default titles;
|
export default titles;
|
||||||
|
@ -128,12 +128,21 @@ const titles = {
|
|||||||
"Satellite: an open-source agent designed for the cloud-native infrastructures, which provides a low-cost, high-efficient, and more secure way to collect telemetry data. It is the recommended load balancer for telemetry collecting.",
|
"Satellite: an open-source agent designed for the cloud-native infrastructures, which provides a low-cost, high-efficient, and more secure way to collect telemetry data. It is the recommended load balancer for telemetry collecting.",
|
||||||
self_observability_java_agent: "SkyWalking Java Agent",
|
self_observability_java_agent: "SkyWalking Java Agent",
|
||||||
self_observability_java_agent_desc:
|
self_observability_java_agent_desc:
|
||||||
"The self observability of SkyWalking Java Agent, which provides the abilities to measure the tracing performance and error statistics of plugins.",
|
"La auto-observabilidad de SkyWalking Java Agent, que proporciona la capacidad de medir el rendimiento del trazado y las estadísticas de errores de los plugins.",
|
||||||
|
self_observability_go_agent: "SkyWalking Go Agent",
|
||||||
|
self_observability_go_agent_desc:
|
||||||
|
"La auto-observabilidad de SkyWalking Go Agent, que proporciona la capacidad de medir el rendimiento del trazado y las estadísticas de errores de los plugins.",
|
||||||
cilium: "Cilium",
|
cilium: "Cilium",
|
||||||
cilium_desc:
|
cilium_desc:
|
||||||
"Cilium es un complemento CNI para Kubernetes que proporciona redes, seguridad y equilibrio de carga basados en eBPF.",
|
"Cilium es un complemento CNI para Kubernetes que proporciona redes, seguridad y equilibrio de carga basados en eBPF.",
|
||||||
cilium_service: "Cilium Service",
|
cilium_service: "Cilium Service",
|
||||||
cilium_service_desc: "Observe el estado del servicio y los recursos de Cilium Hubble.",
|
cilium_service_desc: "Observe el estado del servicio y los recursos de Cilium Hubble.",
|
||||||
|
data_processing_engine: "Data Processing Engine",
|
||||||
|
data_processing_engine_desc:
|
||||||
|
"A data processing engine is a system designed to efficiently process, transform, and analyze large-scale data in real time or batch mode.",
|
||||||
|
data_processing_engine_flink: "Flink",
|
||||||
|
data_processing_engine_flink_desc:
|
||||||
|
"Apache Flink is a framework and distributed processing engine for stateful computations over unbounded and bounded data streams. Flink has been designed to run in all common cluster environments, perform computations at in-memory speed and at any scale.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default titles;
|
export default titles;
|
||||||
|
@ -113,10 +113,17 @@ const titles = {
|
|||||||
"Satellite:为云原生基础设施设计的开源代理,提供了一种低成本、高效、更安全的遥测数据收集方式。它是遥测采集的推荐负载均衡器。",
|
"Satellite:为云原生基础设施设计的开源代理,提供了一种低成本、高效、更安全的遥测数据收集方式。它是遥测采集的推荐负载均衡器。",
|
||||||
self_observability_java_agent: "SkyWalking Java Agent",
|
self_observability_java_agent: "SkyWalking Java Agent",
|
||||||
self_observability_java_agent_desc: "SkyWalking Java Agent 自监控提供了对 agent 插件的性能追踪和错误统计。",
|
self_observability_java_agent_desc: "SkyWalking Java Agent 自监控提供了对 agent 插件的性能追踪和错误统计。",
|
||||||
|
self_observability_go_agent: "SkyWalking Go Agent",
|
||||||
|
self_observability_go_agent_desc: "SkyWalking Go Agent 自监控提供了对 agent 插件的性能追踪和错误统计。",
|
||||||
cilium: "Cilium",
|
cilium: "Cilium",
|
||||||
cilium_desc: "Cilium是Kubernetes上的CNI插件,提供基于eBPF的网络、安全和负载均衡。",
|
cilium_desc: "Cilium是Kubernetes上的CNI插件,提供基于eBPF的网络、安全和负载均衡。",
|
||||||
cilium_service: "Cilium服务",
|
cilium_service: "Cilium服务",
|
||||||
cilium_service_desc: "通过Cilium Hubble收集的遥测数据观察服务。",
|
cilium_service_desc: "通过Cilium Hubble收集的遥测数据观察服务。",
|
||||||
|
data_processing_engine: "数据处理引擎",
|
||||||
|
data_processing_engine_desc: "数据处理引擎是一个用于高效地在实时或批处理模式下处理、转换和分析大规模数据的系统。",
|
||||||
|
data_processing_engine_flink: "Flink",
|
||||||
|
data_processing_engine_flink_desc:
|
||||||
|
"Apache Flink 是一个框架和分布式处理引擎,用于在无边界和有边界数据流上进行有状态的计算。Flink 能在所有常见集群环境中运行,并能以内存速度和任意规模进行计算。",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default titles;
|
export default titles;
|
||||||
|
@ -137,7 +137,6 @@ const msg = {
|
|||||||
duplicateName: "重复的名称",
|
duplicateName: "重复的名称",
|
||||||
text: "文本",
|
text: "文本",
|
||||||
query: "查询",
|
query: "查询",
|
||||||
endpointTips: "这里最多展示20条endpoints。",
|
|
||||||
viewTrace: "查看相关Trace",
|
viewTrace: "查看相关Trace",
|
||||||
relatedTraceOptions: "相关的Trace选项",
|
relatedTraceOptions: "相关的Trace选项",
|
||||||
setLatencyDuration: "延迟相关指标",
|
setLatencyDuration: "延迟相关指标",
|
||||||
@ -152,6 +151,7 @@ const msg = {
|
|||||||
legendOptions: "图例选项",
|
legendOptions: "图例选项",
|
||||||
showLegend: "显示图例",
|
showLegend: "显示图例",
|
||||||
asTable: "作为表格",
|
asTable: "作为表格",
|
||||||
|
asSelector: "作为选择器",
|
||||||
toTheRight: "在右边",
|
toTheRight: "在右边",
|
||||||
legendValues: "图例值",
|
legendValues: "图例值",
|
||||||
minDuration: "最小请求持续时间",
|
minDuration: "最小请求持续时间",
|
||||||
@ -384,5 +384,16 @@ const msg = {
|
|||||||
tabExpressions: "Tab表达式",
|
tabExpressions: "Tab表达式",
|
||||||
hierarchyNodeMetrics: "层次图节点的指标",
|
hierarchyNodeMetrics: "层次图节点的指标",
|
||||||
hierarchyNodeDashboard: "作为层次图节点的dashboard",
|
hierarchyNodeDashboard: "作为层次图节点的dashboard",
|
||||||
|
valueMappings: "值映射",
|
||||||
|
mappingTip: "注意: 映射键是一个正则表达式字符串,比如 ^([0-9])$",
|
||||||
|
valueDashboard: "数据值相关的仪表板",
|
||||||
|
viewValueDashboard: "查看仪表板",
|
||||||
|
errorInstances: "错误的实例",
|
||||||
|
successInstances: "成功的实例",
|
||||||
|
profilingEvents: "异步分析事件",
|
||||||
|
execArgs: "String任务扩展",
|
||||||
|
instances: "实例",
|
||||||
|
snapshot: "快照",
|
||||||
|
expression: "表达式",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@ -33,7 +33,7 @@ export const routesAlarm: Array<RouteRecordRaw> = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/alerting",
|
path: "/alerting",
|
||||||
name: "Alarm",
|
name: "ViewAlarm",
|
||||||
component: Alarm,
|
component: Alarm,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -100,7 +100,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
|||||||
path: "",
|
path: "",
|
||||||
redirect: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name",
|
redirect: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name",
|
||||||
component: Edit,
|
component: Edit,
|
||||||
name: "ViewServiceRelation",
|
name: "ServiceRelations",
|
||||||
meta: {
|
meta: {
|
||||||
notShow: true,
|
notShow: true,
|
||||||
},
|
},
|
||||||
@ -121,7 +121,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
|||||||
path: "",
|
path: "",
|
||||||
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
|
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
|
||||||
component: Edit,
|
component: Edit,
|
||||||
name: "ViewPod",
|
name: "Pods",
|
||||||
meta: {
|
meta: {
|
||||||
notShow: true,
|
notShow: true,
|
||||||
},
|
},
|
||||||
@ -142,7 +142,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
|||||||
path: "",
|
path: "",
|
||||||
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:name",
|
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:name",
|
||||||
component: Edit,
|
component: Edit,
|
||||||
name: "ViewProcess",
|
name: "Processes",
|
||||||
meta: {
|
meta: {
|
||||||
notShow: true,
|
notShow: true,
|
||||||
},
|
},
|
||||||
@ -163,7 +163,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
|||||||
path: "",
|
path: "",
|
||||||
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
|
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
|
||||||
component: Edit,
|
component: Edit,
|
||||||
name: "PodRelation",
|
name: "PodRelations",
|
||||||
meta: {
|
meta: {
|
||||||
notShow: true,
|
notShow: true,
|
||||||
},
|
},
|
||||||
@ -185,7 +185,7 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
|||||||
redirect:
|
redirect:
|
||||||
"/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name",
|
"/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name",
|
||||||
component: Edit,
|
component: Edit,
|
||||||
name: "ProcessRelation",
|
name: "ProcessRelations",
|
||||||
meta: {
|
meta: {
|
||||||
notShow: true,
|
notShow: true,
|
||||||
},
|
},
|
||||||
|
@ -37,16 +37,8 @@ const router = createRouter({
|
|||||||
routes,
|
routes,
|
||||||
});
|
});
|
||||||
|
|
||||||
(window as any).axiosCancel = [];
|
router.beforeEach((to, _, next) => {
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
|
||||||
// const token = window.localStorage.getItem("skywalking-authority");
|
// const token = window.localStorage.getItem("skywalking-authority");
|
||||||
if ((window as any).axiosCancel.length !== 0) {
|
|
||||||
for (const func of (window as any).axiosCancel) {
|
|
||||||
setTimeout(func(), 0);
|
|
||||||
}
|
|
||||||
(window as any).axiosCancel = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to.path === "/") {
|
if (to.path === "/") {
|
||||||
let defaultPath = "";
|
let defaultPath = "";
|
||||||
|
@ -33,7 +33,7 @@ export const routesSettings: Array<RouteRecordRaw> = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/settings",
|
path: "/settings",
|
||||||
name: "Settings",
|
name: "ViewSettings",
|
||||||
component: Settings,
|
component: Settings,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
@ -47,6 +47,7 @@ export const ControlsTypes = [
|
|||||||
WidgetType.DemandLog,
|
WidgetType.DemandLog,
|
||||||
WidgetType.Ebpf,
|
WidgetType.Ebpf,
|
||||||
WidgetType.NetworkProfiling,
|
WidgetType.NetworkProfiling,
|
||||||
|
WidgetType.AsyncProfiling,
|
||||||
WidgetType.ThirdPartyApp,
|
WidgetType.ThirdPartyApp,
|
||||||
WidgetType.ContinuousProfiling,
|
WidgetType.ContinuousProfiling,
|
||||||
WidgetType.TaskTimeline,
|
WidgetType.TaskTimeline,
|
||||||
@ -55,3 +56,5 @@ export enum EBPFProfilingTriggerType {
|
|||||||
FIXED_TIME = "FIXED_TIME",
|
FIXED_TIME = "FIXED_TIME",
|
||||||
CONTINUOUS_PROFILING = "CONTINUOUS_PROFILING",
|
CONTINUOUS_PROFILING = "CONTINUOUS_PROFILING",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const EndpointsTopNDefault = 20;
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import type { Alarm } from "@/types/alarm";
|
import type { Alarm } from "@/types/alarm";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
@ -37,30 +36,22 @@ export const alarmStore = defineStore({
|
|||||||
actions: {
|
actions: {
|
||||||
async getAlarms(params: Recordable) {
|
async getAlarms(params: Recordable) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const res: AxiosResponse = await graphql.query("queryAlarms").params(params);
|
const res = await graphql.query("queryAlarms").params(params);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
if (res.data.data.getAlarm.items) {
|
if (res.data.getAlarm.items) {
|
||||||
this.alarms = res.data.data.getAlarm.items;
|
this.alarms = res.data.getAlarm.items;
|
||||||
this.total = res.data.data.getAlarm.total;
|
this.total = res.data.getAlarm.total;
|
||||||
}
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getAlarmTagKeys() {
|
async getAlarmTagKeys() {
|
||||||
const res: AxiosResponse = await graphql
|
return await graphql.query("queryAlarmTagKeys").params({ duration: useAppStoreWithOut().durationTime });
|
||||||
.query("queryAlarmTagKeys")
|
|
||||||
.params({ duration: useAppStoreWithOut().durationTime });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
async getAlarmTagValues(tagKey: string) {
|
async getAlarmTagValues(tagKey: string) {
|
||||||
const res: AxiosResponse = await graphql
|
return await graphql.query("queryAlarmTagValues").params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
||||||
.query("queryAlarmTagValues")
|
|
||||||
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,6 @@ import { store } from "@/store";
|
|||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { Duration, DurationTime } from "@/types/app";
|
import type { Duration, DurationTime } from "@/types/app";
|
||||||
import getLocalTime from "@/utils/localtime";
|
import getLocalTime from "@/utils/localtime";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
||||||
import { TimeType } from "@/constants/data";
|
import { TimeType } from "@/constants/data";
|
||||||
import type { MenuOptions, SubItem } from "@/types/app";
|
import type { MenuOptions, SubItem } from "@/types/app";
|
||||||
@ -118,12 +117,6 @@ export const appStore = defineStore({
|
|||||||
actions: {
|
actions: {
|
||||||
setDuration(data: Duration): void {
|
setDuration(data: Duration): void {
|
||||||
this.durationRow = data;
|
this.durationRow = data;
|
||||||
if ((window as any).axiosCancel.length !== 0) {
|
|
||||||
for (const event of (window as any).axiosCancel) {
|
|
||||||
setTimeout(event(), 0);
|
|
||||||
}
|
|
||||||
(window as any).axiosCancel = [];
|
|
||||||
}
|
|
||||||
this.runEventStack();
|
this.runEventStack();
|
||||||
},
|
},
|
||||||
updateDurationRow(data: Duration) {
|
updateDurationRow(data: Duration) {
|
||||||
@ -185,11 +178,11 @@ export const appStore = defineStore({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
async queryOAPTimeInfo() {
|
async queryOAPTimeInfo() {
|
||||||
const res: AxiosResponse = await graphql.query("queryOAPTimeInfo").params({});
|
const res = await graphql.query("queryOAPTimeInfo").params({});
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
this.utc = -(new Date().getTimezoneOffset() / 60) + ":0";
|
this.utc = -(new Date().getTimezoneOffset() / 60) + ":0";
|
||||||
} else {
|
} else {
|
||||||
this.utc = res.data.data.getTimeInfo.timezone / 100 + ":0";
|
this.utc = res.data.getTimeInfo.timezone / 100 + ":0";
|
||||||
}
|
}
|
||||||
const utcArr = this.utc.split(":");
|
const utcArr = this.utc.split(":");
|
||||||
this.utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
this.utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||||
@ -197,21 +190,21 @@ export const appStore = defineStore({
|
|||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async fetchVersion(): Promise<void> {
|
async fetchVersion() {
|
||||||
const res: AxiosResponse = await graphql.query("queryOAPVersion").params({});
|
const res = await graphql.query("queryOAPVersion").params({});
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
this.version = res.data.data.version;
|
this.version = res.data.version;
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async queryMenuItems() {
|
async queryMenuItems() {
|
||||||
const res: AxiosResponse = await graphql.query("queryMenuItems").params({});
|
const res = await graphql.query("queryMenuItems").params({});
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
setReloadTimer(timer: IntervalHandle) {
|
setReloadTimer(timer: IntervalHandle) {
|
||||||
this.reloadTimer = timer;
|
this.reloadTimer = timer;
|
||||||
|
138
src/store/modules/async-profiling.ts
Normal file
138
src/store/modules/async-profiling.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
AsyncProfilingTask,
|
||||||
|
AsyncProfileTaskCreationRequest,
|
||||||
|
AsyncProfilerStackElement,
|
||||||
|
AsyncProfilerTaskProgress,
|
||||||
|
} from "@/types/async-profiling";
|
||||||
|
import { store } from "@/store";
|
||||||
|
import graphql from "@/graphql";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import type { Instance } from "@/types/selector";
|
||||||
|
|
||||||
|
interface AsyncProfilingState {
|
||||||
|
taskList: Array<Recordable<AsyncProfilingTask>>;
|
||||||
|
selectedTask: Recordable<AsyncProfilingTask>;
|
||||||
|
taskProgress: Recordable<AsyncProfilerTaskProgress>;
|
||||||
|
instances: Instance[];
|
||||||
|
analyzeTrees: AsyncProfilerStackElement[];
|
||||||
|
loadingTree: boolean;
|
||||||
|
loadingTasks: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const asyncProfilingStore = defineStore({
|
||||||
|
id: "asyncProfiling",
|
||||||
|
state: (): AsyncProfilingState => ({
|
||||||
|
taskList: [],
|
||||||
|
selectedTask: {},
|
||||||
|
taskProgress: {},
|
||||||
|
instances: [],
|
||||||
|
analyzeTrees: [],
|
||||||
|
loadingTree: false,
|
||||||
|
loadingTasks: false,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
setSelectedTask(task: Recordable<AsyncProfilingTask>) {
|
||||||
|
this.selectedTask = task || {};
|
||||||
|
},
|
||||||
|
setAnalyzeTrees(tree: AsyncProfilerStackElement[]) {
|
||||||
|
this.analyzeTrees = tree;
|
||||||
|
},
|
||||||
|
async getTaskList() {
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
this.loadingTasks = true;
|
||||||
|
const response = await graphql.query("getAsyncTaskList").params({
|
||||||
|
request: {
|
||||||
|
serviceId: selectorStore.currentService.id,
|
||||||
|
limit: 10000,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.loadingTasks = false;
|
||||||
|
if (response.errors) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
this.taskList = response.data.asyncTaskList.tasks || [];
|
||||||
|
this.selectedTask = this.taskList[0] || {};
|
||||||
|
this.setAnalyzeTrees([]);
|
||||||
|
this.setSelectedTask(this.selectedTask);
|
||||||
|
if (!this.taskList.length) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
async getTaskLogs(param: { taskID: string }) {
|
||||||
|
const response = await graphql.query("getAsyncProfileTaskProcess").params(param);
|
||||||
|
|
||||||
|
if (response.errors) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
this.taskProgress = response.data.taskProgress;
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
async getServiceInstances(param: { serviceId: string; isRelation: boolean }) {
|
||||||
|
if (!param.serviceId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const response = await graphql.query("queryInstances").params({
|
||||||
|
serviceId: param.serviceId,
|
||||||
|
duration: useAppStoreWithOut().durationTime,
|
||||||
|
});
|
||||||
|
if (!response.errors) {
|
||||||
|
this.instances = (response.data.pods || []).map((d: Instance) => {
|
||||||
|
d.value = d.id || "";
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
async createTask(param: AsyncProfileTaskCreationRequest) {
|
||||||
|
const response = await graphql.query("saveAsyncProfileTask").params({ asyncProfilerTaskCreationRequest: param });
|
||||||
|
|
||||||
|
if (response.errors) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
this.getTaskList();
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
async getAsyncProfilingAnalyze(params: { taskId: string; instanceIds: Array<string>; eventType: string }) {
|
||||||
|
if (!params.instanceIds.length) {
|
||||||
|
return new Promise((resolve) => resolve({}));
|
||||||
|
}
|
||||||
|
this.loadingTree = true;
|
||||||
|
const response = await graphql.query("getAsyncProfileAnalyze").params({ request: params });
|
||||||
|
this.loadingTree = false;
|
||||||
|
if (response.errors) {
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
const { analysisResult } = response.data;
|
||||||
|
if (!analysisResult) {
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
this.analyzeTrees = [analysisResult.tree];
|
||||||
|
return response;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useAsyncProfilingStore(): Recordable {
|
||||||
|
return asyncProfilingStore(store);
|
||||||
|
}
|
@ -21,7 +21,6 @@ import type { Instance } from "@/types/selector";
|
|||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { MonitorInstance, MonitorProcess } from "@/types/continous-profiling";
|
import type { MonitorInstance, MonitorProcess } from "@/types/continous-profiling";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { dateFormat } from "@/utils/dateFormat";
|
import { dateFormat } from "@/utils/dateFormat";
|
||||||
|
|
||||||
interface ContinousProfilingState {
|
interface ContinousProfilingState {
|
||||||
@ -84,37 +83,37 @@ export const continousProfilingStore = defineStore({
|
|||||||
checkItems: CheckItems[];
|
checkItems: CheckItems[];
|
||||||
}[],
|
}[],
|
||||||
) {
|
) {
|
||||||
const res: AxiosResponse = await graphql.query("editStrategy").params({
|
const response = await graphql.query("editStrategy").params({
|
||||||
request: {
|
request: {
|
||||||
serviceId,
|
serviceId,
|
||||||
targets,
|
targets,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getStrategyList(params: { serviceId: string }) {
|
async getStrategyList(params: { serviceId: string }) {
|
||||||
if (!params.serviceId) {
|
if (!params.serviceId) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
this.policyLoading = true;
|
this.policyLoading = true;
|
||||||
const res: AxiosResponse = await graphql.query("getStrategyList").params(params);
|
const response = await graphql.query("getStrategyList").params(params);
|
||||||
|
|
||||||
this.policyLoading = false;
|
this.policyLoading = false;
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const list = res.data.data.strategyList || [];
|
const list = response.data.strategyList || [];
|
||||||
if (!list.length) {
|
if (!list.length) {
|
||||||
this.taskList = [];
|
this.taskList = [];
|
||||||
this.instances = [];
|
this.instances = [];
|
||||||
this.instance = null;
|
this.instance = null;
|
||||||
}
|
}
|
||||||
const arr = list.length ? res.data.data.strategyList : [{ type: "", checkItems: [{ type: "" }] }];
|
const arr = list.length ? response.data.strategyList : [{ type: "", checkItems: [{ type: "" }] }];
|
||||||
this.strategyList = arr.map((d: StrategyItem, index: number) => {
|
this.strategyList = arr.map((d: StrategyItem, index: number) => {
|
||||||
return {
|
return {
|
||||||
...d,
|
...d,
|
||||||
@ -123,25 +122,25 @@ export const continousProfilingStore = defineStore({
|
|||||||
});
|
});
|
||||||
this.setSelectedStrategy(this.strategyList[0]);
|
this.setSelectedStrategy(this.strategyList[0]);
|
||||||
if (!this.selectedStrategy.type) {
|
if (!this.selectedStrategy.type) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.getMonitoringInstances(params.serviceId);
|
this.getMonitoringInstances(params.serviceId);
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getMonitoringInstances(serviceId: string): Promise<Nullable<AxiosResponse>> {
|
async getMonitoringInstances(serviceId: string) {
|
||||||
this.instancesLoading = true;
|
this.instancesLoading = true;
|
||||||
if (!serviceId) {
|
if (!serviceId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getMonitoringInstances").params({
|
const response = await graphql.query("getMonitoringInstances").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
target: this.selectedStrategy.type,
|
target: this.selectedStrategy.type,
|
||||||
});
|
});
|
||||||
this.instancesLoading = false;
|
this.instancesLoading = false;
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.instances = (res.data.data.instances || [])
|
this.instances = (response.data.instances || [])
|
||||||
.map((d: MonitorInstance) => {
|
.map((d: MonitorInstance) => {
|
||||||
const processes = (d.processes || [])
|
const processes = (d.processes || [])
|
||||||
.sort((c: MonitorProcess, d: MonitorProcess) => d.lastTriggerTimestamp - c.lastTriggerTimestamp)
|
.sort((c: MonitorProcess, d: MonitorProcess) => d.lastTriggerTimestamp - c.lastTriggerTimestamp)
|
||||||
@ -161,7 +160,7 @@ export const continousProfilingStore = defineStore({
|
|||||||
})
|
})
|
||||||
.sort((a: MonitorInstance, b: MonitorInstance) => b.lastTriggerTimestamp - a.lastTriggerTimestamp);
|
.sort((a: MonitorInstance, b: MonitorInstance) => b.lastTriggerTimestamp - a.lastTriggerTimestamp);
|
||||||
this.instance = this.instances[0] || null;
|
this.instance = this.instances[0] || null;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -18,11 +18,10 @@ import { defineStore } from "pinia";
|
|||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import query from "@/graphql/fetch";
|
import fetchQuery from "@/graphql/fetch";
|
||||||
import type { DashboardItem } from "@/types/dashboard";
|
import type { DashboardItem } from "@/types/dashboard";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from "../data";
|
import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from "../data";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { EntityType, WidgetType } from "@/views/dashboard/data";
|
import { EntityType, WidgetType } from "@/views/dashboard/data";
|
||||||
interface DashboardState {
|
interface DashboardState {
|
||||||
@ -299,37 +298,20 @@ export const dashboardStore = defineStore({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async fetchMetricType(item: string) {
|
|
||||||
const res: AxiosResponse = await graphql.query("queryTypeOfMetrics").params({ name: item });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
|
||||||
async getTypeOfMQE(expression: string) {
|
|
||||||
const res: AxiosResponse = await graphql.query("getTypeOfMQE").params({ expression });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
|
||||||
async fetchMetricList(regex: string) {
|
|
||||||
const res: AxiosResponse = await graphql.query("queryMetrics").params({ regex });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
|
||||||
async fetchMetricValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
async fetchMetricValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
||||||
const res: AxiosResponse = await query(param);
|
return await fetchQuery(param);
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
async fetchTemplates() {
|
async fetchTemplates() {
|
||||||
const res: AxiosResponse = await graphql.query("getTemplates").params({});
|
const res = await graphql.query("getTemplates").params({});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
const data = res.data.data.getAllTemplates;
|
const data = res.data.getAllTemplates;
|
||||||
let list = [];
|
let list = [];
|
||||||
for (const t of data) {
|
for (const t of data) {
|
||||||
const c = JSON.parse(t.configuration);
|
const c = JSON.parse(t.configuration);
|
||||||
const key = [c.layer, c.entity, c.name].join("_");
|
const key = [c.layer, c.entity, c.name].join("_");
|
||||||
|
|
||||||
list.push({
|
list.push({
|
||||||
...c,
|
...c,
|
||||||
id: t.id,
|
id: t.id,
|
||||||
@ -372,20 +354,20 @@ export const dashboardStore = defineStore({
|
|||||||
this.dashboards = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
this.dashboards = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
},
|
},
|
||||||
async updateDashboard(setting: { id: string; configuration: string }) {
|
async updateDashboard(setting: { id: string; configuration: string }) {
|
||||||
const res: AxiosResponse = await graphql.query("updateTemplate").params({
|
const resp = await graphql.query("updateTemplate").params({
|
||||||
setting,
|
setting,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (resp.errors) {
|
||||||
ElMessage.error(res.data.errors);
|
ElMessage.error(resp.errors);
|
||||||
return res.data;
|
return resp;
|
||||||
}
|
}
|
||||||
const json = res.data.data.changeTemplate;
|
const json = resp.data.changeTemplate;
|
||||||
if (!json.status) {
|
if (!json.status) {
|
||||||
ElMessage.error(json.message);
|
ElMessage.error(json.message);
|
||||||
return res.data;
|
return resp;
|
||||||
}
|
}
|
||||||
ElMessage.success("Saved successfully");
|
ElMessage.success("Saved successfully");
|
||||||
return res.data;
|
return resp;
|
||||||
},
|
},
|
||||||
async saveDashboard() {
|
async saveDashboard() {
|
||||||
if (!this.currentDashboard?.name) {
|
if (!this.currentDashboard?.name) {
|
||||||
@ -419,14 +401,14 @@ export const dashboardStore = defineStore({
|
|||||||
}
|
}
|
||||||
res = await graphql.query("addNewTemplate").params({ setting: { configuration: JSON.stringify(c) } });
|
res = await graphql.query("addNewTemplate").params({ setting: { configuration: JSON.stringify(c) } });
|
||||||
|
|
||||||
json = res.data.data.addTemplate;
|
json = res.data.addTemplate;
|
||||||
if (!json.status) {
|
if (!json.status) {
|
||||||
ElMessage.error(json.message);
|
ElMessage.error(json.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (res.data.errors || res.errors) {
|
if (res.errors) {
|
||||||
ElMessage.error(res.data.errors);
|
ElMessage.error(res.errors);
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
if (!json.status) {
|
if (!json.status) {
|
||||||
return json;
|
return json;
|
||||||
@ -448,16 +430,16 @@ export const dashboardStore = defineStore({
|
|||||||
return json;
|
return json;
|
||||||
},
|
},
|
||||||
async deleteDashboard() {
|
async deleteDashboard() {
|
||||||
const res: AxiosResponse = await graphql.query("removeTemplate").params({ id: this.currentDashboard?.id });
|
const res = await graphql.query("removeTemplate").params({ id: this.currentDashboard?.id });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
ElMessage.error(res.data.errors);
|
ElMessage.error(res.errors);
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
const json = res.data.data.disableTemplate;
|
const json = res.data.disableTemplate;
|
||||||
if (!json.status) {
|
if (!json.status) {
|
||||||
ElMessage.error(json.message);
|
ElMessage.error(json.message);
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
this.dashboards = this.dashboards.filter((d: Recordable) => d.id !== this.currentDashboard?.id);
|
this.dashboards = this.dashboards.filter((d: Recordable) => d.id !== this.currentDashboard?.id);
|
||||||
const key = [this.currentDashboard?.layer, this.currentDashboard?.entity, this.currentDashboard?.name].join("_");
|
const key = [this.currentDashboard?.layer, this.currentDashboard?.entity, this.currentDashboard?.name].join("_");
|
||||||
|
@ -18,7 +18,6 @@ import { defineStore } from "pinia";
|
|||||||
import type { Instance } from "@/types/selector";
|
import type { Instance } from "@/types/selector";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import type { Conditions, Log } from "@/types/demand-log";
|
import type { Conditions, Log } from "@/types/demand-log";
|
||||||
@ -60,16 +59,16 @@ export const demandLogStore = defineStore({
|
|||||||
},
|
},
|
||||||
async getInstances(id: string) {
|
async getInstances(id: string) {
|
||||||
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
||||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
const response = await graphql.query("queryInstances").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.instances = res.data.data.pods || [];
|
this.instances = response.data.pods || [];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getContainers(serviceInstanceId: string) {
|
async getContainers(serviceInstanceId: string) {
|
||||||
if (!serviceInstanceId) {
|
if (!serviceInstanceId) {
|
||||||
@ -78,35 +77,35 @@ export const demandLogStore = defineStore({
|
|||||||
const condition = {
|
const condition = {
|
||||||
serviceInstanceId,
|
serviceInstanceId,
|
||||||
};
|
};
|
||||||
const res: AxiosResponse = await graphql.query("fetchContainers").params({ condition });
|
const response = await graphql.query("fetchContainers").params({ condition });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
if (res.data.data.containers.errorReason) {
|
if (response.data.containers.errorReason) {
|
||||||
this.containers = [{ label: "", value: "" }];
|
this.containers = [{ label: "", value: "" }];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.containers = res.data.data.containers.containers.map((d: string) => {
|
this.containers = response.data.containers.containers.map((d: string) => {
|
||||||
return { label: d, value: d };
|
return { label: d, value: d };
|
||||||
});
|
});
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getDemandLogs() {
|
async getDemandLogs() {
|
||||||
this.loadLogs = true;
|
this.loadLogs = true;
|
||||||
const res: AxiosResponse = await graphql.query("fetchDemandPodLogs").params({ condition: this.conditions });
|
const response = await graphql.query("fetchDemandPodLogs").params({ condition: this.conditions });
|
||||||
this.loadLogs = false;
|
this.loadLogs = false;
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
if (res.data.data.logs.errorReason) {
|
if (response.data.logs.errorReason) {
|
||||||
this.setLogs([], res.data.data.logs.errorReason);
|
this.setLogs([], response.data.logs.errorReason);
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.total = res.data.data.logs.logs.length;
|
this.total = response.data.logs.logs.length;
|
||||||
const logs = res.data.data.logs.logs.map((d: Log) => d.content).join("\n");
|
const logs = response.data.logs.logs.map((d: Log) => d.content).join("\n");
|
||||||
this.setLogs(logs);
|
this.setLogs(logs);
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -19,7 +19,6 @@ import type { Option } from "@/types/app";
|
|||||||
import type { EBPFTaskCreationRequest, EBPFProfilingSchedule, EBPFTaskList, AnalyzationTrees } from "@/types/ebpf";
|
import type { EBPFTaskCreationRequest, EBPFProfilingSchedule, EBPFTaskList, AnalyzationTrees } from "@/types/ebpf";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { EBPFProfilingTriggerType } from "../data";
|
import { EBPFProfilingTriggerType } from "../data";
|
||||||
interface EbpfState {
|
interface EbpfState {
|
||||||
taskList: Array<Recordable<EBPFTaskList>>;
|
taskList: Array<Recordable<EBPFTaskList>>;
|
||||||
@ -57,70 +56,70 @@ export const ebpfStore = defineStore({
|
|||||||
this.analyzeTrees = tree;
|
this.analyzeTrees = tree;
|
||||||
},
|
},
|
||||||
async getCreateTaskData(serviceId: string) {
|
async getCreateTaskData(serviceId: string) {
|
||||||
const res: AxiosResponse = await graphql.query("getCreateTaskData").params({ serviceId });
|
const response = await graphql.query("getCreateTaskData").params({ serviceId });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const json = res.data.data.createTaskData;
|
const json = response.data.createTaskData;
|
||||||
this.couldProfiling = json.couldProfiling || false;
|
this.couldProfiling = json.couldProfiling || false;
|
||||||
this.labels = json.processLabels.map((d: string) => {
|
this.labels = json.processLabels.map((d: string) => {
|
||||||
return { label: d, value: d };
|
return { label: d, value: d };
|
||||||
});
|
});
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async createTask(param: EBPFTaskCreationRequest) {
|
async createTask(param: EBPFTaskCreationRequest) {
|
||||||
const res: AxiosResponse = await graphql.query("saveEBPFTask").params({ request: param });
|
const response = await graphql.query("saveEBPFTask").params({ request: param });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.getTaskList({
|
this.getTaskList({
|
||||||
serviceId: param.serviceId,
|
serviceId: param.serviceId,
|
||||||
targets: ["ON_CPU", "OFF_CPU"],
|
targets: ["ON_CPU", "OFF_CPU"],
|
||||||
triggerType: EBPFProfilingTriggerType.FIXED_TIME,
|
triggerType: EBPFProfilingTriggerType.FIXED_TIME,
|
||||||
});
|
});
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getTaskList(params: { serviceId: string; targets: string[] }) {
|
async getTaskList(params: { serviceId: string; targets: string[] }) {
|
||||||
if (!params.serviceId) {
|
if (!params.serviceId) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
const response = await graphql.query("getEBPFTasks").params(params);
|
||||||
|
|
||||||
this.ebpfTips = "";
|
this.ebpfTips = "";
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.taskList = res.data.data.queryEBPFTasks || [];
|
this.taskList = response.data.queryEBPFTasks || [];
|
||||||
this.selectedTask = this.taskList[0] || {};
|
this.selectedTask = this.taskList[0] || {};
|
||||||
this.setSelectedTask(this.selectedTask);
|
this.setSelectedTask(this.selectedTask);
|
||||||
if (!this.taskList.length) {
|
if (!this.taskList.length) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.getEBPFSchedules({ taskId: String(this.taskList[0].taskId) });
|
this.getEBPFSchedules({ taskId: String(this.taskList[0].taskId) });
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getEBPFSchedules(params: { taskId: string }) {
|
async getEBPFSchedules(params: { taskId: string }) {
|
||||||
if (!params.taskId) {
|
if (!params.taskId) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFSchedules").params({ ...params });
|
const response = await graphql.query("getEBPFSchedules").params({ ...params });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
this.eBPFSchedules = [];
|
this.eBPFSchedules = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.ebpfTips = "";
|
this.ebpfTips = "";
|
||||||
const { eBPFSchedules } = res.data.data;
|
const { eBPFSchedules } = response.data;
|
||||||
|
|
||||||
this.eBPFSchedules = eBPFSchedules;
|
this.eBPFSchedules = eBPFSchedules;
|
||||||
if (!eBPFSchedules.length) {
|
if (!eBPFSchedules.length) {
|
||||||
this.eBPFSchedules = [];
|
this.eBPFSchedules = [];
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
}
|
}
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getEBPFAnalyze(params: {
|
async getEBPFAnalyze(params: {
|
||||||
scheduleIdList: string[];
|
scheduleIdList: string[];
|
||||||
@ -134,24 +133,24 @@ export const ebpfStore = defineStore({
|
|||||||
if (!params.timeRanges.length) {
|
if (!params.timeRanges.length) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFResult").params(params);
|
const response = await graphql.query("getEBPFResult").params(params);
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const { analysisEBPFResult } = res.data.data;
|
const { analysisEBPFResult } = response.data;
|
||||||
this.ebpfTips = analysisEBPFResult.tip;
|
this.ebpfTips = analysisEBPFResult.tip;
|
||||||
if (!analysisEBPFResult) {
|
if (!analysisEBPFResult) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
if (analysisEBPFResult.tip) {
|
if (analysisEBPFResult.tip) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.analyzeTrees = analysisEBPFResult.trees;
|
this.analyzeTrees = analysisEBPFResult.trees;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import type { Event, QueryEventCondition } from "@/types/events";
|
import type { Event, QueryEventCondition } from "@/types/events";
|
||||||
import type { Instance, Endpoint } from "@/types/selector";
|
import type { Instance, Endpoint } from "@/types/selector";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { EndpointsTopNDefault } from "../data";
|
||||||
|
|
||||||
interface eventState {
|
interface eventState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@ -46,47 +46,48 @@ export const eventStore = defineStore({
|
|||||||
},
|
},
|
||||||
async getInstances() {
|
async getInstances() {
|
||||||
const serviceId = useSelectorStore().currentService ? useSelectorStore().currentService.id : "";
|
const serviceId = useSelectorStore().currentService ? useSelectorStore().currentService.id : "";
|
||||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
const response = await graphql.query("queryInstances").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.instances = [{ value: "", label: "All" }, ...res.data.data.pods] || [{ value: "", label: "All" }];
|
this.instances = [{ value: "", label: "All" }, ...response.data.pods];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getEndpoints(keyword: string) {
|
async getEndpoints(keyword: string) {
|
||||||
const serviceId = useSelectorStore().currentService ? useSelectorStore().currentService.id : "";
|
const serviceId = useSelectorStore().currentService ? useSelectorStore().currentService.id : "";
|
||||||
if (!serviceId) {
|
if (!serviceId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
const response = await graphql.query("queryEndpoints").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
keyword: keyword || "",
|
keyword: keyword || "",
|
||||||
|
limit: EndpointsTopNDefault,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods] || [{ value: "", label: "All" }];
|
this.endpoints = [{ value: "", label: "All" }, ...response.data.pods];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getEvents() {
|
async getEvents() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const res: AxiosResponse = await graphql.query("queryEvents").params({
|
const response = await graphql.query("queryEvents").params({
|
||||||
condition: {
|
condition: {
|
||||||
...this.condition,
|
...this.condition,
|
||||||
time: useAppStoreWithOut().durationTime,
|
time: useAppStoreWithOut().durationTime,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
if (res.data.data.fetchEvents) {
|
if (response.data.fetchEvents) {
|
||||||
this.events = (res.data.data.fetchEvents.events || []).map((item: Event) => {
|
this.events = (response.data.fetchEvents.events || []).map((item: Event) => {
|
||||||
let scope = "Service";
|
let scope = "Service";
|
||||||
if (item.source.serviceInstance) {
|
if (item.source.serviceInstance) {
|
||||||
scope = "ServiceInstance";
|
scope = "ServiceInstance";
|
||||||
@ -101,7 +102,7 @@ export const eventStore = defineStore({
|
|||||||
return item;
|
return item;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -18,10 +18,10 @@ import { defineStore } from "pinia";
|
|||||||
import type { Instance, Endpoint, Service } from "@/types/selector";
|
import type { Instance, Endpoint, Service } from "@/types/selector";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { EndpointsTopNDefault } from "../data";
|
||||||
|
|
||||||
interface LogState {
|
interface LogState {
|
||||||
services: Service[];
|
services: Service[];
|
||||||
@ -61,50 +61,51 @@ export const logStore = defineStore({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
async getServices(layer: string) {
|
async getServices(layer: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
const response = await graphql.query("queryServices").params({
|
||||||
layer,
|
layer,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.services = res.data.data.services;
|
this.services = response.data.services;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getInstances(id: string) {
|
async getInstances(id: string) {
|
||||||
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
||||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
const response = await graphql.query("queryInstances").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.instances = [{ value: "0", label: "All" }, ...res.data.data.pods] || [{ value: " 0", label: "All" }];
|
this.instances = [{ value: "0", label: "All" }, ...response.data.pods];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getEndpoints(id: string, keyword?: string) {
|
async getEndpoints(id: string, keyword?: string) {
|
||||||
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
const response = await graphql.query("queryEndpoints").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
keyword: keyword || "",
|
keyword: keyword || "",
|
||||||
|
limit: EndpointsTopNDefault,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.endpoints = [{ value: "0", label: "All" }, ...res.data.data.pods] || [{ value: "0", label: "All" }];
|
this.endpoints = [{ value: "0", label: "All" }, ...response.data.pods];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getLogsByKeywords() {
|
async getLogsByKeywords() {
|
||||||
const res: AxiosResponse = await graphql.query("queryLogsByKeywords").params({});
|
const response = await graphql.query("queryLogsByKeywords").params({});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.supportQueryLogsByKeywords = res.data.data.support;
|
this.supportQueryLogsByKeywords = response.data.support;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getLogs() {
|
async getLogs() {
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@ -115,39 +116,31 @@ export const logStore = defineStore({
|
|||||||
},
|
},
|
||||||
async getServiceLogs() {
|
async getServiceLogs() {
|
||||||
this.loadLogs = true;
|
this.loadLogs = true;
|
||||||
const res: AxiosResponse = await graphql.query("queryServiceLogs").params({ condition: this.conditions });
|
const response = await graphql.query("queryServiceLogs").params({ condition: this.conditions });
|
||||||
this.loadLogs = false;
|
this.loadLogs = false;
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logs = res.data.data.queryLogs.logs;
|
this.logs = response.data.queryLogs.logs;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getBrowserLogs() {
|
async getBrowserLogs() {
|
||||||
this.loadLogs = true;
|
this.loadLogs = true;
|
||||||
const res: AxiosResponse = await graphql.query("queryBrowserErrorLogs").params({ condition: this.conditions });
|
const response = await graphql.query("queryBrowserErrorLogs").params({ condition: this.conditions });
|
||||||
|
|
||||||
this.loadLogs = false;
|
this.loadLogs = false;
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.logs = res.data.data.queryBrowserErrorLogs.logs;
|
this.logs = response.data.queryBrowserErrorLogs.logs;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getLogTagKeys() {
|
async getLogTagKeys() {
|
||||||
const res: AxiosResponse = await graphql
|
return await graphql.query("queryLogTagKeys").params({ duration: useAppStoreWithOut().durationTime });
|
||||||
.query("queryLogTagKeys")
|
|
||||||
.params({ duration: useAppStoreWithOut().durationTime });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
async getLogTagValues(tagKey: string) {
|
async getLogTagValues(tagKey: string) {
|
||||||
const res: AxiosResponse = await graphql
|
return await graphql.query("queryLogTagValues").params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
||||||
.query("queryLogTagValues")
|
|
||||||
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,6 @@ import { defineStore } from "pinia";
|
|||||||
import type { EBPFTaskList, ProcessNode } from "@/types/ebpf";
|
import type { EBPFTaskList, ProcessNode } from "@/types/ebpf";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import type { Call } from "@/types/topology";
|
import type { Call } from "@/types/topology";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
@ -126,65 +125,65 @@ export const networkProfilingStore = defineStore({
|
|||||||
minDuration: number;
|
minDuration: number;
|
||||||
}[],
|
}[],
|
||||||
) {
|
) {
|
||||||
const res: AxiosResponse = await graphql.query("newNetworkProfiling").params({
|
const response = await graphql.query("newNetworkProfiling").params({
|
||||||
request: {
|
request: {
|
||||||
instanceId,
|
instanceId,
|
||||||
samplings: params,
|
samplings: params,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getTaskList(params: { serviceId: string; serviceInstanceId: string; targets: string[] }) {
|
async getTaskList(params: { serviceId: string; serviceInstanceId: string; targets: string[] }) {
|
||||||
if (!params.serviceId) {
|
if (!params.serviceId) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
const response = await graphql.query("getEBPFTasks").params(params);
|
||||||
|
|
||||||
this.networkTip = "";
|
this.networkTip = "";
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.networkTasks = res.data.data.queryEBPFTasks || [];
|
this.networkTasks = response.data.queryEBPFTasks || [];
|
||||||
this.selectedNetworkTask = this.networkTasks[0] || {};
|
this.selectedNetworkTask = this.networkTasks[0] || {};
|
||||||
this.setSelectedNetworkTask(this.selectedNetworkTask);
|
this.setSelectedNetworkTask(this.selectedNetworkTask);
|
||||||
if (!this.networkTasks.length) {
|
if (!this.networkTasks.length) {
|
||||||
this.nodes = [];
|
this.nodes = [];
|
||||||
this.calls = [];
|
this.calls = [];
|
||||||
}
|
}
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async keepNetworkProfiling(taskId: string) {
|
async keepNetworkProfiling(taskId: string) {
|
||||||
if (!taskId) {
|
if (!taskId) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("aliveNetworkProfiling").params({ taskId });
|
const response = await graphql.query("aliveNetworkProfiling").params({ taskId });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.aliveNetwork = res.data.data.keepEBPFNetworkProfiling.status;
|
this.aliveNetwork = response.data.keepEBPFNetworkProfiling.status;
|
||||||
if (!this.aliveNetwork) {
|
if (!this.aliveNetwork) {
|
||||||
ElMessage.warning(res.data.data.keepEBPFNetworkProfiling.errorReason);
|
ElMessage.warning(response.data.keepEBPFNetworkProfiling.errorReason);
|
||||||
}
|
}
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getProcessTopology(params: { duration: DurationTime; serviceInstanceId: string }) {
|
async getProcessTopology(params: { duration: DurationTime; serviceInstanceId: string }) {
|
||||||
this.loadNodes = true;
|
this.loadNodes = true;
|
||||||
const res: AxiosResponse = await graphql.query("getProcessTopology").params(params);
|
const response = await graphql.query("getProcessTopology").params(params);
|
||||||
this.loadNodes = false;
|
this.loadNodes = false;
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
this.nodes = [];
|
this.nodes = [];
|
||||||
this.calls = [];
|
this.calls = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const { topology } = res.data.data;
|
const { topology } = response.data;
|
||||||
|
|
||||||
this.setTopology(topology);
|
this.setTopology(topology);
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -26,8 +26,8 @@ import type {
|
|||||||
import type { Trace } from "@/types/trace";
|
import type { Trace } from "@/types/trace";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { EndpointsTopNDefault } from "../data";
|
||||||
|
|
||||||
interface ProfileState {
|
interface ProfileState {
|
||||||
endpoints: Endpoint[];
|
endpoints: Endpoint[];
|
||||||
@ -80,7 +80,7 @@ export const profileStore = defineStore({
|
|||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
},
|
},
|
||||||
setCurrentSegment(segment: Trace) {
|
setCurrentSegment(segment: Trace) {
|
||||||
this.currentSegment = segment;
|
this.currentSegment = segment || {};
|
||||||
this.segmentSpans = segment.spans || [];
|
this.segmentSpans = segment.spans || [];
|
||||||
if (segment.spans) {
|
if (segment.spans) {
|
||||||
this.currentSpan = segment.spans[0] || {};
|
this.currentSpan = segment.spans[0] || {};
|
||||||
@ -93,36 +93,38 @@ export const profileStore = defineStore({
|
|||||||
this.highlightTop = !this.highlightTop;
|
this.highlightTop = !this.highlightTop;
|
||||||
},
|
},
|
||||||
async getEndpoints(serviceId: string, keyword?: string) {
|
async getEndpoints(serviceId: string, keyword?: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
const response = await graphql.query("queryEndpoints").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
keyword: keyword || "",
|
keyword: keyword || "",
|
||||||
|
limit: EndpointsTopNDefault,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.endpoints = res.data.data.pods || [];
|
this.endpoints = response.data.pods || [];
|
||||||
return res.data;
|
return response.data;
|
||||||
},
|
},
|
||||||
async getTaskEndpoints(serviceId: string, keyword?: string) {
|
async getTaskEndpoints(serviceId: string, keyword?: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
const response = await graphql.query("queryEndpoints").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
keyword: keyword || "",
|
keyword: keyword || "",
|
||||||
|
limit: EndpointsTopNDefault,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.taskEndpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
this.taskEndpoints = [{ value: "", label: "All" }, ...response.data.pods];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getTaskList() {
|
async getTaskList() {
|
||||||
const res: AxiosResponse = await graphql.query("getProfileTaskList").params(this.condition);
|
const response = await graphql.query("getProfileTaskList").params(this.condition);
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const list = res.data.data.taskList || [];
|
const list = response.data.taskList || [];
|
||||||
this.taskList = list;
|
this.taskList = list;
|
||||||
this.currentTask = list[0] || {};
|
this.currentTask = list[0] || {};
|
||||||
if (!list.length) {
|
if (!list.length) {
|
||||||
@ -130,52 +132,52 @@ export const profileStore = defineStore({
|
|||||||
this.segmentSpans = [];
|
this.segmentSpans = [];
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
|
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.getSegmentList({ taskID: list[0].id });
|
this.getSegmentList({ taskID: list[0].id });
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getSegmentList(params: { taskID: string }) {
|
async getSegmentList(params: { taskID: string }) {
|
||||||
if (!params.taskID) {
|
if (!params.taskID) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getProfileTaskSegmentList").params(params);
|
const response = await graphql.query("getProfileTaskSegmentList").params(params);
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
this.segmentList = [];
|
this.segmentList = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const { segmentList } = res.data.data;
|
const { segmentList } = response.data;
|
||||||
|
|
||||||
this.segmentList = segmentList || [];
|
this.segmentList = segmentList || [];
|
||||||
if (!segmentList.length) {
|
if (!segmentList.length) {
|
||||||
this.segmentSpans = [];
|
this.segmentSpans = [];
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
|
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
if (segmentList[0]) {
|
if (segmentList[0]) {
|
||||||
this.currentSegment = segmentList[0];
|
this.setCurrentSegment(segmentList[0]);
|
||||||
this.getSegmentSpans(segmentList[0].segmentId);
|
this.getSegmentSpans(segmentList[0].segmentId);
|
||||||
} else {
|
} else {
|
||||||
this.currentSegment = {};
|
this.setCurrentSegment({});
|
||||||
}
|
}
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getSegmentSpans(params: { segmentId: string }) {
|
async getSegmentSpans(params: { segmentId: string }) {
|
||||||
if (!(params && params.segmentId)) {
|
if (!(params && params.segmentId)) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryProfileSegment").params(params);
|
const response = await graphql.query("queryProfileSegment").params(params);
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
this.segmentSpans = [];
|
this.segmentSpans = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const { segment } = res.data.data;
|
const { segment } = response.data;
|
||||||
if (!segment) {
|
if (!segment) {
|
||||||
this.segmentSpans = [];
|
this.segmentSpans = [];
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.segmentSpans = segment.spans.map((d: SegmentSpan) => {
|
this.segmentSpans = segment.spans.map((d: SegmentSpan) => {
|
||||||
return {
|
return {
|
||||||
@ -186,52 +188,52 @@ export const profileStore = defineStore({
|
|||||||
});
|
});
|
||||||
if (!(segment.spans && segment.spans.length)) {
|
if (!(segment.spans && segment.spans.length)) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const index = segment.spans.length - 1 || 0;
|
const index = segment.spans.length - 1 || 0;
|
||||||
this.currentSpan = segment.spans[index];
|
this.currentSpan = segment.spans[index];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getProfileAnalyze(params: Array<{ segmentId: string; timeRange: { start: number; end: number } }>) {
|
async getProfileAnalyze(params: Array<{ segmentId: string; timeRange: { start: number; end: number } }>) {
|
||||||
if (!params.length) {
|
if (!params.length) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getProfileAnalyze").params({ queries: params });
|
const response = await graphql.query("getProfileAnalyze").params({ queries: params });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const { analyze, tip } = res.data.data;
|
const { analyze, tip } = response.data;
|
||||||
if (tip) {
|
if (tip) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!analyze) {
|
if (!analyze) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.analyzeTrees = analyze.trees;
|
this.analyzeTrees = analyze.trees;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async createTask(param: ProfileTaskCreationRequest) {
|
async createTask(param: ProfileTaskCreationRequest) {
|
||||||
const res: AxiosResponse = await graphql.query("saveProfileTask").params({ creationRequest: param });
|
const response = await graphql.query("saveProfileTask").params({ creationRequest: param });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.getTaskList();
|
this.getTaskList();
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getTaskLogs(param: { taskID: string }) {
|
async getTaskLogs(param: { taskID: string }) {
|
||||||
const res: AxiosResponse = await graphql.query("getProfileTaskLogs").params(param);
|
const response = await graphql.query("getProfileTaskLogs").params(param);
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.taskLogs = res.data.data.taskLogs;
|
this.taskLogs = response.data.taskLogs;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -18,8 +18,8 @@ import { defineStore } from "pinia";
|
|||||||
import type { Service, Instance, Endpoint, Process } from "@/types/selector";
|
import type { Service, Instance, Endpoint, Process } from "@/types/selector";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { EndpointsTopNDefault } from "../data";
|
||||||
interface SelectorState {
|
interface SelectorState {
|
||||||
services: Service[];
|
services: Service[];
|
||||||
destServices: Service[];
|
destServices: Service[];
|
||||||
@ -76,62 +76,55 @@ export const selectorStore = defineStore({
|
|||||||
setDestProcesses(processes: Array<Process>) {
|
setDestProcesses(processes: Array<Process>) {
|
||||||
this.destProcesses = processes;
|
this.destProcesses = processes;
|
||||||
},
|
},
|
||||||
async fetchLayers(): Promise<AxiosResponse> {
|
async fetchLayers() {
|
||||||
const res: AxiosResponse = await graphql.query("queryLayers").params({});
|
return await graphql.query("queryLayers").params({});
|
||||||
|
|
||||||
return res.data || {};
|
|
||||||
},
|
},
|
||||||
async fetchServices(layer: string): Promise<AxiosResponse> {
|
async fetchServices(layer: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServices").params({ layer });
|
const res = await graphql.query("queryServices").params({ layer });
|
||||||
|
|
||||||
if (!res.data.errors) {
|
if (!res.errors) {
|
||||||
this.services = res.data.data.services || [];
|
this.services = res.data.services || [];
|
||||||
this.destServices = res.data.data.services || [];
|
this.destServices = res.data.services || [];
|
||||||
}
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getServiceInstances(param?: { serviceId: string; isRelation: boolean }): Promise<Nullable<AxiosResponse>> {
|
async getServiceInstances(param?: { serviceId: string; isRelation: boolean }) {
|
||||||
const serviceId = param ? param.serviceId : this.currentService?.id;
|
const serviceId = param ? param.serviceId : this.currentService?.id;
|
||||||
if (!serviceId) {
|
if (!serviceId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
const resp = await graphql.query("queryInstances").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
});
|
});
|
||||||
if (!res.data.errors) {
|
if (!resp.errors) {
|
||||||
if (param && param.isRelation) {
|
if (param && param.isRelation) {
|
||||||
this.destPods = res.data.data.pods || [];
|
this.destPods = resp.data.pods || [];
|
||||||
return res.data;
|
return resp;
|
||||||
}
|
}
|
||||||
this.pods = res.data.data.pods || [];
|
this.pods = resp.data.pods || [];
|
||||||
}
|
}
|
||||||
return res.data;
|
return resp;
|
||||||
},
|
},
|
||||||
async getProcesses(param?: { instanceId: string; isRelation: boolean }): Promise<Nullable<AxiosResponse>> {
|
async getProcesses(param?: { instanceId: string; isRelation: boolean }) {
|
||||||
const instanceId = param ? param.instanceId : this.currentPod?.id;
|
const instanceId = param ? param.instanceId : this.currentPod?.id;
|
||||||
if (!instanceId) {
|
if (!instanceId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryProcesses").params({
|
const res = await graphql.query("queryProcesses").params({
|
||||||
instanceId,
|
instanceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
});
|
});
|
||||||
if (!res.data.errors) {
|
if (!res.errors) {
|
||||||
if (param && param.isRelation) {
|
if (param && param.isRelation) {
|
||||||
this.destProcesses = res.data.data.processes || [];
|
this.destProcesses = res.data.processes || [];
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
this.processes = res.data.data.processes || [];
|
this.processes = res.data.processes || [];
|
||||||
}
|
}
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async getEndpoints(params: {
|
async getEndpoints(params: { keyword?: string; serviceId?: string; isRelation?: boolean; limit?: number }) {
|
||||||
keyword?: string;
|
|
||||||
serviceId?: string;
|
|
||||||
isRelation?: boolean;
|
|
||||||
limit?: number;
|
|
||||||
}): Promise<Nullable<AxiosResponse>> {
|
|
||||||
if (!params) {
|
if (!params) {
|
||||||
params = {};
|
params = {};
|
||||||
}
|
}
|
||||||
@ -139,96 +132,96 @@ export const selectorStore = defineStore({
|
|||||||
if (!serviceId) {
|
if (!serviceId) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
const res = await graphql.query("queryEndpoints").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
keyword: params.keyword || "",
|
keyword: params.keyword || "",
|
||||||
limit: params.limit,
|
limit: params.limit || EndpointsTopNDefault,
|
||||||
});
|
});
|
||||||
if (!res.data.errors) {
|
if (!res.errors) {
|
||||||
if (params.isRelation) {
|
if (params.isRelation) {
|
||||||
this.destPods = res.data.data.pods || [];
|
this.destPods = res.data.pods || [];
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
this.pods = res.data.data.pods || [];
|
this.pods = res.data.pods || [];
|
||||||
}
|
}
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async getService(serviceId: string, isRelation: boolean) {
|
async getService(serviceId: string, isRelation: boolean) {
|
||||||
if (!serviceId) {
|
if (!serviceId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryService").params({
|
const res = await graphql.query("queryService").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
});
|
});
|
||||||
if (!res.data.errors) {
|
if (!res.errors) {
|
||||||
if (isRelation) {
|
if (isRelation) {
|
||||||
this.setCurrentDestService(res.data.data.service);
|
this.setCurrentDestService(res.data.service);
|
||||||
this.destServices = [res.data.data.service];
|
this.destServices = [res.data.service];
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
this.setCurrentService(res.data.data.service);
|
this.setCurrentService(res.data.service);
|
||||||
this.services = [res.data.data.service];
|
this.services = [res.data.service];
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async getInstance(instanceId: string, isRelation?: boolean) {
|
async getInstance(instanceId: string, isRelation?: boolean) {
|
||||||
if (!instanceId) {
|
if (!instanceId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryInstance").params({
|
const res = await graphql.query("queryInstance").params({
|
||||||
instanceId,
|
instanceId,
|
||||||
});
|
});
|
||||||
if (!res.data.errors) {
|
if (!res.errors) {
|
||||||
if (isRelation) {
|
if (isRelation) {
|
||||||
this.currentDestPod = res.data.data.instance || null;
|
this.currentDestPod = res.data.instance || null;
|
||||||
this.destPods = [res.data.data.instance];
|
this.destPods = [res.data.instance];
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
this.currentPod = res.data.data.instance || null;
|
this.currentPod = res.data.instance || null;
|
||||||
this.pods = [res.data.data.instance];
|
this.pods = [res.data.instance];
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async getEndpoint(endpointId: string, isRelation?: string) {
|
async getEndpoint(endpointId: string, isRelation?: string) {
|
||||||
if (!endpointId) {
|
if (!endpointId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoint").params({
|
const res = await graphql.query("queryEndpoint").params({
|
||||||
endpointId,
|
endpointId,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
if (isRelation) {
|
if (isRelation) {
|
||||||
this.currentDestPod = res.data.data.endpoint || null;
|
this.currentDestPod = res.data.endpoint || null;
|
||||||
this.destPods = [res.data.data.endpoint];
|
this.destPods = [res.data.endpoint];
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
this.currentPod = res.data.data.endpoint || null;
|
this.currentPod = res.data.endpoint || null;
|
||||||
this.pods = [res.data.data.endpoint];
|
this.pods = [res.data.endpoint];
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async getProcess(processId: string, isRelation?: boolean) {
|
async getProcess(processId: string, isRelation?: boolean) {
|
||||||
if (!processId) {
|
if (!processId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryProcess").params({
|
const res = await graphql.query("queryProcess").params({
|
||||||
processId,
|
processId,
|
||||||
});
|
});
|
||||||
if (!res.data.errors) {
|
if (!res.errors) {
|
||||||
if (isRelation) {
|
if (isRelation) {
|
||||||
this.currentDestProcess = res.data.data.process || null;
|
this.currentDestProcess = res.data.process || null;
|
||||||
this.destProcesses = [res.data.data.process];
|
this.destProcesses = [res.data.process];
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.currentProcess = res.data.data.process || null;
|
this.currentProcess = res.data.process || null;
|
||||||
this.processes = [res.data.data.process];
|
this.processes = [res.data.process];
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -18,7 +18,6 @@ import { defineStore } from "pinia";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import type { EBPFTaskList } from "@/types/ebpf";
|
import type { EBPFTaskList } from "@/types/ebpf";
|
||||||
import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
|
import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
|
||||||
@ -57,20 +56,18 @@ export const taskTimelineStore = defineStore({
|
|||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
const response = await graphql.query("getEBPFTasks").params(params);
|
||||||
|
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.errorTip = "";
|
this.errorTip = "";
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
this.taskList = (res.data.data.queryEBPFTasks || []).filter(
|
this.taskList = (response.data.queryEBPFTasks || []).filter(
|
||||||
(d: EBPFTaskList) => selectorStore.currentProcess && d.processId === selectorStore.currentProcess.id,
|
(d: EBPFTaskList) => selectorStore.currentProcess && d.processId === selectorStore.currentProcess.id,
|
||||||
);
|
);
|
||||||
// this.selectedTask = this.taskList[0] || {};
|
return response;
|
||||||
// await this.getGraphData();
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
async getGraphData() {
|
async getGraphData() {
|
||||||
let res: any = {};
|
let res: any = {};
|
||||||
|
@ -21,10 +21,8 @@ import graphql from "@/graphql";
|
|||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import type { AxiosResponse } from "axios";
|
import fetchQuery from "@/graphql/fetch";
|
||||||
import query from "@/graphql/fetch";
|
|
||||||
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
|
|
||||||
interface MetricVal {
|
interface MetricVal {
|
||||||
[key: string]: { values: { id: string; value: unknown }[] };
|
[key: string]: { values: { id: string; value: unknown }[] };
|
||||||
@ -306,14 +304,14 @@ export const topologyStore = defineStore({
|
|||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const duration = useAppStoreWithOut().durationTime;
|
const duration = useAppStoreWithOut().durationTime;
|
||||||
const res: AxiosResponse = await graphql.query("getServicesTopology").params({
|
const res = await graphql.query("getServicesTopology").params({
|
||||||
serviceIds,
|
serviceIds,
|
||||||
duration,
|
duration,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
return res.data.data.topology;
|
return res.data.topology;
|
||||||
},
|
},
|
||||||
async getInstanceTopology() {
|
async getInstanceTopology() {
|
||||||
const { currentService, currentDestService } = useSelectorStore();
|
const { currentService, currentDestService } = useSelectorStore();
|
||||||
@ -323,15 +321,15 @@ export const topologyStore = defineStore({
|
|||||||
if (!(serverServiceId && clientServiceId)) {
|
if (!(serverServiceId && clientServiceId)) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getInstanceTopology").params({
|
const res = await graphql.query("getInstanceTopology").params({
|
||||||
clientServiceId,
|
clientServiceId,
|
||||||
serverServiceId,
|
serverServiceId,
|
||||||
duration,
|
duration,
|
||||||
});
|
});
|
||||||
if (!res.data.errors) {
|
if (!res.errors) {
|
||||||
this.setInstanceTopology(res.data.data.topology);
|
this.setInstanceTopology(res.data.topology);
|
||||||
}
|
}
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async updateEndpointTopology(endpointIds: string[], depth: number) {
|
async updateEndpointTopology(endpointIds: string[], depth: number) {
|
||||||
if (!endpointIds.length) {
|
if (!endpointIds.length) {
|
||||||
@ -339,7 +337,10 @@ export const topologyStore = defineStore({
|
|||||||
}
|
}
|
||||||
const res = await this.getEndpointTopology(endpointIds);
|
const res = await this.getEndpointTopology(endpointIds);
|
||||||
if (depth > 1) {
|
if (depth > 1) {
|
||||||
const ids = res.nodes.map((item: Node) => item.id).filter((d: string) => !endpointIds.includes(d));
|
const userNodeName = "User";
|
||||||
|
const ids = res.nodes
|
||||||
|
.filter((d: Node) => !endpointIds.includes(d.id) && d.name !== userNodeName)
|
||||||
|
.map((item: Node) => item.id);
|
||||||
if (!ids.length) {
|
if (!ids.length) {
|
||||||
this.setTopology(res);
|
this.setTopology(res);
|
||||||
return;
|
return;
|
||||||
@ -347,8 +348,8 @@ export const topologyStore = defineStore({
|
|||||||
const json = await this.getEndpointTopology(ids);
|
const json = await this.getEndpointTopology(ids);
|
||||||
if (depth > 2) {
|
if (depth > 2) {
|
||||||
const pods = json.nodes
|
const pods = json.nodes
|
||||||
.map((item: Node) => item.id)
|
.filter((d: Node) => ![...ids, ...endpointIds].includes(d.id) && d.name !== userNodeName)
|
||||||
.filter((d: string) => ![...ids, ...endpointIds].includes(d));
|
.map((item: Node) => item.id);
|
||||||
if (!pods.length) {
|
if (!pods.length) {
|
||||||
const nodes = [...res.nodes, ...json.nodes];
|
const nodes = [...res.nodes, ...json.nodes];
|
||||||
const calls = [...res.calls, ...json.calls];
|
const calls = [...res.calls, ...json.calls];
|
||||||
@ -358,8 +359,8 @@ export const topologyStore = defineStore({
|
|||||||
const topo = await this.getEndpointTopology(pods);
|
const topo = await this.getEndpointTopology(pods);
|
||||||
if (depth > 3) {
|
if (depth > 3) {
|
||||||
const endpoints = topo.nodes
|
const endpoints = topo.nodes
|
||||||
.map((item: Node) => item.id)
|
.filter((d: Node) => ![...ids, ...pods, ...endpointIds].includes(d.id) && d.name !== userNodeName)
|
||||||
.filter((d: string) => ![...ids, ...pods, ...endpointIds].includes(d));
|
.map((item: Node) => item.id);
|
||||||
if (!endpoints.length) {
|
if (!endpoints.length) {
|
||||||
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes];
|
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes];
|
||||||
const calls = [...res.calls, ...json.calls, ...topo.calls];
|
const calls = [...res.calls, ...json.calls, ...topo.calls];
|
||||||
@ -369,8 +370,11 @@ export const topologyStore = defineStore({
|
|||||||
const data = await this.getEndpointTopology(endpoints);
|
const data = await this.getEndpointTopology(endpoints);
|
||||||
if (depth > 4) {
|
if (depth > 4) {
|
||||||
const nodeIds = data.nodes
|
const nodeIds = data.nodes
|
||||||
.map((item: Node) => item.id)
|
.filter(
|
||||||
.filter((d: string) => ![...endpoints, ...ids, ...pods, ...endpointIds].includes(d));
|
(d: Node) =>
|
||||||
|
![...endpoints, ...ids, ...pods, ...endpointIds].includes(d.id) && d.name !== userNodeName,
|
||||||
|
)
|
||||||
|
.map((item: Node) => item.id);
|
||||||
if (!nodeIds.length) {
|
if (!nodeIds.length) {
|
||||||
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes];
|
const nodes = [...res.nodes, ...json.nodes, ...topo.nodes, ...data.nodes];
|
||||||
const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls];
|
const calls = [...res.calls, ...json.calls, ...topo.calls, ...data.calls];
|
||||||
@ -427,12 +431,12 @@ export const topologyStore = defineStore({
|
|||||||
});
|
});
|
||||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||||
const conditions = { duration };
|
const conditions = { duration };
|
||||||
const res: AxiosResponse = await query({ queryStr, conditions });
|
const res = await fetchQuery({ queryStr, conditions });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
const topo = res.data.data;
|
const topo = res.data;
|
||||||
const calls = [] as Call[];
|
const calls = [] as Call[];
|
||||||
const nodes = [] as Node[];
|
const nodes = [] as Node[];
|
||||||
for (const key of Object.keys(topo)) {
|
for (const key of Object.keys(topo)) {
|
||||||
@ -443,14 +447,14 @@ export const topologyStore = defineStore({
|
|||||||
|
|
||||||
return { calls, nodes };
|
return { calls, nodes };
|
||||||
},
|
},
|
||||||
async getNodeExpressionValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
async getTopologyExpressionValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
||||||
const res: AxiosResponse = await query(param);
|
const res = await fetchQuery(param);
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async getLinkExpressions(expressions: string[], type: string) {
|
async getLinkExpressions(expressions: string[], type: string) {
|
||||||
if (!expressions.length) {
|
if (!expressions.length) {
|
||||||
@ -461,14 +465,8 @@ export const topologyStore = defineStore({
|
|||||||
if (!calls.length) {
|
if (!calls.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { getExpressionQuery, handleExpressionValues } = useQueryTopologyExpressionsProcessor(expressions, calls);
|
const { getMetrics } = useQueryTopologyExpressionsProcessor(expressions, calls);
|
||||||
const param = getExpressionQuery();
|
const metrics = await getMetrics();
|
||||||
const res = await this.getNodeExpressionValue(param);
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics = handleExpressionValues(res.data);
|
|
||||||
if (type === "SERVER") {
|
if (type === "SERVER") {
|
||||||
this.setLinkServerMetrics(metrics);
|
this.setLinkServerMetrics(metrics);
|
||||||
} else {
|
} else {
|
||||||
@ -484,17 +482,11 @@ export const topologyStore = defineStore({
|
|||||||
this.setNodeMetricValue({});
|
this.setNodeMetricValue({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { getExpressionQuery, handleExpressionValues } = useQueryTopologyExpressionsProcessor(
|
const { getMetrics } = useQueryTopologyExpressionsProcessor(
|
||||||
expressions,
|
expressions,
|
||||||
this.nodes.filter((d: Node) => d.isReal),
|
this.nodes.filter((d: Node) => d.isReal),
|
||||||
);
|
);
|
||||||
const param = getExpressionQuery();
|
const metrics = await getMetrics();
|
||||||
const res = await this.getNodeExpressionValue(param);
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics = handleExpressionValues(res.data);
|
|
||||||
this.setNodeMetricValue(metrics);
|
this.setNodeMetricValue(metrics);
|
||||||
},
|
},
|
||||||
async getHierarchyServiceTopology() {
|
async getHierarchyServiceTopology() {
|
||||||
@ -510,22 +502,20 @@ export const topologyStore = defineStore({
|
|||||||
if (!(id && layer)) {
|
if (!(id && layer)) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql
|
const res = await graphql.query("getHierarchyServiceTopology").params({ serviceId: id, layer: layer });
|
||||||
.query("getHierarchyServiceTopology")
|
if (res.errors) {
|
||||||
.params({ serviceId: id, layer: layer });
|
return res;
|
||||||
if (res.data.errors) {
|
|
||||||
return res.data;
|
|
||||||
}
|
}
|
||||||
const resp = await this.getListLayerLevels();
|
const resp = await this.getListLayerLevels();
|
||||||
if (resp.errors) {
|
if (resp.errors) {
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
const levels = resp.data.levels || [];
|
const levels = resp.levels || [];
|
||||||
this.setHierarchyServiceTopology(res.data.data.hierarchyServiceTopology || {}, levels);
|
this.setHierarchyServiceTopology(res.data.hierarchyServiceTopology || {}, levels);
|
||||||
return res.data;
|
return res;
|
||||||
},
|
},
|
||||||
async getListLayerLevels() {
|
async getListLayerLevels() {
|
||||||
const res: AxiosResponse = await graphql.query("queryListLayerLevels").params({});
|
const res = await graphql.query("queryListLayerLevels").params({});
|
||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
@ -536,30 +526,19 @@ export const topologyStore = defineStore({
|
|||||||
if (!(currentPod && dashboardStore.layerId)) {
|
if (!(currentPod && dashboardStore.layerId)) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql
|
const res = await graphql
|
||||||
.query("getHierarchyInstanceTopology")
|
.query("getHierarchyInstanceTopology")
|
||||||
.params({ instanceId: currentPod.id, layer: dashboardStore.layerId });
|
.params({ instanceId: currentPod.id, layer: dashboardStore.layerId });
|
||||||
if (res.data.errors) {
|
if (res.errors) {
|
||||||
return res.data;
|
return res;
|
||||||
}
|
}
|
||||||
const resp = await this.getListLayerLevels();
|
const resp = await this.getListLayerLevels();
|
||||||
if (resp.errors) {
|
if (resp.errors) {
|
||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
const levels = resp.data.levels || [];
|
const levels = resp.levels || [];
|
||||||
this.setHierarchyInstanceTopology(res.data.data.hierarchyInstanceTopology || {}, levels);
|
this.setHierarchyInstanceTopology(res.data.hierarchyInstanceTopology || {}, levels);
|
||||||
return res.data;
|
return res;
|
||||||
},
|
|
||||||
async queryHierarchyExpressions(expressions: string[], nodes: Node[]) {
|
|
||||||
const { getExpressionQuery, handleExpressionValues } = useQueryTopologyExpressionsProcessor(expressions, nodes);
|
|
||||||
const param = getExpressionQuery();
|
|
||||||
const res = await this.getNodeExpressionValue(param);
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics = handleExpressionValues(res.data);
|
|
||||||
return metrics;
|
|
||||||
},
|
},
|
||||||
async queryHierarchyNodeExpressions(expressions: string[], layer: string) {
|
async queryHierarchyNodeExpressions(expressions: string[], layer: string) {
|
||||||
const nodes = this.hierarchyServiceNodes.filter((n: HierarchyNode) => n.layer === layer);
|
const nodes = this.hierarchyServiceNodes.filter((n: HierarchyNode) => n.layer === layer);
|
||||||
@ -571,7 +550,8 @@ export const topologyStore = defineStore({
|
|||||||
this.setHierarchyNodeMetricValue({}, layer);
|
this.setHierarchyNodeMetricValue({}, layer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metrics = await this.queryHierarchyExpressions(expressions, nodes);
|
const { getMetrics } = useQueryTopologyExpressionsProcessor(expressions, nodes);
|
||||||
|
const metrics = await getMetrics();
|
||||||
this.setHierarchyNodeMetricValue(metrics, layer);
|
this.setHierarchyNodeMetricValue(metrics, layer);
|
||||||
},
|
},
|
||||||
async queryHierarchyInstanceNodeExpressions(expressions: string[], layer: string) {
|
async queryHierarchyInstanceNodeExpressions(expressions: string[], layer: string) {
|
||||||
@ -585,7 +565,8 @@ export const topologyStore = defineStore({
|
|||||||
this.setHierarchyInstanceNodeMetricValue({}, layer);
|
this.setHierarchyInstanceNodeMetricValue({}, layer);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metrics = await this.queryHierarchyExpressions(expressions, nodes);
|
const { getMetrics } = useQueryTopologyExpressionsProcessor(expressions, nodes);
|
||||||
|
const metrics = await getMetrics();
|
||||||
this.setHierarchyInstanceNodeMetricValue(metrics, layer);
|
this.setHierarchyInstanceNodeMetricValue(metrics, layer);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -19,10 +19,10 @@ import type { Instance, Endpoint, Service } from "@/types/selector";
|
|||||||
import type { Trace, Span } from "@/types/trace";
|
import type { Trace, Span } from "@/types/trace";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { QueryOrders } from "@/views/dashboard/data";
|
import { QueryOrders } from "@/views/dashboard/data";
|
||||||
|
import { EndpointsTopNDefault } from "../data";
|
||||||
interface TraceState {
|
interface TraceState {
|
||||||
services: Service[];
|
services: Service[];
|
||||||
instances: Instance[];
|
instances: Instance[];
|
||||||
@ -33,6 +33,7 @@ interface TraceState {
|
|||||||
conditions: Recordable;
|
conditions: Recordable;
|
||||||
traceSpanLogs: Recordable[];
|
traceSpanLogs: Recordable[];
|
||||||
selectorStore: Recordable;
|
selectorStore: Recordable;
|
||||||
|
selectedSpan: Recordable<Span>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const traceStore = defineStore({
|
export const traceStore = defineStore({
|
||||||
@ -44,6 +45,7 @@ export const traceStore = defineStore({
|
|||||||
traceList: [],
|
traceList: [],
|
||||||
traceSpans: [],
|
traceSpans: [],
|
||||||
currentTrace: {},
|
currentTrace: {},
|
||||||
|
selectedSpan: {},
|
||||||
conditions: {
|
conditions: {
|
||||||
queryDuration: useAppStoreWithOut().durationTime,
|
queryDuration: useAppStoreWithOut().durationTime,
|
||||||
traceState: "ALL",
|
traceState: "ALL",
|
||||||
@ -63,6 +65,9 @@ export const traceStore = defineStore({
|
|||||||
setTraceSpans(spans: Span[]) {
|
setTraceSpans(spans: Span[]) {
|
||||||
this.traceSpans = spans;
|
this.traceSpans = spans;
|
||||||
},
|
},
|
||||||
|
setSelectedSpan(span: Span) {
|
||||||
|
this.selectedSpan = span;
|
||||||
|
},
|
||||||
resetState() {
|
resetState() {
|
||||||
this.traceSpans = [];
|
this.traceSpans = [];
|
||||||
this.traceList = [];
|
this.traceList = [];
|
||||||
@ -75,124 +80,115 @@ export const traceStore = defineStore({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
async getServices(layer: string) {
|
async getServices(layer: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
const response = await graphql.query("queryServices").params({
|
||||||
layer,
|
layer,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.services = res.data.data.services;
|
this.services = response.data.services;
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getService(serviceId: string) {
|
async getService(serviceId: string) {
|
||||||
if (!serviceId) {
|
if (!serviceId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryService").params({
|
const response = await graphql.query("queryService").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getInstance(instanceId: string) {
|
async getInstance(instanceId: string) {
|
||||||
if (!instanceId) {
|
if (!instanceId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryInstance").params({
|
const response = await graphql.query("queryInstance").params({
|
||||||
instanceId,
|
instanceId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getEndpoint(endpointId: string) {
|
async getEndpoint(endpointId: string) {
|
||||||
if (!endpointId) {
|
if (!endpointId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoint").params({
|
return await graphql.query("queryEndpoint").params({
|
||||||
endpointId,
|
endpointId,
|
||||||
});
|
});
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
async getInstances(id: string) {
|
async getInstances(id: string) {
|
||||||
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
||||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
const response = await graphql.query("queryInstances").params({
|
||||||
serviceId: serviceId,
|
serviceId: serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.instances = [{ value: "0", label: "All" }, ...res.data.data.pods];
|
this.instances = [{ value: "0", label: "All" }, ...response.data.pods];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getEndpoints(id: string, keyword?: string) {
|
async getEndpoints(id: string, keyword?: string) {
|
||||||
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
const serviceId = this.selectorStore.currentService ? this.selectorStore.currentService.id : id;
|
||||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
const response = await graphql.query("queryEndpoints").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
keyword: keyword || "",
|
keyword: keyword || "",
|
||||||
|
limit: EndpointsTopNDefault,
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.endpoints = [{ value: "0", label: "All" }, ...res.data.data.pods];
|
this.endpoints = [{ value: "0", label: "All" }, ...response.data.pods];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getTraces() {
|
async getTraces() {
|
||||||
const res: AxiosResponse = await graphql.query("queryTraces").params({ condition: this.conditions });
|
const response = await graphql.query("queryTraces").params({ condition: this.conditions });
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
if (!res.data.data.data.traces.length) {
|
if (!response.data.data.traces.length) {
|
||||||
this.traceList = [];
|
this.traceList = [];
|
||||||
this.setCurrentTrace({});
|
this.setCurrentTrace({});
|
||||||
this.setTraceSpans([]);
|
this.setTraceSpans([]);
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.getTraceSpans({ traceId: res.data.data.data.traces[0].traceIds[0] });
|
this.getTraceSpans({ traceId: response.data.data.traces[0].traceIds[0] });
|
||||||
this.traceList = res.data.data.data.traces.map((d: Trace) => {
|
this.traceList = response.data.data.traces.map((d: Trace) => {
|
||||||
d.traceIds = d.traceIds.map((id: string) => {
|
d.traceIds = d.traceIds.map((id: string) => {
|
||||||
return { value: id, label: id };
|
return { value: id, label: id };
|
||||||
});
|
});
|
||||||
return d;
|
return d;
|
||||||
});
|
});
|
||||||
this.setCurrentTrace(res.data.data.data.traces[0] || {});
|
this.setCurrentTrace(response.data.data.traces[0] || {});
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getTraceSpans(params: { traceId: string }) {
|
async getTraceSpans(params: { traceId: string }) {
|
||||||
const res: AxiosResponse = await graphql.query("queryTrace").params(params);
|
const response = await graphql.query("queryTrace").params(params);
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
const data = res.data.data.trace.spans;
|
const data = response.data.trace.spans;
|
||||||
|
|
||||||
this.setTraceSpans(data || []);
|
this.setTraceSpans(data || []);
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getSpanLogs(params: Recordable) {
|
async getSpanLogs(params: Recordable) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServiceLogs").params(params);
|
const response = await graphql.query("queryServiceLogs").params(params);
|
||||||
if (res.data.errors) {
|
if (response.errors) {
|
||||||
this.traceSpanLogs = [];
|
this.traceSpanLogs = [];
|
||||||
return res.data;
|
return response;
|
||||||
}
|
}
|
||||||
this.traceSpanLogs = res.data.data.queryLogs.logs || [];
|
this.traceSpanLogs = response.data.queryLogs.logs || [];
|
||||||
return res.data;
|
return response;
|
||||||
},
|
},
|
||||||
async getTagKeys() {
|
async getTagKeys() {
|
||||||
const res: AxiosResponse = await graphql
|
return await graphql.query("queryTraceTagKeys").params({ duration: useAppStoreWithOut().durationTime });
|
||||||
.query("queryTraceTagKeys")
|
|
||||||
.params({ duration: useAppStoreWithOut().durationTime });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
async getTagValues(tagKey: string) {
|
async getTagValues(tagKey: string) {
|
||||||
const res: AxiosResponse = await graphql
|
return await graphql.query("queryTraceTagValues").params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
||||||
.query("queryTraceTagValues")
|
|
||||||
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
|
||||||
|
|
||||||
return res.data;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -139,6 +139,10 @@
|
|||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mb-20 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.mr-5 {
|
.mr-5 {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
html {
|
html {
|
||||||
--el-color-primary: #409eff;
|
--el-color-primary: #409eff;
|
||||||
|
--el-color-info-light-9: #666;
|
||||||
--theme-background: #fff;
|
--theme-background: #fff;
|
||||||
--font-color: #3d444f;
|
--font-color: #3d444f;
|
||||||
--disabled-color: #ccc;
|
--disabled-color: #ccc;
|
||||||
@ -69,10 +70,12 @@ html {
|
|||||||
--sw-drawer-header: #72767b;
|
--sw-drawer-header: #72767b;
|
||||||
--sw-marketplace-border: #dedfe0;
|
--sw-marketplace-border: #dedfe0;
|
||||||
--sw-grid-item-active: #d4d7de;
|
--sw-grid-item-active: #d4d7de;
|
||||||
|
--sw-trace-line: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
--el-color-primary: #409eff;
|
--el-color-primary: #409eff;
|
||||||
|
--el-color-info-light-9: #333;
|
||||||
--theme-background: #212224;
|
--theme-background: #212224;
|
||||||
--font-color: #fafbfc;
|
--font-color: #fafbfc;
|
||||||
--disabled-color: #999;
|
--disabled-color: #999;
|
||||||
@ -110,14 +113,16 @@ html.dark {
|
|||||||
--sw-drawer-header: #e9e9eb;
|
--sw-drawer-header: #e9e9eb;
|
||||||
--sw-marketplace-border: #606266;
|
--sw-marketplace-border: #606266;
|
||||||
--sw-grid-item-active: #73767a;
|
--sw-grid-item-active: #73767a;
|
||||||
|
--sw-trace-line: #e8e8e8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-drawer__header {
|
.el-drawer__header {
|
||||||
color: var(--sw-drawer-header);
|
color: var(--sw-drawer-header);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-table tr {
|
.el-table {
|
||||||
background-color: var(--el-table-tr-bg-color);
|
--el-table-tr-bg-color: var(--theme-background);
|
||||||
|
--el-table-header-bg-color: var(--theme-background);
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-popper.is-light {
|
.el-popper.is-light {
|
||||||
@ -129,27 +134,6 @@ html.dark {
|
|||||||
--el-switch-off-color: #aaa;
|
--el-switch-off-color: #aaa;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-table__body-wrapper tr td.el-table-fixed-column--left,
|
|
||||||
.el-table__body-wrapper tr td.el-table-fixed-column--right,
|
|
||||||
.el-table__body-wrapper tr th.el-table-fixed-column--left,
|
|
||||||
.el-table__body-wrapper tr th.el-table-fixed-column--right,
|
|
||||||
.el-table__footer-wrapper tr td.el-table-fixed-column--left,
|
|
||||||
.el-table__footer-wrapper tr td.el-table-fixed-column--right,
|
|
||||||
.el-table__footer-wrapper tr th.el-table-fixed-column--left,
|
|
||||||
.el-table__footer-wrapper tr th.el-table-fixed-column--right,
|
|
||||||
.el-table__header-wrapper tr td.el-table-fixed-column--left,
|
|
||||||
.el-table__header-wrapper tr td.el-table-fixed-column--right,
|
|
||||||
.el-table__header-wrapper tr th.el-table-fixed-column--left,
|
|
||||||
.el-table__header-wrapper tr th.el-table-fixed-column--right {
|
|
||||||
background-color: var(--sw-table-col);
|
|
||||||
}
|
|
||||||
|
|
||||||
.el-table.is-scrolling-none th.el-table-fixed-column--left,
|
|
||||||
.el-table.is-scrolling-none th.el-table-fixed-column--right,
|
|
||||||
.el-table th.el-table__cell {
|
|
||||||
background-color: var(--sw-table-col);
|
|
||||||
}
|
|
||||||
|
|
||||||
$tool-icon-btn-bg: var(--sw-icon-btn-bg);
|
$tool-icon-btn-bg: var(--sw-icon-btn-bg);
|
||||||
$tool-icon-btn-color: var(--sw-icon-btn-color);
|
$tool-icon-btn-color: var(--sw-icon-btn-color);
|
||||||
$popper-hover-bg-color: var(--popper-hover-bg);
|
$popper-hover-bg-color: var(--popper-hover-bg);
|
||||||
@ -261,6 +245,10 @@ div:has(> a.menu-title) {
|
|||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-input--small .el-input__inner {
|
||||||
|
--el-input-inner-height: calc(var(--el-input-height, 24px));
|
||||||
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
&::view-transition-old(root),
|
&::view-transition-old(root),
|
||||||
&::view-transition-new(root) {
|
&::view-transition-new(root) {
|
||||||
|
1
src/types/alarm.d.ts
vendored
1
src/types/alarm.d.ts
vendored
@ -27,6 +27,7 @@ export interface Alarm {
|
|||||||
scope: string;
|
scope: string;
|
||||||
tags: Array<{ key: string; value: string }>;
|
tags: Array<{ key: string; value: string }>;
|
||||||
events: Event[];
|
events: Event[];
|
||||||
|
snapshot: Indexable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Event {
|
export interface Event {
|
||||||
|
68
src/types/async-profiling.ts
Normal file
68
src/types/async-profiling.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/**
|
||||||
|
* 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 type AsyncProfilingTask = {
|
||||||
|
id: string;
|
||||||
|
serviceId: string;
|
||||||
|
serviceInstanceIds: string[];
|
||||||
|
createTime: number;
|
||||||
|
events: string;
|
||||||
|
duration: number;
|
||||||
|
execArgs: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AsyncProfileTaskCreationRequest = {
|
||||||
|
serviceId: string;
|
||||||
|
serviceInstanceIds: string[];
|
||||||
|
duration: number;
|
||||||
|
events: string[];
|
||||||
|
execArgs: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AsyncProfilerStackElement = {
|
||||||
|
id: string;
|
||||||
|
parentId: string;
|
||||||
|
codeSignature: string;
|
||||||
|
total: number;
|
||||||
|
self: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AsyncProfilerTaskProgress = {
|
||||||
|
errorInstanceIds: string[];
|
||||||
|
successInstanceIds: string[];
|
||||||
|
logs: AsyncProfilerTaskLog[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type AsyncProfilerTaskLog = {
|
||||||
|
id: string;
|
||||||
|
instanceId: string;
|
||||||
|
instanceName: string;
|
||||||
|
operationType: string;
|
||||||
|
operationTime: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type StackElement = {
|
||||||
|
id: string;
|
||||||
|
originId: string;
|
||||||
|
name: string;
|
||||||
|
parentId: string;
|
||||||
|
codeSignature: string;
|
||||||
|
total: number;
|
||||||
|
self: number;
|
||||||
|
value: number;
|
||||||
|
children?: StackElement[];
|
||||||
|
};
|
5
src/types/components.d.ts
vendored
5
src/types/components.d.ts
vendored
@ -12,6 +12,8 @@ declare module 'vue' {
|
|||||||
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem']
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
ElCard: typeof import('element-plus/es')['ElCard']
|
||||||
|
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||||
|
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
||||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||||
@ -42,8 +44,9 @@ declare module 'vue' {
|
|||||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||||
ElTag: typeof import('element-plus/es')['ElTag']
|
ElTag: typeof import('element-plus/es')['ElTag']
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
Graph: typeof import('./../components/Graph.vue')['default']
|
Graph: typeof import('./../components/Graph/Graph.vue')['default']
|
||||||
Icon: typeof import('./../components/Icon.vue')['default']
|
Icon: typeof import('./../components/Icon.vue')['default']
|
||||||
|
Legend: typeof import('./../components/Graph/Legend.vue')['default']
|
||||||
Radio: typeof import('./../components/Radio.vue')['default']
|
Radio: typeof import('./../components/Radio.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
18
src/types/dashboard.d.ts
vendored
18
src/types/dashboard.d.ts
vendored
@ -46,6 +46,7 @@ export interface LayoutConfig {
|
|||||||
relatedTrace?: RelatedTrace;
|
relatedTrace?: RelatedTrace;
|
||||||
subExpressions?: string[];
|
subExpressions?: string[];
|
||||||
subTypesOfMQE?: string[];
|
subTypesOfMQE?: string[];
|
||||||
|
valueRelatedDashboard?: string;
|
||||||
}
|
}
|
||||||
export type RelatedTrace = {
|
export type RelatedTrace = {
|
||||||
duration: DurationTime;
|
duration: DurationTime;
|
||||||
@ -110,6 +111,7 @@ export interface LineConfig extends AreaConfig {
|
|||||||
showYAxis?: boolean;
|
showYAxis?: boolean;
|
||||||
smallTips?: boolean;
|
smallTips?: boolean;
|
||||||
showlabels?: boolean;
|
showlabels?: boolean;
|
||||||
|
noTooltips?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AreaConfig {
|
export interface AreaConfig {
|
||||||
@ -123,6 +125,7 @@ export interface CardConfig {
|
|||||||
fontSize?: number;
|
fontSize?: number;
|
||||||
showUnit?: boolean;
|
showUnit?: boolean;
|
||||||
textAlign?: "center" | "right" | "left";
|
textAlign?: "center" | "right" | "left";
|
||||||
|
valueMappings?: { [key: string]: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TextConfig {
|
export interface TextConfig {
|
||||||
@ -194,4 +197,19 @@ export type LegendOptions = {
|
|||||||
asTable: boolean;
|
asTable: boolean;
|
||||||
toTheRight: boolean;
|
toTheRight: boolean;
|
||||||
width: number;
|
width: number;
|
||||||
|
asSelector: boolean;
|
||||||
|
};
|
||||||
|
export type MetricsResults = {
|
||||||
|
metric: { labels: MetricLabel[] };
|
||||||
|
values: MetricValue[];
|
||||||
|
};
|
||||||
|
type MetricLabel = {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
type MetricValue = {
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
owner: null | string;
|
||||||
|
refId: null | string;
|
||||||
};
|
};
|
||||||
|
3
src/types/profile.d.ts
vendored
3
src/types/profile.d.ts
vendored
@ -41,6 +41,9 @@ export interface TaskListItem {
|
|||||||
dumpPeriod: number;
|
dumpPeriod: number;
|
||||||
maxSamplingCount: number;
|
maxSamplingCount: number;
|
||||||
logs: TaskLog[];
|
logs: TaskLog[];
|
||||||
|
errorInstanceIds: string[];
|
||||||
|
successInstanceIds: string[];
|
||||||
|
serviceInstanceIds: string[];
|
||||||
}
|
}
|
||||||
export interface SegmentSpan {
|
export interface SegmentSpan {
|
||||||
spanId: string;
|
spanId: string;
|
||||||
|
10
src/types/trace.d.ts
vendored
10
src/types/trace.d.ts
vendored
@ -48,9 +48,10 @@ export interface Span {
|
|||||||
logs?: log[];
|
logs?: log[];
|
||||||
parentSegmentId?: string;
|
parentSegmentId?: string;
|
||||||
refs?: Ref[];
|
refs?: Ref[];
|
||||||
|
key?: string;
|
||||||
}
|
}
|
||||||
export type Ref = {
|
export type Ref = {
|
||||||
type: string;
|
type?: string;
|
||||||
parentSegmentId: string;
|
parentSegmentId: string;
|
||||||
parentSpanId: number;
|
parentSpanId: number;
|
||||||
traceId: string;
|
traceId: string;
|
||||||
@ -60,13 +61,6 @@ export interface log {
|
|||||||
data: Map<string, string>;
|
data: Map<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Ref {
|
|
||||||
traceId: string;
|
|
||||||
parentSegmentId: string;
|
|
||||||
parentSpanId: number;
|
|
||||||
type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StatisticsSpan {
|
export interface StatisticsSpan {
|
||||||
groupRef: StatisticsGroupRef;
|
groupRef: StatisticsGroupRef;
|
||||||
maxTime: number;
|
maxTime: number;
|
||||||
|
@ -16,18 +16,22 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { ElNotification } from "element-plus";
|
import { ElNotification } from "element-plus";
|
||||||
export default (value: string): void => {
|
|
||||||
const input = document.createElement("input");
|
export default (text: string): void => {
|
||||||
input.value = value;
|
navigator.clipboard
|
||||||
document.body.appendChild(input);
|
.writeText(text)
|
||||||
input.select();
|
.then(() => {
|
||||||
if (document.execCommand("Copy")) {
|
ElNotification({
|
||||||
document.execCommand("Copy");
|
title: "Success",
|
||||||
}
|
message: "Copied",
|
||||||
input.remove();
|
type: "success",
|
||||||
ElNotification({
|
});
|
||||||
title: "Success",
|
})
|
||||||
message: "Copied",
|
.catch((err) => {
|
||||||
type: "success",
|
ElNotification({
|
||||||
});
|
title: "Error",
|
||||||
|
message: err,
|
||||||
|
type: "warning",
|
||||||
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
@ -37,8 +37,10 @@ export const saveFile = (data: any, name: string) => {
|
|||||||
tagA.download = name;
|
tagA.download = name;
|
||||||
tagA.style.display = "none";
|
tagA.style.display = "none";
|
||||||
const blob = new Blob([newData]);
|
const blob = new Blob([newData]);
|
||||||
tagA.href = URL.createObjectURL(blob);
|
const url = URL.createObjectURL(blob);
|
||||||
|
tagA.href = url;
|
||||||
document.body.appendChild(tagA);
|
document.body.appendChild(tagA);
|
||||||
tagA.click();
|
tagA.click();
|
||||||
document.body.removeChild(tagA);
|
document.body.removeChild(tagA);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
class Vec2 extends Float32Array {
|
class Vec2 extends Float32Array {
|
||||||
constructor(v?: unknown, y?: unknown) {
|
constructor(v?: unknown, y?: unknown) {
|
||||||
super(2);
|
super(2);
|
||||||
if (v instanceof Vec2 || v instanceof Float32Array || (v instanceof Array && v.length == 2)) {
|
if (v instanceof Vec2 || v instanceof Float32Array || (v instanceof Array && v.length === 2)) {
|
||||||
this[0] = v[0];
|
this[0] = v[0];
|
||||||
this[1] = v[1];
|
this[1] = v[1];
|
||||||
} else if (typeof v === "number" && typeof y === "number") {
|
} else if (typeof v === "number" && typeof y === "number") {
|
||||||
@ -104,7 +104,7 @@ class Vec2 extends Float32Array {
|
|||||||
}
|
}
|
||||||
norm(out?: number[] | Vec2): number[] | Vec2 | undefined {
|
norm(out?: number[] | Vec2): number[] | Vec2 | undefined {
|
||||||
const mag = Math.sqrt(this[0] * this[0] + this[1] * this[1]);
|
const mag = Math.sqrt(this[0] * this[0] + this[1] * this[1]);
|
||||||
if (mag == 0) return this;
|
if (mag === 0) return this;
|
||||||
out = out || this;
|
out = out || this;
|
||||||
out[0] = this[0] / mag;
|
out[0] = this[0] / mag;
|
||||||
out[1] = this[1] / mag;
|
out[1] = this[1] / mag;
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
class Vec3 extends Float32Array {
|
class Vec3 extends Float32Array {
|
||||||
constructor(v?: unknown, y?: unknown, z?: unknown) {
|
constructor(v?: unknown, y?: unknown, z?: unknown) {
|
||||||
super(3);
|
super(3);
|
||||||
if (v instanceof Vec3 || v instanceof Float32Array || (v instanceof Array && v.length == 3)) {
|
if (v instanceof Vec3 || v instanceof Float32Array || (v instanceof Array && v.length === 3)) {
|
||||||
this[0] = v[0];
|
this[0] = v[0];
|
||||||
this[1] = v[1];
|
this[1] = v[1];
|
||||||
this[2] = v[2];
|
this[2] = v[2];
|
||||||
@ -150,7 +150,7 @@ class Vec3 extends Float32Array {
|
|||||||
}
|
}
|
||||||
static norm(x: unknown, y: unknown, z: unknown): Vec3 {
|
static norm(x: unknown, y: unknown, z: unknown): Vec3 {
|
||||||
const rtn = new Vec3();
|
const rtn = new Vec3();
|
||||||
if (x instanceof Vec3 || x instanceof Float32Array || (x instanceof Array && x.length == 3)) {
|
if (x instanceof Vec3 || x instanceof Float32Array || (x instanceof Array && x.length === 3)) {
|
||||||
rtn.copy(x);
|
rtn.copy(x);
|
||||||
} else if (typeof x === "number" && typeof y === "number" && typeof z === "number") {
|
} else if (typeof x === "number" && typeof y === "number" && typeof z === "number") {
|
||||||
rtn.xyz(x, y, z);
|
rtn.xyz(x, y, z);
|
||||||
|
@ -22,7 +22,7 @@ limitations under the License. -->
|
|||||||
placeholder="Select a language"
|
placeholder="Select a language"
|
||||||
@change="setLang"
|
@change="setLang"
|
||||||
size="small"
|
size="small"
|
||||||
style="font-size: 14px"
|
style="font-size: 14px; width: 180px"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-h item">
|
<div class="flex-h item">
|
||||||
|
@ -22,15 +22,17 @@ limitations under the License. -->
|
|||||||
<div class="message mb-5 b">
|
<div class="message mb-5 b">
|
||||||
{{ i.message }}
|
{{ i.message }}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="flex-h">
|
||||||
class="timeline-table-i-scope mr-10 l sm"
|
<div
|
||||||
:class="{
|
class="timeline-table-i-scope"
|
||||||
blue: i.scope === 'Service',
|
:class="{
|
||||||
green: i.scope === 'Endpoint',
|
blue: i.scope === 'Service',
|
||||||
yellow: i.scope === 'ServiceInstance',
|
green: i.scope === 'Endpoint',
|
||||||
}"
|
yellow: i.scope === 'ServiceInstance',
|
||||||
>
|
}"
|
||||||
{{ t(i.scope.toLowerCase()) }}
|
>
|
||||||
|
{{ t(i.scope.toLowerCase()) }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grey sm show-xs">
|
<div class="grey sm show-xs">
|
||||||
{{ dateFormat(parseInt(i.startTime)) }}
|
{{ dateFormat(parseInt(i.startTime)) }}
|
||||||
@ -46,7 +48,7 @@ limitations under the License. -->
|
|||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
@closed="isShowDetails = false"
|
@closed="isShowDetails = false"
|
||||||
>
|
>
|
||||||
<div class="mb-10 clear alarm-detail" v-for="(item, index) in AlarmDetailCol" :key="index">
|
<div class="mb-20 clear alarm-detail" v-for="(item, index) in AlarmDetailCol" :key="index">
|
||||||
<span class="g-sm-2 grey">{{ t(item.value) }}:</span>
|
<span class="g-sm-2 grey">{{ t(item.value) }}:</span>
|
||||||
<span v-if="item.label === 'startTime'">
|
<span v-if="item.label === 'startTime'">
|
||||||
{{ dateFormat(currentDetail[item.label]) }}
|
{{ dateFormat(currentDetail[item.label]) }}
|
||||||
@ -54,7 +56,7 @@ limitations under the License. -->
|
|||||||
<span v-else-if="item.label === 'tags'">
|
<span v-else-if="item.label === 'tags'">
|
||||||
<div v-for="(d, index) in alarmTags" :key="index">{{ d }}</div>
|
<div v-for="(d, index) in alarmTags" :key="index">{{ d }}</div>
|
||||||
</span>
|
</span>
|
||||||
<span v-else-if="item.label === 'events'" class="event-detail">
|
<span v-else-if="item.label === 'events'">
|
||||||
<div>
|
<div>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
@ -75,6 +77,12 @@ limitations under the License. -->
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
|
<span v-else-if="item.label === 'expression'">
|
||||||
|
{{ currentDetail.snapshot.expression }}
|
||||||
|
</span>
|
||||||
|
<span v-else-if="item.label === 'snapshot'">
|
||||||
|
<Snapshot :snapshot="currentDetail.snapshot" />
|
||||||
|
</span>
|
||||||
<span v-else>{{ currentDetail[item.label] }}</span>
|
<span v-else>{{ currentDetail[item.label] }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -85,7 +93,7 @@ limitations under the License. -->
|
|||||||
:destroy-on-close="true"
|
:destroy-on-close="true"
|
||||||
@closed="showEventDetails = false"
|
@closed="showEventDetails = false"
|
||||||
>
|
>
|
||||||
<div class="event-detail">
|
<div>
|
||||||
<div class="mb-10" v-for="(eventKey, index) in EventsDetailKeys" :key="index">
|
<div class="mb-10" v-for="(eventKey, index) in EventsDetailKeys" :key="index">
|
||||||
<span class="keys">{{ t(eventKey.text) }}</span>
|
<span class="keys">{{ t(eventKey.text) }}</span>
|
||||||
<span v-if="eventKey.class === 'parameters'">
|
<span v-if="eventKey.class === 'parameters'">
|
||||||
@ -117,6 +125,7 @@ limitations under the License. -->
|
|||||||
import { useAlarmStore } from "@/store/modules/alarm";
|
import { useAlarmStore } from "@/store/modules/alarm";
|
||||||
import { EventsDetailHeaders, AlarmDetailCol, EventsDetailKeys } from "./data";
|
import { EventsDetailHeaders, AlarmDetailCol, EventsDetailKeys } from "./data";
|
||||||
import { dateFormat } from "@/utils/dateFormat";
|
import { dateFormat } from "@/utils/dateFormat";
|
||||||
|
import Snapshot from "./components/Snapshot.vue";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const alarmStore = useAlarmStore();
|
const alarmStore = useAlarmStore();
|
||||||
@ -186,11 +195,10 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.timeline-table-i-scope {
|
.timeline-table-i-scope {
|
||||||
display: inline-block;
|
padding: 0 5px;
|
||||||
padding: 0 8px;
|
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
margin-top: -1px;
|
border-radius: 3px;
|
||||||
border-radius: 4px;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.timeline-item {
|
.timeline-item {
|
||||||
@ -224,9 +232,6 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.alarm-detail {
|
.alarm-detail {
|
||||||
max-height: 600px;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
@ -247,4 +252,9 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mini-chart {
|
||||||
|
height: 20px;
|
||||||
|
width: 400px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -38,7 +38,7 @@ limitations under the License. -->
|
|||||||
:total="total"
|
:total="total"
|
||||||
@current-change="changePage"
|
@current-change="changePage"
|
||||||
:pager-count="5"
|
:pager-count="5"
|
||||||
small
|
size="small"
|
||||||
:style="
|
:style="
|
||||||
appStore.theme === Themes.Light
|
appStore.theme === Themes.Light
|
||||||
? `--el-pagination-bg-color: #f0f2f5; --el-pagination-button-disabled-bg-color: #f0f2f5;`
|
? `--el-pagination-bg-color: #f0f2f5; --el-pagination-button-disabled-bg-color: #f0f2f5;`
|
||||||
|
141
src/views/alarm/components/Line.vue
Normal file
141
src/views/alarm/components/Line.vue
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
<!-- 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>
|
||||||
|
<Graph :option="option" @select="clickEvent" />
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import type { EventParams } from "@/types/dashboard";
|
||||||
|
import useLegendProcess from "@/hooks/useLegendProcessor";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { Themes } from "@/constants/data";
|
||||||
|
|
||||||
|
/*global defineProps, defineEmits */
|
||||||
|
const emits = defineEmits(["click"]);
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Array as PropType<any>,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
|
});
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
|
const option = computed(() => getOption());
|
||||||
|
function getOption() {
|
||||||
|
const { chartColors } = useLegendProcess();
|
||||||
|
const color: string[] = chartColors();
|
||||||
|
const series = [];
|
||||||
|
const grid = [];
|
||||||
|
const xAxis = [];
|
||||||
|
const yAxis = [];
|
||||||
|
for (const [index, metric] of props.data.entries()) {
|
||||||
|
grid.push({
|
||||||
|
top: 300 * index + 30,
|
||||||
|
left: 0,
|
||||||
|
right: 10,
|
||||||
|
bottom: 5,
|
||||||
|
containLabel: true,
|
||||||
|
height: 260,
|
||||||
|
});
|
||||||
|
xAxis.push({
|
||||||
|
type: "category",
|
||||||
|
show: true,
|
||||||
|
axisTick: {
|
||||||
|
lineStyle: { color: "#c1c5ca41" },
|
||||||
|
alignWithLabel: true,
|
||||||
|
},
|
||||||
|
splitLine: { show: false },
|
||||||
|
axisLine: { lineStyle: { color: "rgba(0,0,0,0)" } },
|
||||||
|
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||||
|
gridIndex: index,
|
||||||
|
});
|
||||||
|
yAxis.push({
|
||||||
|
type: "value",
|
||||||
|
axisLine: { show: false },
|
||||||
|
axisTick: { show: false },
|
||||||
|
splitLine: { lineStyle: { color: "#c1c5ca41", type: "dashed" } },
|
||||||
|
axisLabel: {
|
||||||
|
color: "#9da5b2",
|
||||||
|
fontSize: "11",
|
||||||
|
show: true,
|
||||||
|
},
|
||||||
|
gridIndex: index,
|
||||||
|
});
|
||||||
|
for (const item of metric.values) {
|
||||||
|
series.push({
|
||||||
|
data: item.values.map((item: number, itemIndex: number) => [props.intervalTime[itemIndex], item]),
|
||||||
|
name: item.name || metric.name,
|
||||||
|
type: "line",
|
||||||
|
symbol: "circle",
|
||||||
|
symbolSize: 4,
|
||||||
|
xAxisIndex: index,
|
||||||
|
yAxisIndex: index,
|
||||||
|
lineStyle: {
|
||||||
|
width: 2,
|
||||||
|
type: "solid",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const tooltip = {
|
||||||
|
trigger: "axis",
|
||||||
|
backgroundColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
||||||
|
borderColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: appStore.theme === Themes.Dark ? "#eee" : "#333",
|
||||||
|
},
|
||||||
|
enterable: true,
|
||||||
|
confine: true,
|
||||||
|
extraCssText: "max-height:85%; overflow: auto;",
|
||||||
|
axisPointer: {
|
||||||
|
animation: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
color,
|
||||||
|
tooltip,
|
||||||
|
axisPointer: {
|
||||||
|
link: { xAxisIndex: "all" },
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
type: "scroll",
|
||||||
|
icon: "circle",
|
||||||
|
top: -5,
|
||||||
|
left: 0,
|
||||||
|
itemWidth: 12,
|
||||||
|
textStyle: {
|
||||||
|
color: appStore.theme === Themes.Dark ? "#fff" : "#333",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
grid,
|
||||||
|
xAxis,
|
||||||
|
yAxis,
|
||||||
|
series,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickEvent(params: EventParams) {
|
||||||
|
emits("click", params);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.snapshot-charts {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
35
src/views/alarm/components/Snapshot.vue
Normal file
35
src/views/alarm/components/Snapshot.vue
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!-- 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>
|
||||||
|
<LineChart
|
||||||
|
:intervalTime="appStore.intervalTime"
|
||||||
|
:data="metrics"
|
||||||
|
:style="{ width: `800px`, height: `${metrics.length * 300}px` }"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
import { useSnapshot } from "@/hooks/useSnapshot";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import LineChart from "./Line.vue";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
const props = defineProps({
|
||||||
|
snapshot: { type: Object, default: () => {} },
|
||||||
|
});
|
||||||
|
const { processResults } = useSnapshot(props.snapshot.metrics);
|
||||||
|
const metrics = computed(() => processResults());
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
|
</script>
|
@ -52,6 +52,14 @@ export const AlarmDetailCol = [
|
|||||||
label: "events",
|
label: "events",
|
||||||
value: "eventDetail",
|
value: "eventDetail",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: "expression",
|
||||||
|
value: "expression",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "snapshot",
|
||||||
|
value: "snapshot",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const EventsDetailKeys = [
|
export const EventsDetailKeys = [
|
||||||
|
@ -612,7 +612,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
function searchDashboards(pageIndex: number) {
|
function searchDashboards(pageIndex: number) {
|
||||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
const arr = list.filter((d: { name: string }) => d.name.includes(searchText.value));
|
const arr = list.filter((d: { name: string }) => d.name.toLowerCase().includes(searchText.value.toLowerCase()));
|
||||||
|
|
||||||
total.value = arr.length;
|
total.value = arr.length;
|
||||||
dashboards.value = arr.filter(
|
dashboards.value = arr.filter(
|
||||||
|
@ -32,11 +32,13 @@ limitations under the License. -->
|
|||||||
:config="{
|
:config="{
|
||||||
i: 0,
|
i: 0,
|
||||||
...graph,
|
...graph,
|
||||||
|
valueMappings: graph?.valueMappings,
|
||||||
metricConfig: config.metricConfig,
|
metricConfig: config.metricConfig,
|
||||||
expressions: config.expressions || [],
|
expressions: config.expressions || [],
|
||||||
typesOfMQE: typesOfMQE || [],
|
typesOfMQE: typesOfMQE || [],
|
||||||
subExpressions: config.subExpressions || [],
|
subExpressions: config.subExpressions || [],
|
||||||
subTypesOfMQE: config.subTypesOfMQE || [],
|
subTypesOfMQE: config.subTypesOfMQE || [],
|
||||||
|
valueRelatedDashboard: config.valueRelatedDashboard,
|
||||||
}"
|
}"
|
||||||
:needQuery="true"
|
:needQuery="true"
|
||||||
/>
|
/>
|
||||||
|
@ -126,7 +126,7 @@ limitations under the License. -->
|
|||||||
opt.auto = Number(f.value) * 60 * 60 * 1000;
|
opt.auto = Number(f.value) * 60 * 60 * 1000;
|
||||||
}
|
}
|
||||||
if (f.step === TimeType.DAY_TIME) {
|
if (f.step === TimeType.DAY_TIME) {
|
||||||
opt.auto = Number(f.value) * 60 * 60 * 60 * 1000;
|
opt.auto = Number(f.value) * 24 * 60 * 60 * 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const config = JSON.stringify(opt);
|
const config = JSON.stringify(opt);
|
||||||
|
@ -32,7 +32,8 @@ limitations under the License. -->
|
|||||||
:data="states.source"
|
:data="states.source"
|
||||||
:config="{
|
:config="{
|
||||||
...graph,
|
...graph,
|
||||||
legend: (dashboardStore.selectedGrid.graph || {}).legend,
|
decorations: dashboardStore.selectedGrid.graph?.decorations,
|
||||||
|
legend: dashboardStore.selectedGrid.graph?.legend,
|
||||||
i: dashboardStore.selectedGrid.i,
|
i: dashboardStore.selectedGrid.i,
|
||||||
metricConfig: dashboardStore.selectedGrid.metricConfig,
|
metricConfig: dashboardStore.selectedGrid.metricConfig,
|
||||||
relatedTrace: dashboardStore.selectedGrid.relatedTrace,
|
relatedTrace: dashboardStore.selectedGrid.relatedTrace,
|
||||||
@ -40,6 +41,7 @@ limitations under the License. -->
|
|||||||
typesOfMQE: dashboardStore.selectedGrid.typesOfMQE || [],
|
typesOfMQE: dashboardStore.selectedGrid.typesOfMQE || [],
|
||||||
subExpressions: dashboardStore.selectedGrid.subExpressions || [],
|
subExpressions: dashboardStore.selectedGrid.subExpressions || [],
|
||||||
subTypesOfMQE: dashboardStore.selectedGrid.subTypesOfMQE || [],
|
subTypesOfMQE: dashboardStore.selectedGrid.subTypesOfMQE || [],
|
||||||
|
valueRelatedDashboard: dashboardStore.selectedGrid.valueRelatedDashboard,
|
||||||
}"
|
}"
|
||||||
:needQuery="true"
|
:needQuery="true"
|
||||||
@expressionTips="getErrors"
|
@expressionTips="getErrors"
|
||||||
|
@ -81,7 +81,7 @@ limitations under the License. -->
|
|||||||
const latency = ref<boolean>(traceOpt.latency || false);
|
const latency = ref<boolean>(traceOpt.latency || false);
|
||||||
const enableRelate = ref<boolean>(traceOpt.enableRelate || false);
|
const enableRelate = ref<boolean>(traceOpt.enableRelate || false);
|
||||||
const type = ref<string>((graph && graph.type) || "");
|
const type = ref<string>((graph && graph.type) || "");
|
||||||
const refIdType = ref<string>(traceOpt.refIdType || "traceId");
|
const refIdType = ref<string>(traceOpt.refIdType || "");
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
const relatedTrace = {
|
const relatedTrace = {
|
||||||
|
@ -13,6 +13,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
|
<div>
|
||||||
|
<value-mappings />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">{{ t("fontSize") }}</span>
|
<span class="label">{{ t("fontSize") }}</span>
|
||||||
<el-slider
|
<el-slider
|
||||||
@ -26,7 +29,7 @@ limitations under the License. -->
|
|||||||
@change="updateConfig({ fontSize })"
|
@change="updateConfig({ fontSize })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div>
|
||||||
<span class="label">{{ t("showUnit") }}</span>
|
<span class="label">{{ t("showUnit") }}</span>
|
||||||
<el-switch v-model="showUnit" active-text="Yes" inactive-text="No" @change="updateConfig({ showUnit })" />
|
<el-switch v-model="showUnit" active-text="Yes" inactive-text="No" @change="updateConfig({ showUnit })" />
|
||||||
</div>
|
</div>
|
||||||
@ -35,6 +38,7 @@ limitations under the License. -->
|
|||||||
import { ref } from "vue";
|
import { ref } 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 ValueMappings from "./components/ValueMappings.vue";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
<value-mappings />
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
<span class="label">{{ t("showValues") }}</span>
|
<span class="label">{{ t("showValues") }}</span>
|
||||||
<el-switch
|
<el-switch
|
||||||
v-model="showTableValues"
|
v-model="showTableValues"
|
||||||
@ -37,6 +40,7 @@ limitations under the License. -->
|
|||||||
import { ref } from "vue";
|
import { ref } 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 ValueMappings from "./components/ValueMappings.vue";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
@ -22,6 +22,15 @@ limitations under the License. -->
|
|||||||
@change="updateLegendConfig({ show: legend.show })"
|
@change="updateLegendConfig({ show: legend.show })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="label mr-5">{{ t("asSelector") }}</span>
|
||||||
|
<el-switch
|
||||||
|
v-model="legend.asSelector"
|
||||||
|
active-text="Yes"
|
||||||
|
inactive-text="No"
|
||||||
|
@change="updateLegendConfig({ asSelector: legend.asSelector })"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="label">{{ t("asTable") }}</span>
|
<span class="label">{{ t("asTable") }}</span>
|
||||||
<el-switch
|
<el-switch
|
||||||
@ -97,6 +106,7 @@ limitations under the License. -->
|
|||||||
max: false,
|
max: false,
|
||||||
mean: false,
|
mean: false,
|
||||||
asTable: false,
|
asTable: false,
|
||||||
|
asSelector: false,
|
||||||
toTheRight: false,
|
toTheRight: false,
|
||||||
width: 130,
|
width: 130,
|
||||||
...graph.value.legend,
|
...graph.value.legend,
|
||||||
|
@ -0,0 +1,112 @@
|
|||||||
|
<!-- 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>
|
||||||
|
<span class="label">{{ t("valueMappings") }}</span>
|
||||||
|
<span class="label red">{{ t("mappingTip") }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-for="(key, index) in keys" :key="index" class="mb-10 flex-h">
|
||||||
|
<div class="content-decoration" contenteditable="true" @blur="changeKeys($event, index)">
|
||||||
|
{{ key }}
|
||||||
|
</div>
|
||||||
|
<div class="ml-5 mr-10">:</div>
|
||||||
|
<div class="content-decoration" contenteditable="true" @blur="changeValues($event, key)">
|
||||||
|
{{ valueMappings[key] }}
|
||||||
|
</div>
|
||||||
|
<div v-if="index === keys.length - 1">
|
||||||
|
<Icon class="cp mr-5" iconName="add_circle_outlinecontrol_point" size="middle" @click="addDecoration" />
|
||||||
|
<Icon
|
||||||
|
v-if="index !== 0"
|
||||||
|
class="cp"
|
||||||
|
iconName="remove_circle_outline"
|
||||||
|
size="middle"
|
||||||
|
@click="deleteDecoration(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const graph = dashboardStore.selectedGrid.graph;
|
||||||
|
const valueMappings = ref<{ [key: string]: string }>(graph?.valueMappings || {});
|
||||||
|
const keys = ref<string[]>(graph.valueMappings ? Object.keys(valueMappings.value) : [""]);
|
||||||
|
|
||||||
|
function changeKeys(event: any, index: number) {
|
||||||
|
const params = event.target.textContent || "";
|
||||||
|
const list = Object.keys(valueMappings.value);
|
||||||
|
if (params) {
|
||||||
|
valueMappings.value[params] = valueMappings.value[list[index]];
|
||||||
|
}
|
||||||
|
delete valueMappings.value[list[index]];
|
||||||
|
keys.value = Object.keys(valueMappings.value);
|
||||||
|
if (!keys.value.length) {
|
||||||
|
keys.value = [""];
|
||||||
|
}
|
||||||
|
updateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeValues(event: any, key: string) {
|
||||||
|
valueMappings.value[key] = event.target.textContent || "";
|
||||||
|
updateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function addDecoration() {
|
||||||
|
keys.value.push("");
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteDecoration(index: number) {
|
||||||
|
if (!keys.value.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete valueMappings.value[keys.value[index]];
|
||||||
|
keys.value.splice(index, 1);
|
||||||
|
updateConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateConfig() {
|
||||||
|
const graph = {
|
||||||
|
...dashboardStore.selectedGrid.graph,
|
||||||
|
valueMappings: valueMappings.value,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, graph });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content-decoration {
|
||||||
|
width: 350px;
|
||||||
|
border: 1px solid $border-color;
|
||||||
|
cursor: text;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
outline: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
min-height: 26px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: $active-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -95,6 +95,20 @@ limitations under the License. -->
|
|||||||
{{ type.label }}
|
{{ type.label }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="states.isTopList" class="mt-10">
|
||||||
|
<div>{{ t("valueDashboard") }}</div>
|
||||||
|
<div>
|
||||||
|
<Selector
|
||||||
|
:value="states.valueRelatedDashboard || ''"
|
||||||
|
:options="states.dashboardList"
|
||||||
|
size="small"
|
||||||
|
placeholder="Please select a dashboard name"
|
||||||
|
@change="changeValueDashboard"
|
||||||
|
class="selectors"
|
||||||
|
:clearable="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref, computed } from "vue";
|
import { reactive, ref, computed } from "vue";
|
||||||
@ -140,21 +154,25 @@ limitations under the License. -->
|
|||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
metricTypeList: Option[][];
|
metricTypeList: Option[][];
|
||||||
isList: boolean;
|
isList: boolean;
|
||||||
|
isTopList: boolean;
|
||||||
dashboardName: string;
|
dashboardName: string;
|
||||||
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
|
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
|
||||||
tips: string[];
|
tips: string[];
|
||||||
subTips: string[];
|
subTips: string[];
|
||||||
|
valueRelatedDashboard: string;
|
||||||
}>({
|
}>({
|
||||||
metrics: metrics.value.length ? metrics.value : [""],
|
metrics: metrics.value.length ? metrics.value : [""],
|
||||||
metricTypes: typesOfMQE.value.length ? typesOfMQE.value : [""],
|
metricTypes: typesOfMQE.value.length ? typesOfMQE.value : [""],
|
||||||
metricTypeList: [],
|
metricTypeList: [],
|
||||||
isList: false,
|
isList: false,
|
||||||
|
isTopList: false,
|
||||||
dashboardName: graph.value.dashboardName,
|
dashboardName: graph.value.dashboardName,
|
||||||
dashboardList: [{ label: "", value: "" }],
|
dashboardList: [{ label: "", value: "" }],
|
||||||
tips: [],
|
tips: [],
|
||||||
subTips: [],
|
subTips: [],
|
||||||
subMetrics: subMetrics.value.length ? subMetrics.value : [""],
|
subMetrics: subMetrics.value.length ? subMetrics.value : [""],
|
||||||
subMetricTypes: subMetricTypes.value.length ? subMetricTypes.value : [""],
|
subMetricTypes: subMetricTypes.value.length ? subMetricTypes.value : [""],
|
||||||
|
valueRelatedDashboard: dashboardStore.selectedGrid.valueRelatedDashboard,
|
||||||
});
|
});
|
||||||
const currentMetricConfig = ref<MetricConfigOpt>({
|
const currentMetricConfig = ref<MetricConfigOpt>({
|
||||||
unit: "",
|
unit: "",
|
||||||
@ -163,6 +181,7 @@ limitations under the License. -->
|
|||||||
sortOrder: "DES",
|
sortOrder: "DES",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
states.isTopList = graph.value.type === ChartTypes[4].value;
|
||||||
states.isList = ListChartTypes.includes(graph.value.type);
|
states.isList = ListChartTypes.includes(graph.value.type);
|
||||||
const defaultLen = ref<number>(states.isList ? 5 : 20);
|
const defaultLen = ref<number>(states.isList ? 5 : 20);
|
||||||
|
|
||||||
@ -187,9 +206,10 @@ limitations under the License. -->
|
|||||||
const arr = list.reduce((prev: (DashboardItem & { label: string; value: string })[], d: DashboardItem) => {
|
const arr = list.reduce((prev: (DashboardItem & { label: string; value: string })[], d: DashboardItem) => {
|
||||||
if (d.layer === dashboardStore.layerId) {
|
if (d.layer === dashboardStore.layerId) {
|
||||||
if (
|
if (
|
||||||
(d.entity === EntityType[0].value && chart === "ServiceList") ||
|
(d.entity === EntityType[0].value && chart === ChartTypes[8].value) ||
|
||||||
(d.entity === EntityType[2].value && chart === "EndpointList") ||
|
(d.entity === EntityType[2].value && chart === ChartTypes[9].value) ||
|
||||||
(d.entity === EntityType[3].value && chart === "InstanceList")
|
(d.entity === EntityType[3].value && chart === ChartTypes[10].value) ||
|
||||||
|
states.isTopList
|
||||||
) {
|
) {
|
||||||
prev.push({
|
prev.push({
|
||||||
...d,
|
...d,
|
||||||
@ -254,9 +274,28 @@ limitations under the License. -->
|
|||||||
typesOfMQE: states.metricTypes,
|
typesOfMQE: states.metricTypes,
|
||||||
});
|
});
|
||||||
emit("update", params.source || {});
|
emit("update", params.source || {});
|
||||||
|
if (states.isTopList) {
|
||||||
|
const values: any = Object.values(params.source)[0];
|
||||||
|
if (!values) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
states.dashboardList = states.dashboardList.filter((d) => d.entity === values[0].owner.scope);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeDashboard(opt: any) {
|
function changeValueDashboard(opt: { value: string }[]) {
|
||||||
|
if (!opt[0]) {
|
||||||
|
states.valueRelatedDashboard = "";
|
||||||
|
} else {
|
||||||
|
states.valueRelatedDashboard = opt[0].value;
|
||||||
|
}
|
||||||
|
dashboardStore.selectWidget({
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
valueRelatedDashboard: states.valueRelatedDashboard,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeDashboard(opt: { value: string }[]) {
|
||||||
if (!opt[0]) {
|
if (!opt[0]) {
|
||||||
states.dashboardName = "";
|
states.dashboardName = "";
|
||||||
} else {
|
} else {
|
||||||
|
85
src/views/dashboard/controls/AsyncProfiling.vue
Normal file
85
src/views/dashboard/controls/AsyncProfiling.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<!-- 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-wrapper flex-v">
|
||||||
|
<el-popover placement="bottom" trigger="click" :width="100" v-if="dashboardStore.editMode">
|
||||||
|
<template #reference>
|
||||||
|
<span class="operation cp">
|
||||||
|
<Icon iconName="ellipsis_v" size="middle" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="tools" @click="removeWidget">
|
||||||
|
<span>{{ t("delete") }}</span>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
<Header />
|
||||||
|
<Content :config="props.data" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import Content from "../related/async-profiling/Content.vue";
|
||||||
|
import Header from "../related/async-profiling/Header.vue";
|
||||||
|
|
||||||
|
/*global defineProps*/
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
activeIndex: { type: String, default: "" },
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
function removeWidget() {
|
||||||
|
dashboardStore.removeControls(props.data);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: $font-size-smaller;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: $font-size-smaller;
|
||||||
|
border-bottom: 1px solid $border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
padding: 5px 0;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $active-color;
|
||||||
|
background-color: $popper-hover-bg-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -184,7 +184,7 @@ limitations under the License. -->
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 2px;
|
width: 2px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-color: #e8e8e8;
|
background-color: var(--sw-trace-line);
|
||||||
cursor: ew-resize;
|
cursor: ew-resize;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -61,6 +61,7 @@ limitations under the License. -->
|
|||||||
typesOfMQE: typesOfMQE || [],
|
typesOfMQE: typesOfMQE || [],
|
||||||
subExpressions: data.subExpressions || [],
|
subExpressions: data.subExpressions || [],
|
||||||
subTypesOfMQE: data.subTypesOfMQE || [],
|
subTypesOfMQE: data.subTypesOfMQE || [],
|
||||||
|
valueRelatedDashboard: data.valueRelatedDashboard,
|
||||||
}"
|
}"
|
||||||
:needQuery="needQuery"
|
:needQuery="needQuery"
|
||||||
@click="clickHandle"
|
@click="clickHandle"
|
||||||
|
@ -26,6 +26,7 @@ import DemandLog from "./DemandLog.vue";
|
|||||||
import Event from "./Event.vue";
|
import Event from "./Event.vue";
|
||||||
import NetworkProfiling from "./NetworkProfiling.vue";
|
import NetworkProfiling from "./NetworkProfiling.vue";
|
||||||
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
||||||
|
import AsyncProfiling from "./AsyncProfiling.vue";
|
||||||
import TimeRange from "./TimeRange.vue";
|
import TimeRange from "./TimeRange.vue";
|
||||||
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
||||||
import TaskTimeline from "./TaskTimeline.vue";
|
import TaskTimeline from "./TaskTimeline.vue";
|
||||||
@ -43,6 +44,7 @@ export default {
|
|||||||
Event,
|
Event,
|
||||||
NetworkProfiling,
|
NetworkProfiling,
|
||||||
ContinuousProfiling,
|
ContinuousProfiling,
|
||||||
|
AsyncProfiling,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
ThirdPartyApp,
|
ThirdPartyApp,
|
||||||
TaskTimeline,
|
TaskTimeline,
|
||||||
|
@ -25,6 +25,7 @@ import DemandLog from "./DemandLog.vue";
|
|||||||
import Event from "./Event.vue";
|
import Event from "./Event.vue";
|
||||||
import NetworkProfiling from "./NetworkProfiling.vue";
|
import NetworkProfiling from "./NetworkProfiling.vue";
|
||||||
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
||||||
|
import AsyncProfiling from "./AsyncProfiling.vue";
|
||||||
import TimeRange from "./TimeRange.vue";
|
import TimeRange from "./TimeRange.vue";
|
||||||
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
||||||
import TaskTimeline from "./TaskTimeline.vue";
|
import TaskTimeline from "./TaskTimeline.vue";
|
||||||
@ -43,5 +44,6 @@ export default {
|
|||||||
TimeRange,
|
TimeRange,
|
||||||
ThirdPartyApp,
|
ThirdPartyApp,
|
||||||
ContinuousProfiling,
|
ContinuousProfiling,
|
||||||
|
AsyncProfiling,
|
||||||
TaskTimeline,
|
TaskTimeline,
|
||||||
};
|
};
|
||||||
|
@ -150,6 +150,7 @@ export enum WidgetType {
|
|||||||
Event = "Event",
|
Event = "Event",
|
||||||
NetworkProfiling = "NetworkProfiling",
|
NetworkProfiling = "NetworkProfiling",
|
||||||
ContinuousProfiling = "ContinuousProfiling",
|
ContinuousProfiling = "ContinuousProfiling",
|
||||||
|
AsyncProfiling = "AsyncProfiling",
|
||||||
ThirdPartyApp = "ThirdPartyApp",
|
ThirdPartyApp = "ThirdPartyApp",
|
||||||
TaskTimeline = "TaskTimeline",
|
TaskTimeline = "TaskTimeline",
|
||||||
}
|
}
|
||||||
@ -171,6 +172,7 @@ export const ServiceTools = [
|
|||||||
{ name: "timeline", content: "Add Trace Profiling", id: WidgetType.Profile },
|
{ name: "timeline", content: "Add Trace Profiling", id: WidgetType.Profile },
|
||||||
{ name: "insert_chart", content: "Add eBPF Profiling", id: WidgetType.Ebpf },
|
{ name: "insert_chart", content: "Add eBPF Profiling", id: WidgetType.Ebpf },
|
||||||
{ name: "continuous_profiling", content: "Add Continuous Profiling", id: WidgetType.ContinuousProfiling },
|
{ name: "continuous_profiling", content: "Add Continuous Profiling", id: WidgetType.ContinuousProfiling },
|
||||||
|
{ name: "async_profiling", content: "Add Async Profiling", id: WidgetType.AsyncProfiling },
|
||||||
{ name: "assignment", content: "Add Log", id: WidgetType.Log },
|
{ name: "assignment", content: "Add Log", id: WidgetType.Log },
|
||||||
{ name: "demand", content: "Add On Demand Log", id: WidgetType.DemandLog },
|
{ name: "demand", content: "Add On Demand Log", id: WidgetType.DemandLog },
|
||||||
{ name: "event", content: "Add Event", id: WidgetType.Event },
|
{ name: "event", content: "Add Event", id: WidgetType.Event },
|
||||||
@ -266,8 +268,9 @@ export const TextColors: { [key: string]: string } = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const RefIdTypes = [
|
export const RefIdTypes = [
|
||||||
{ label: "Trace ID", value: "traceId" },
|
|
||||||
{ label: "None", value: "none" },
|
{ label: "None", value: "none" },
|
||||||
|
{ label: "Trace ID", value: "traceId" },
|
||||||
|
{ label: "Owner", value: "owner" },
|
||||||
];
|
];
|
||||||
export const RefreshOptions = [
|
export const RefreshOptions = [
|
||||||
{ label: "Last 30 minutes", value: "30", step: "MINUTE" },
|
{ label: "Last 30 minutes", value: "30", step: "MINUTE" },
|
||||||
|
@ -75,6 +75,34 @@ limitations under the License. -->
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
const color: string[] = chartColors();
|
const color: string[] = chartColors();
|
||||||
|
const legend =
|
||||||
|
appStore.theme === Themes.Dark
|
||||||
|
? {
|
||||||
|
pageIconColor: "#ccc",
|
||||||
|
pageIconInactiveColor: "#444",
|
||||||
|
backgroundColor: "#333",
|
||||||
|
borderColor: "#fff",
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: "#eee",
|
||||||
|
},
|
||||||
|
pageTextStyle: {
|
||||||
|
color: "#eee",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
pageIconColor: "#666",
|
||||||
|
pageIconInactiveColor: "#ccc",
|
||||||
|
backgroundColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
||||||
|
borderColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: "#333",
|
||||||
|
},
|
||||||
|
pageTextStyle: {
|
||||||
|
color: "#333",
|
||||||
|
},
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
color,
|
color,
|
||||||
tooltip: {
|
tooltip: {
|
||||||
@ -85,7 +113,7 @@ limitations under the License. -->
|
|||||||
},
|
},
|
||||||
enterable: true,
|
enterable: true,
|
||||||
confine: true,
|
confine: true,
|
||||||
extraCssText: "max-height:85%; overflow: auto;",
|
extraCssText: "max-width: 100%; max-height: 75%; white-space: normal; overflow: auto;",
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
type: "scroll",
|
type: "scroll",
|
||||||
@ -94,15 +122,10 @@ limitations under the License. -->
|
|||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
itemWidth: 12,
|
itemWidth: 12,
|
||||||
backgroundColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
...legend,
|
||||||
borderColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 12,
|
|
||||||
color: appStore.theme === Themes.Dark ? "#eee" : "#333",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: keys.length === 1 ? 15 : 40,
|
top: showEchartsLegend(keys) ? 35 : 10,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 10,
|
right: 10,
|
||||||
bottom: 5,
|
bottom: 5,
|
||||||
|
@ -22,7 +22,7 @@ limitations under the License. -->
|
|||||||
justifyContent: config.textAlign || 'center',
|
justifyContent: config.textAlign || 'center',
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
{{ singleVal }}
|
{{ getValue() }}
|
||||||
<span class="unit" v-show="config.showUnit && unit">
|
<span class="unit" v-show="config.showUnit && unit">
|
||||||
{{ decodeURIComponent(unit) }}
|
{{ decodeURIComponent(unit) }}
|
||||||
</span>
|
</span>
|
||||||
@ -34,6 +34,7 @@ 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 type { CardConfig, MetricConfigOpt } from "@/types/dashboard";
|
import type { CardConfig, MetricConfigOpt } from "@/types/dashboard";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -48,16 +49,36 @@ limitations under the License. -->
|
|||||||
showUnit: true,
|
showUnit: true,
|
||||||
textAlign: "center",
|
textAlign: "center",
|
||||||
metricConfig: [],
|
metricConfig: [],
|
||||||
|
valueMappings: {},
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const metricConfig = computed(() => props.config.metricConfig || []);
|
const metricConfig = computed(() => props.config.metricConfig || []);
|
||||||
|
const valueMappings = computed(() => props.config.valueMappings || {});
|
||||||
const key = computed(() => Object.keys(props.data)[0]);
|
const key = computed(() => Object.keys(props.data)[0]);
|
||||||
const singleVal = computed(() =>
|
const singleVal = computed(() =>
|
||||||
Array.isArray(props.data[key.value]) ? props.data[key.value][0] : props.data[key.value],
|
Array.isArray(props.data[key.value]) ? props.data[key.value][0] : props.data[key.value],
|
||||||
);
|
);
|
||||||
const unit = computed(() => metricConfig.value[0] && encodeURIComponent(metricConfig.value[0].unit || ""));
|
const unit = computed(() => metricConfig.value[0] && encodeURIComponent(metricConfig.value[0].unit || ""));
|
||||||
|
|
||||||
|
function getValue() {
|
||||||
|
if (valueMappings.value[singleVal.value]) {
|
||||||
|
return valueMappings.value[singleVal.value];
|
||||||
|
}
|
||||||
|
const list = Object.keys(valueMappings.value);
|
||||||
|
for (const i of list) {
|
||||||
|
try {
|
||||||
|
if (new RegExp(i).test(String(singleVal.value))) {
|
||||||
|
return valueMappings.value[i] || singleVal.value;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error("invalid regex string");
|
||||||
|
return singleVal.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return singleVal.value;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.chart-card {
|
.chart-card {
|
||||||
|
@ -16,16 +16,18 @@ limitations under the License. -->
|
|||||||
<div class="table">
|
<div class="table">
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<el-input v-model="searchText" placeholder="Search for more endpoints" @change="searchList" class="inputs">
|
<el-input v-model="searchText" placeholder="Search for more endpoints" @change="searchList" class="inputs">
|
||||||
|
<template #prepend>
|
||||||
|
<Selector style="width: 120px" v-model="topN" :options="topNList" placeholder="Select" />
|
||||||
|
</template>
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button @click="searchList">
|
<el-button @click="searchList">
|
||||||
<Icon size="middle" iconName="search" />
|
<Icon size="middle" iconName="search" />
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
<span class="ml-5 tips">{{ t("endpointTips") }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<el-table v-loading="chartLoading" :data="endpoints" style="width: 100%">
|
<el-table v-loading="chartLoading" :data="currentEndpoints" style="width: 100%">
|
||||||
<el-table-column label="Endpoints" fixed min-width="220">
|
<el-table-column label="Endpoints" fixed min-width="220">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span class="link" @click="clickEndpoint(scope)" :style="{ fontSize: `${config.fontSize}px` }">
|
<span class="link" @click="clickEndpoint(scope)" :style="{ fontSize: `${config.fontSize}px` }">
|
||||||
@ -46,13 +48,22 @@ limitations under the License. -->
|
|||||||
/>
|
/>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
|
<el-pagination
|
||||||
|
class="pagination flex-h"
|
||||||
|
layout="prev, pager, next"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-size="pageSize"
|
||||||
|
:total="endpoints.length"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
@prev-click="changePage"
|
||||||
|
@next-click="changePage"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import type { EndpointListConfig } from "@/types/dashboard";
|
import type { EndpointListConfig } from "@/types/dashboard";
|
||||||
import type { Endpoint } from "@/types/selector";
|
import type { Endpoint } from "@/types/selector";
|
||||||
@ -90,16 +101,26 @@ limitations under the License. -->
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["expressionTips"]);
|
const emit = defineEmits(["expressionTips"]);
|
||||||
const { t } = useI18n();
|
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const chartLoading = ref<boolean>(false);
|
const chartLoading = ref<boolean>(false);
|
||||||
const endpoints = ref<Endpoint[]>([]);
|
const endpoints = ref<Endpoint[]>([]); // all of endpoints
|
||||||
|
const currentEndpoints = ref<Endpoint[]>([]); // current page of endpoints
|
||||||
const searchText = ref<string>("");
|
const searchText = ref<string>("");
|
||||||
const colMetrics = ref<string[]>([]);
|
const colMetrics = ref<string[]>([]);
|
||||||
const colSubMetrics = ref<string[]>([]);
|
const colSubMetrics = ref<string[]>([]);
|
||||||
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
||||||
const typesOfMQE = ref<string[]>(props.config.typesOfMQE || []);
|
const typesOfMQE = ref<string[]>(props.config.typesOfMQE || []);
|
||||||
|
const topN = ref<number>(20);
|
||||||
|
const currentPage = ref<number>(1);
|
||||||
|
const pageSize = 10;
|
||||||
|
const topNList = [
|
||||||
|
{ label: "TopN20", value: 20 },
|
||||||
|
{ label: "TopN50", value: 50 },
|
||||||
|
{ label: "TopN100", value: 100 },
|
||||||
|
{ label: "TopN150", value: 150 },
|
||||||
|
{ label: "TopN200", value: 200 },
|
||||||
|
];
|
||||||
|
|
||||||
if (props.needQuery) {
|
if (props.needQuery) {
|
||||||
queryEndpoints();
|
queryEndpoints();
|
||||||
@ -108,6 +129,7 @@ limitations under the License. -->
|
|||||||
chartLoading.value = true;
|
chartLoading.value = true;
|
||||||
const resp = await selectorStore.getEndpoints({
|
const resp = await selectorStore.getEndpoints({
|
||||||
keyword: searchText.value,
|
keyword: searchText.value,
|
||||||
|
limit: topN.value,
|
||||||
});
|
});
|
||||||
|
|
||||||
chartLoading.value = false;
|
chartLoading.value = false;
|
||||||
@ -116,7 +138,8 @@ limitations under the License. -->
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
endpoints.value = resp.data.pods || [];
|
endpoints.value = resp.data.pods || [];
|
||||||
queryEndpointMetrics(endpoints.value);
|
currentEndpoints.value = endpoints.value.filter((d: unknown, index: number) => index < pageSize);
|
||||||
|
queryEndpointMetrics(currentEndpoints.value);
|
||||||
}
|
}
|
||||||
async function queryEndpointMetrics(arr: Endpoint[]) {
|
async function queryEndpointMetrics(arr: Endpoint[]) {
|
||||||
if (!arr.length) {
|
if (!arr.length) {
|
||||||
@ -142,7 +165,7 @@ limitations under the License. -->
|
|||||||
{ metricConfig: metricConfig.value || [], expressions, subExpressions },
|
{ metricConfig: metricConfig.value || [], expressions, subExpressions },
|
||||||
EntityType[2].value,
|
EntityType[2].value,
|
||||||
);
|
);
|
||||||
endpoints.value = params.data;
|
currentEndpoints.value = params.data;
|
||||||
colMetrics.value = params.names;
|
colMetrics.value = params.names;
|
||||||
colSubMetrics.value = params.subNames;
|
colSubMetrics.value = params.subNames;
|
||||||
metricConfig.value = params.metricConfigArr;
|
metricConfig.value = params.metricConfigArr;
|
||||||
@ -151,7 +174,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
endpoints.value = currentPods;
|
currentEndpoints.value = currentPods;
|
||||||
colMetrics.value = [];
|
colMetrics.value = [];
|
||||||
colSubMetrics.value = [];
|
colSubMetrics.value = [];
|
||||||
metricConfig.value = [];
|
metricConfig.value = [];
|
||||||
@ -175,6 +198,16 @@ limitations under the License. -->
|
|||||||
async function searchList() {
|
async function searchList() {
|
||||||
await queryEndpoints();
|
await queryEndpoints();
|
||||||
}
|
}
|
||||||
|
function changePage() {
|
||||||
|
currentEndpoints.value = endpoints.value.filter(
|
||||||
|
(_, index: number) => index >= (currentPage.value - 1) * pageSize && index < currentPage.value * pageSize,
|
||||||
|
);
|
||||||
|
queryEndpointMetrics(currentEndpoints.value);
|
||||||
|
}
|
||||||
|
function handleCurrentChange(val: number) {
|
||||||
|
currentPage.value = val;
|
||||||
|
changePage();
|
||||||
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [
|
() => [
|
||||||
...(props.config.metricConfig || []),
|
...(props.config.metricConfig || []),
|
||||||
|
@ -16,10 +16,11 @@ limitations under the License. -->
|
|||||||
<div class="graph flex-v" :class="setRight ? 'flex-h' : 'flex-v'">
|
<div class="graph flex-v" :class="setRight ? 'flex-h' : 'flex-v'">
|
||||||
<Graph
|
<Graph
|
||||||
:option="option"
|
:option="option"
|
||||||
@select="clickEvent"
|
|
||||||
:filters="config.filters"
|
:filters="config.filters"
|
||||||
:relatedTrace="config.relatedTrace"
|
:relatedTrace="config.relatedTrace"
|
||||||
:associate="config.associate || []"
|
:associate="config.associate || []"
|
||||||
|
:legendSelector="{ isSelector: legendSelector, sConfigPage: dashboardStore.showConfig }"
|
||||||
|
@select="clickEvent"
|
||||||
/>
|
/>
|
||||||
<Legend :config="config.legend" :data="data" :intervalTime="intervalTime" />
|
<Legend :config="config.legend" :data="data" :intervalTime="intervalTime" />
|
||||||
</div>
|
</div>
|
||||||
@ -32,6 +33,7 @@ limitations under the License. -->
|
|||||||
import useLegendProcess from "@/hooks/useLegendProcessor";
|
import useLegendProcess from "@/hooks/useLegendProcessor";
|
||||||
import { isDef } from "@/utils/is";
|
import { isDef } from "@/utils/is";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { Themes } from "@/constants/data";
|
import { Themes } from "@/constants/data";
|
||||||
|
|
||||||
/*global defineProps, defineEmits */
|
/*global defineProps, defineEmits */
|
||||||
@ -60,19 +62,24 @@ limitations under the License. -->
|
|||||||
showYAxis: true,
|
showYAxis: true,
|
||||||
smallTips: false,
|
smallTips: false,
|
||||||
showlabels: true,
|
showlabels: true,
|
||||||
|
noTooltips: false,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
const setRight = ref<boolean>(false);
|
const setRight = ref<boolean>(false);
|
||||||
|
const legendSelector = computed(() => props.config.legend?.asSelector);
|
||||||
const option = computed(() => getOption());
|
const option = computed(() => getOption());
|
||||||
function getOption() {
|
function getOption() {
|
||||||
const { showEchartsLegend, isRight, chartColors } = useLegendProcess(props.config.legend);
|
const { showEchartsLegend, isRight, chartColors } = useLegendProcess(props.config.legend);
|
||||||
setRight.value = isRight;
|
setRight.value = isRight;
|
||||||
const keys = Object.keys(props.data || {}).filter((i: any) => Array.isArray(props.data[i]) && props.data[i].length);
|
const keys = Object.keys(props.data || {}).filter(
|
||||||
const temp = keys.map((i: any) => {
|
(i: string) => Array.isArray(props.data[i]) && props.data[i].length,
|
||||||
|
);
|
||||||
|
const temp = keys.map((i: string) => {
|
||||||
const serie: any = {
|
const serie: any = {
|
||||||
data: props.data[i].map((item: any, itemIndex: number) => [props.intervalTime[itemIndex], item]),
|
data: props.data[i].map((item: number, itemIndex: number) => [props.intervalTime[itemIndex], item]),
|
||||||
name: i,
|
name: i,
|
||||||
type: "line",
|
type: "line",
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
@ -95,6 +102,7 @@ limitations under the License. -->
|
|||||||
const color: string[] = chartColors();
|
const color: string[] = chartColors();
|
||||||
const tooltip = {
|
const tooltip = {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
|
show: !props.config.noTooltips,
|
||||||
backgroundColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
backgroundColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
||||||
borderColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
borderColor: appStore.theme === Themes.Dark ? "#333" : "#fff",
|
||||||
textStyle: {
|
textStyle: {
|
||||||
@ -103,13 +111,13 @@ limitations under the License. -->
|
|||||||
},
|
},
|
||||||
enterable: true,
|
enterable: true,
|
||||||
confine: true,
|
confine: true,
|
||||||
extraCssText: "max-height:85%; overflow: auto;",
|
extraCssText: "max-width: 100%; max-height: 75%; white-space: normal; overflow: auto;",
|
||||||
};
|
};
|
||||||
const tips = {
|
const tips = {
|
||||||
|
show: !props.config.noTooltips,
|
||||||
formatter(params: any) {
|
formatter(params: any) {
|
||||||
return `${params[0].value[1]}`;
|
return `${params[0].value[1]}`;
|
||||||
},
|
},
|
||||||
confine: true,
|
|
||||||
extraCssText: `height: 20px; padding:0 2px;`,
|
extraCssText: `height: 20px; padding:0 2px;`,
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
backgroundColor: appStore.theme === Themes.Dark ? "#666" : "#eee",
|
backgroundColor: appStore.theme === Themes.Dark ? "#666" : "#eee",
|
||||||
@ -119,7 +127,30 @@ limitations under the License. -->
|
|||||||
color: appStore.theme === Themes.Dark ? "#eee" : "#333",
|
color: appStore.theme === Themes.Dark ? "#eee" : "#333",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
const legend =
|
||||||
|
appStore.theme === Themes.Dark
|
||||||
|
? {
|
||||||
|
pageIconColor: "#ccc",
|
||||||
|
pageIconInactiveColor: "#444",
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: "#eee",
|
||||||
|
},
|
||||||
|
pageTextStyle: {
|
||||||
|
color: "#eee",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
pageIconColor: "#666",
|
||||||
|
pageIconInactiveColor: "#ccc",
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 12,
|
||||||
|
color: "#333",
|
||||||
|
},
|
||||||
|
pageTextStyle: {
|
||||||
|
color: "#333",
|
||||||
|
},
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
color,
|
color,
|
||||||
tooltip: props.config.smallTips ? tips : tooltip,
|
tooltip: props.config.smallTips ? tips : tooltip,
|
||||||
@ -130,16 +161,15 @@ limitations under the License. -->
|
|||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
itemWidth: 12,
|
itemWidth: 12,
|
||||||
textStyle: {
|
data: keys.map((d: string) => ({ name: d })),
|
||||||
color: appStore.theme === Themes.Dark ? "#fff" : "#333",
|
...legend,
|
||||||
},
|
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: showEchartsLegend(keys) ? 35 : 10,
|
top: showEchartsLegend(keys) ? 35 : 10,
|
||||||
left: 0,
|
left: 0,
|
||||||
right: 10,
|
right: 10,
|
||||||
bottom: 5,
|
bottom: 5,
|
||||||
containLabel: props.config.showlabels === undefined ? true : props.config.showlabels,
|
containLabel: isDef(props.config.showlabels) ? props.config.showlabels : true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
|
@ -37,7 +37,7 @@ limitations under the License. -->
|
|||||||
>{{ k.split("=")[1] }}</div
|
>{{ k.split("=")[1] }}</div
|
||||||
>
|
>
|
||||||
<div class="value-col" v-if="config.showTableValues">
|
<div class="value-col" v-if="config.showTableValues">
|
||||||
{{ data[(keys as string[]).join(",")][data[(keys as string[]).join(",")].length - 1 || 0] }}
|
{{ getColValue(keys) }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -47,6 +47,8 @@ limitations under the License. -->
|
|||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
@ -58,12 +60,14 @@ limitations under the License. -->
|
|||||||
showTableValues: boolean;
|
showTableValues: boolean;
|
||||||
tableHeaderCol2: string;
|
tableHeaderCol2: string;
|
||||||
typesOfMQE: string[];
|
typesOfMQE: string[];
|
||||||
|
valueMappings: {};
|
||||||
}>,
|
}>,
|
||||||
default: () => ({ showTableValues: true }),
|
default: () => ({ showTableValues: true }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const valueMappings = computed<{ [key: string]: string }>(() => props.config.valueMappings || {});
|
||||||
const nameWidth = computed(() => (props.config.showTableValues ? 80 : 100));
|
const nameWidth = computed(() => (props.config.showTableValues ? 80 : 100));
|
||||||
const dataKeys = computed(() => {
|
const dataKeys = computed(() => {
|
||||||
const keys = Object.keys(props.data || {}).filter(
|
const keys = Object.keys(props.data || {}).filter(
|
||||||
@ -73,6 +77,25 @@ limitations under the License. -->
|
|||||||
|
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function getColValue(keys: string[]) {
|
||||||
|
const source = props.data[(keys as string[]).join(",")][props.data[(keys as string[]).join(",")].length - 1 || 0];
|
||||||
|
if (valueMappings.value[source]) {
|
||||||
|
return valueMappings.value[source];
|
||||||
|
}
|
||||||
|
const list = Object.keys(valueMappings.value);
|
||||||
|
for (const i of list) {
|
||||||
|
try {
|
||||||
|
if (new RegExp(i).test(String(source))) {
|
||||||
|
return valueMappings.value[i] || source;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
ElMessage.error("invalid regex string");
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return source;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.chart-table {
|
.chart-table {
|
||||||
|
@ -32,9 +32,12 @@ limitations under the License. -->
|
|||||||
<div class="operation" @click="handleClick(i.name)">
|
<div class="operation" @click="handleClick(i.name)">
|
||||||
<span>{{ t("copy") }}</span>
|
<span>{{ t("copy") }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="operation" @click="viewTrace(i)" v-show="refIdType === RefIdTypes[0].value">
|
<div class="operation" @click="viewTrace(i)" v-show="![RefIdTypes[0].value].includes(refIdType)">
|
||||||
<span>{{ t("viewTrace") }}</span>
|
<span>{{ t("viewTrace") }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="operation" @click="viewDashboard(i)" v-show="props.config.valueRelatedDashboard">
|
||||||
|
<span>{{ t("viewValueDashboard") }}</span>
|
||||||
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
<el-progress
|
<el-progress
|
||||||
@ -61,16 +64,18 @@ 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 { computed, ref } from "vue";
|
import { computed, ref } from "vue";
|
||||||
|
import router from "@/router";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import copy from "@/utils/copy";
|
import copy from "@/utils/copy";
|
||||||
import { TextColors } from "@/views/dashboard/data";
|
import { TextColors, MetricCatalog } from "@/views/dashboard/data";
|
||||||
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
||||||
import { WidgetType, QueryOrders, Status, RefIdTypes, ExpressionResultType } from "@/views/dashboard/data";
|
import { WidgetType, QueryOrders, Status, RefIdTypes, ExpressionResultType } from "@/views/dashboard/data";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps, Recordable*/
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
[key: string]: { name: string; value: number; refId: string }[];
|
[key: string]: { name: string; value: number; refId: string; owner: object }[];
|
||||||
}>,
|
}>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
@ -80,12 +85,14 @@ limitations under the License. -->
|
|||||||
expressions: string[];
|
expressions: string[];
|
||||||
typesOfMQE: string[];
|
typesOfMQE: string[];
|
||||||
relatedTrace: any;
|
relatedTrace: any;
|
||||||
|
valueRelatedDashboard: string;
|
||||||
}>,
|
}>,
|
||||||
default: () => ({ color: "purple" }),
|
default: () => ({ color: "purple" }),
|
||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
const showTrace = ref<boolean>(false);
|
const showTrace = ref<boolean>(false);
|
||||||
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
||||||
type: WidgetType.Trace,
|
type: WidgetType.Trace,
|
||||||
@ -107,14 +114,15 @@ limitations under the License. -->
|
|||||||
function handleClick(i: string) {
|
function handleClick(i: string) {
|
||||||
copy(i);
|
copy(i);
|
||||||
}
|
}
|
||||||
function viewTrace(item: { name: string; refId: string; value: unknown }) {
|
function viewTrace(item: { name: string; refId: string; value: unknown; owner: object }) {
|
||||||
const filters = {
|
const filters = {
|
||||||
...item,
|
...item,
|
||||||
queryOrder: QueryOrders[1].value,
|
queryOrder: QueryOrders[1].value,
|
||||||
status: Status[2].value,
|
status: Status[2].value,
|
||||||
id: item.refId,
|
id: refIdType.value === RefIdTypes[1].value ? item.refId : undefined,
|
||||||
metricValue: [{ label: props.config.expressions[0], data: item.value, value: item.name }],
|
metricValue: [{ label: props.config.expressions[0], data: item.value, value: item.name }],
|
||||||
isReadRecords: props.config.typesOfMQE.includes(ExpressionResultType.RECORD_LIST) || undefined,
|
isReadRecords: props.config.typesOfMQE.includes(ExpressionResultType.RECORD_LIST) || undefined,
|
||||||
|
owner: refIdType.value === RefIdTypes[2].value ? item.owner : null,
|
||||||
};
|
};
|
||||||
traceOptions.value = {
|
traceOptions.value = {
|
||||||
...traceOptions.value,
|
...traceOptions.value,
|
||||||
@ -122,6 +130,23 @@ limitations under the License. -->
|
|||||||
};
|
};
|
||||||
showTrace.value = true;
|
showTrace.value = true;
|
||||||
}
|
}
|
||||||
|
function viewDashboard(item: Recordable) {
|
||||||
|
const { owner } = item;
|
||||||
|
let path;
|
||||||
|
if (owner.scope === MetricCatalog.SERVICE) {
|
||||||
|
path = `/dashboard/${dashboardStore.layerId}/${owner.scope}/${owner.serviceID}/${props.config.valueRelatedDashboard}`;
|
||||||
|
}
|
||||||
|
if (owner.scope === MetricCatalog.SERVICE_INSTANCE) {
|
||||||
|
path = `/dashboard/${dashboardStore.layerId}/${owner.scope}/${owner.serviceID}/${owner.serviceInstanceID}/${props.config.valueRelatedDashboard}`;
|
||||||
|
}
|
||||||
|
if (owner.scope === MetricCatalog.ENDPOINT) {
|
||||||
|
path = `/dashboard/${dashboardStore.layerId}/${owner.scope}/${owner.serviceID}/${owner.endpointID}/${props.config.valueRelatedDashboard}`;
|
||||||
|
}
|
||||||
|
if (!path) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
router.push(path);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.top-list {
|
.top-list {
|
||||||
@ -187,11 +212,10 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.operation {
|
.operation {
|
||||||
padding: 5px 0;
|
padding: 5px;
|
||||||
color: $font-color;
|
color: $font-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position: relative;
|
position: relative;
|
||||||
text-align: center;
|
|
||||||
font-size: $font-size-smaller;
|
font-size: $font-size-smaller;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
@ -53,5 +53,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.inputs {
|
.inputs {
|
||||||
width: 300px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
@ -77,16 +77,20 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function queryMetrics() {
|
async function queryMetrics() {
|
||||||
const widgets = [];
|
const widgets: LayoutConfig[] = [];
|
||||||
|
|
||||||
for (const item of dashboardStore.layout) {
|
for (const item of dashboardStore.layout) {
|
||||||
const isList = ListChartTypes.includes(item.type || "");
|
if (item.type === WidgetType.Widget) {
|
||||||
if (item.type === WidgetType.Widget && !isList) {
|
if (!ListChartTypes.includes(item.graph?.type || "")) {
|
||||||
widgets.push(item);
|
widgets.push(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (item.type === WidgetType.Tab) {
|
if (item.type === WidgetType.Tab) {
|
||||||
const index = isNaN(item.activedTabIndex) ? 0 : item.activedTabIndex;
|
const index = isNaN(item.activedTabIndex) ? 0 : item.activedTabIndex;
|
||||||
widgets.push(...item.children[index].children);
|
widgets.push(
|
||||||
|
...item.children[index].children.filter(
|
||||||
|
(d: LayoutConfig) => d.type === WidgetType.Widget && !ListChartTypes.includes(d.graph?.type || ""),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const configList = widgets.map((d: LayoutConfig) => ({
|
const configList = widgets.map((d: LayoutConfig) => ({
|
||||||
@ -103,7 +107,9 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
async function queryTabsMetrics() {
|
async function queryTabsMetrics() {
|
||||||
const configList = dashboardStore.currentTabItems
|
const configList = dashboardStore.currentTabItems
|
||||||
.filter((item: LayoutConfig) => item.type === WidgetType.Widget && !ListChartTypes.includes(item.type || ""))
|
.filter(
|
||||||
|
(item: LayoutConfig) => item.type === WidgetType.Widget && !ListChartTypes.includes(item.graph?.type || ""),
|
||||||
|
)
|
||||||
.map((d: LayoutConfig) => ({
|
.map((d: LayoutConfig) => ({
|
||||||
metrics: d.expressions || [],
|
metrics: d.expressions || [],
|
||||||
metricConfig: d.metricConfig || [],
|
metricConfig: d.metricConfig || [],
|
||||||
@ -151,7 +157,7 @@ limitations under the License. -->
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
watch(
|
watch(
|
||||||
() => appStore.durationTime,
|
() => [appStore.durationTime, dashboardStore.layout],
|
||||||
() => {
|
() => {
|
||||||
if (dashboardStore.entity === EntityType[1].value) {
|
if (dashboardStore.entity === EntityType[1].value) {
|
||||||
queryMetrics();
|
queryMetrics();
|
||||||
|
@ -16,7 +16,7 @@ limitations under the License. -->
|
|||||||
<div class="dashboard-tool flex-h">
|
<div class="dashboard-tool flex-h">
|
||||||
<div :class="isRelation ? 'flex-v' : 'flex-h'" class="tool-selectors">
|
<div :class="isRelation ? 'flex-v' : 'flex-h'" class="tool-selectors">
|
||||||
<div class="flex-h">
|
<div class="flex-h">
|
||||||
<div class="selectors-item" v-if="key !== 10">
|
<div class="flex-h selectors-item" v-if="key !== 10">
|
||||||
<span class="label">$Service</span>
|
<span class="label">$Service</span>
|
||||||
<Selector
|
<Selector
|
||||||
v-model="states.currentService"
|
v-model="states.currentService"
|
||||||
@ -30,7 +30,7 @@ limitations under the License. -->
|
|||||||
<Icon size="small" iconName="hierarchy_topology" />
|
<Icon size="small" iconName="hierarchy_topology" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 3 || key === 4 || key === 5 || key === 6">
|
<div class="flex-h selectors-item" v-if="key === 3 || key === 4 || key === 5 || key === 6">
|
||||||
<span class="label">
|
<span class="label">
|
||||||
{{ ["EndpointRelation", "Endpoint"].includes(dashboardStore.entity) ? "$Endpoint" : "$ServiceInstance" }}
|
{{ ["EndpointRelation", "Endpoint"].includes(dashboardStore.entity) ? "$Endpoint" : "$ServiceInstance" }}
|
||||||
</span>
|
</span>
|
||||||
@ -52,7 +52,7 @@ limitations under the License. -->
|
|||||||
<Icon size="small" iconName="hierarchy_topology" />
|
<Icon size="small" iconName="hierarchy_topology" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 5 || key === 6">
|
<div class="flex-h selectors-item" v-if="key === 5 || key === 6">
|
||||||
<span class="label"> $Process </span>
|
<span class="label"> $Process </span>
|
||||||
<Selector
|
<Selector
|
||||||
v-model="states.currentProcess"
|
v-model="states.currentProcess"
|
||||||
@ -65,7 +65,7 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-h" :class="isRelation ? 'relation' : ''">
|
<div class="flex-h" :class="isRelation ? 'relation' : ''">
|
||||||
<div class="selectors-item" v-if="key === 2 || key === 4 || key === 5">
|
<div class="flex-h selectors-item" v-if="key === 2 || key === 4 || key === 5">
|
||||||
<span class="label">$DestinationService</span>
|
<span class="label">$DestinationService</span>
|
||||||
<Selector
|
<Selector
|
||||||
v-model="states.currentDestService"
|
v-model="states.currentDestService"
|
||||||
@ -76,7 +76,7 @@ limitations under the License. -->
|
|||||||
class="selectors"
|
class="selectors"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 4 || key === 5">
|
<div class="flex-h selectors-item" v-if="key === 4 || key === 5">
|
||||||
<span class="label">
|
<span class="label">
|
||||||
{{ dashboardStore.entity === "EndpointRelation" ? "$DestinationEndpoint" : "$DestinationServiceInstance" }}
|
{{ dashboardStore.entity === "EndpointRelation" ? "$DestinationEndpoint" : "$DestinationServiceInstance" }}
|
||||||
</span>
|
</span>
|
||||||
@ -91,7 +91,7 @@ limitations under the License. -->
|
|||||||
:isRemote="dashboardStore.entity === 'EndpointRelation'"
|
:isRemote="dashboardStore.entity === 'EndpointRelation'"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 5">
|
<div class="flex-h selectors-item" v-if="key === 5">
|
||||||
<span class="label"> $DestinationProcess </span>
|
<span class="label"> $DestinationProcess </span>
|
||||||
<Selector
|
<Selector
|
||||||
v-model="states.currentDestProcess"
|
v-model="states.currentDestProcess"
|
||||||
@ -105,11 +105,11 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-h tools" v-loading="loading" v-if="!appStore.isMobile">
|
<div class="flex-h tools" v-loading="loading" v-if="!appStore.isMobile">
|
||||||
<div class="tool-icons" v-if="dashboardStore.editMode">
|
<div class="flex-h" v-if="dashboardStore.editMode">
|
||||||
<el-dropdown content="Controls" placement="bottom" :persistent="false">
|
<el-dropdown content="Controls" placement="bottom" :persistent="false">
|
||||||
<i>
|
<div class="icon-btn">
|
||||||
<Icon class="icon-btn" size="sm" iconName="control" />
|
<Icon size="sm" iconName="control" />
|
||||||
</i>
|
</div>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<el-dropdown-item @click="clickIcons(t)" v-for="(t, index) in toolIcons" :key="index" :title="t.content">
|
<el-dropdown-item @click="clickIcons(t)" v-for="(t, index) in toolIcons" :key="index" :title="t.content">
|
||||||
@ -120,9 +120,9 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
<el-tooltip content="Apply" placement="bottom">
|
<el-tooltip content="Apply" placement="bottom">
|
||||||
<i @click="applyDashboard">
|
<div class="icon-btn" @click="applyDashboard">
|
||||||
<Icon class="icon-btn" size="sm" iconName="save" />
|
<Icon size="sm" iconName="save" />
|
||||||
</i>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-5">
|
<div class="ml-5">
|
||||||
@ -693,10 +693,6 @@ limitations under the License. -->
|
|||||||
padding: 4px 2px;
|
padding: 4px 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool-icons {
|
|
||||||
margin-top: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tools {
|
.tools {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -704,9 +700,10 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.icon-btn {
|
.icon-btn {
|
||||||
display: inline-block;
|
width: 22px;
|
||||||
padding: 3px;
|
height: 22px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
line-height: 18px;
|
||||||
border: 1px solid var(--sw-icon-btn-border);
|
border: 1px solid var(--sw-icon-btn-border);
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
@ -734,7 +731,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
.hierarchy-btn {
|
.hierarchy-btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 0 2px 2px;
|
padding: 0 3px;
|
||||||
border: 1px solid #666;
|
border: 1px solid #666;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
69
src/views/dashboard/related/async-profiling/Content.vue
Normal file
69
src/views/dashboard/related/async-profiling/Content.vue
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
<!-- 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 content">
|
||||||
|
<TaskList />
|
||||||
|
<div class="vis-graph ml-5">
|
||||||
|
<div class="mb-20">
|
||||||
|
<Filter />
|
||||||
|
</div>
|
||||||
|
<div class="stack" v-loading="asyncProfilingStore.loadingTree">
|
||||||
|
<EBPFStack :type="ComponentType" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted } from "vue";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import TaskList from "./components/TaskList.vue";
|
||||||
|
import Filter from "./components/Filter.vue";
|
||||||
|
import EBPFStack from "@/views/dashboard/related/ebpf/components/EBPFStack.vue";
|
||||||
|
import { ComponentType } from "./components/data";
|
||||||
|
|
||||||
|
const asyncProfilingStore = useAsyncProfilingStore();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const resp = await asyncProfilingStore.getServiceInstances({ serviceId: selectorStore.currentService.id });
|
||||||
|
if (resp && resp.errors) {
|
||||||
|
ElMessage.error(resp.errors);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content {
|
||||||
|
height: calc(100% - 30px);
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vis-graph {
|
||||||
|
height: 100%;
|
||||||
|
flex-grow: 2;
|
||||||
|
min-width: 700px;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
width: calc(100% - 330px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stack {
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
height: calc(100% - 100px);
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
50
src/views/dashboard/related/async-profiling/Header.vue
Normal file
50
src/views/dashboard/related/async-profiling/Header.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!-- 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="title">Async Profiling</div>
|
||||||
|
<el-button class="mr-20" size="small" type="primary" @click="() => (newTask = true)">
|
||||||
|
{{ 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 } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import NewTask from "./components/NewTask.vue";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const newTask = ref<boolean>(false);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: $font-size-smaller;
|
||||||
|
border-bottom: 1px solid $border-color;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
width: 270px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,115 @@
|
|||||||
|
<!-- 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">
|
||||||
|
<Selector
|
||||||
|
class="filter-selector"
|
||||||
|
:multiple="true"
|
||||||
|
:value="serviceInstanceIds"
|
||||||
|
size="small"
|
||||||
|
:options="instances"
|
||||||
|
placeholder="Select instances"
|
||||||
|
@change="changeInstances"
|
||||||
|
/>
|
||||||
|
<Selector
|
||||||
|
class="filter-events"
|
||||||
|
:value="selectedEventType"
|
||||||
|
size="small"
|
||||||
|
:options="eventTypes"
|
||||||
|
placeholder="Select a event"
|
||||||
|
@change="changeEventType"
|
||||||
|
/>
|
||||||
|
<el-button type="primary" size="small" @click="analyzeProfiling">
|
||||||
|
{{ t("analyze") }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, ref, watch } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||||
|
import type { Instance } from "@/types/selector";
|
||||||
|
import type { Option } from "@/types/app";
|
||||||
|
import { EventsMap, ProfilingEvents, JFREventType } from "./data";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const asyncProfilingStore = useAsyncProfilingStore();
|
||||||
|
const serviceInstanceIds = ref<string[]>([]);
|
||||||
|
const selectedEventType = ref<string>("");
|
||||||
|
const eventTypes = computed(() =>
|
||||||
|
(asyncProfilingStore.selectedTask.events ?? [])
|
||||||
|
.map((d: string) => {
|
||||||
|
if (d === ProfilingEvents[1]) {
|
||||||
|
return [
|
||||||
|
{ label: JFREventType.OBJECT_ALLOCATION_IN_NEW_TLAB, value: JFREventType.OBJECT_ALLOCATION_IN_NEW_TLAB },
|
||||||
|
{ label: JFREventType.OBJECT_ALLOCATION_OUTSIDE_TLAB, value: JFREventType.OBJECT_ALLOCATION_OUTSIDE_TLAB },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return { label: d, value: d };
|
||||||
|
})
|
||||||
|
.flat(),
|
||||||
|
);
|
||||||
|
const instances = computed(() =>
|
||||||
|
asyncProfilingStore.instances.filter((d: Instance) =>
|
||||||
|
(asyncProfilingStore.selectedTask.successInstanceIds ?? []).includes(d.id),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
function changeInstances(options: Option[]) {
|
||||||
|
serviceInstanceIds.value = options.map((d: Option) => d.value);
|
||||||
|
asyncProfilingStore.setAnalyzeTrees([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeEventType(options: Option[]) {
|
||||||
|
selectedEventType.value = options[0].value;
|
||||||
|
asyncProfilingStore.setAnalyzeTrees([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function analyzeProfiling() {
|
||||||
|
const instanceIds = asyncProfilingStore.instances
|
||||||
|
.filter((d: Instance) => (serviceInstanceIds.value ?? []).includes(d.value))
|
||||||
|
.map((d: Instance) => d.id);
|
||||||
|
const res = await asyncProfilingStore.getAsyncProfilingAnalyze({
|
||||||
|
instanceIds,
|
||||||
|
taskId: asyncProfilingStore.selectedTask.id,
|
||||||
|
eventType: (EventsMap as any)[selectedEventType.value],
|
||||||
|
});
|
||||||
|
if (res.data && res.data.errors) {
|
||||||
|
ElMessage.error(res.data.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => asyncProfilingStore.selectedTask.successInstanceIds,
|
||||||
|
() => {
|
||||||
|
serviceInstanceIds.value = [];
|
||||||
|
selectedEventType.value = "";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.filter-selector {
|
||||||
|
width: 400px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filter-events {
|
||||||
|
width: 300px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,187 @@
|
|||||||
|
<!-- 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="async-profile-task">
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("instance") }}</div>
|
||||||
|
<Selector
|
||||||
|
class="profile-input"
|
||||||
|
:multiple="true"
|
||||||
|
:value="serviceInstanceIds"
|
||||||
|
size="small"
|
||||||
|
:options="asyncProfilingStore.instances"
|
||||||
|
placeholder="Select instances"
|
||||||
|
@change="changeInstances"
|
||||||
|
:filterable="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("duration") }}</div>
|
||||||
|
<Radio class="mb-5" :value="duration" :options="DurationOptions" @change="changeDuration" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">{{ t("profilingEvents") }}</div>
|
||||||
|
<el-checkbox-group v-model="asyncEvents" class="profile-input mb-5">
|
||||||
|
<el-checkbox
|
||||||
|
v-for="event in ProfilingEvents"
|
||||||
|
:label="event"
|
||||||
|
:value="event"
|
||||||
|
:key="event"
|
||||||
|
:disabled="disableEvents(event)"
|
||||||
|
/>
|
||||||
|
</el-checkbox-group>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">
|
||||||
|
<span class="mr-5 cp">{{ t("execArgs") }}</span>
|
||||||
|
<el-popover placement="right" :width="480" trigger="hover" title="Async profiler extension parameters">
|
||||||
|
<template #reference>
|
||||||
|
<span>
|
||||||
|
<Icon iconName="help" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
<span class="mr-10">live </span>
|
||||||
|
<span>- build allocation profile from live objects only</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mr-10">lock[=DURATION] </span>
|
||||||
|
<span>- profile contended locks overflowing the DURATION ns bucket (default: 10us)</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mr-10">alloc[=BYTES] </span>
|
||||||
|
<span>- profile allocations with BYTES interval</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mr-10">interval=N </span>
|
||||||
|
<span>- sampling interval in ns (default: 10'000'000, i.e. 10 ms)</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mr-10">jstackdepth=N </span>
|
||||||
|
<span>- maximum Java stack depth (default: 2048)</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mr-10">chunksize=N </span>
|
||||||
|
<span>- approximate size of JFR chunk in bytes (default: 100 MB)</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span class="mr-10">chunktime=N </span>
|
||||||
|
<span>- duration of JFR chunk in seconds (default: 1 hour)</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
<el-input size="small" class="profile-input" v-model="execArgs" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<el-button @click="createTask" type="primary" class="create-task-btn" :loading="loading">
|
||||||
|
{{ t("createTask") }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { DurationOptions, ProfilingEvents } from "./data";
|
||||||
|
|
||||||
|
/* global defineEmits */
|
||||||
|
const emits = defineEmits(["close"]);
|
||||||
|
const asyncProfilingStore = useAsyncProfilingStore();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const serviceInstanceIds = ref<string[]>([]);
|
||||||
|
const asyncEvents = ref<string[]>([]);
|
||||||
|
const duration = ref<string>(DurationOptions[0].value);
|
||||||
|
const execArgs = ref<string>("");
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const PartofEvents = [ProfilingEvents[3], ProfilingEvents[4], ProfilingEvents[5]];
|
||||||
|
|
||||||
|
function changeDuration(val: string) {
|
||||||
|
duration.value = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeInstances(options: { id: string }[]) {
|
||||||
|
serviceInstanceIds.value = options.map((d: { id: string }) => d.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableEvents(item: string) {
|
||||||
|
if (asyncEvents.value.includes(ProfilingEvents[0]) && PartofEvents.includes(item)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (item === ProfilingEvents[0]) {
|
||||||
|
for (const event of PartofEvents) {
|
||||||
|
if (asyncEvents.value.includes(event)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function createTask() {
|
||||||
|
const params = {
|
||||||
|
serviceId: selectorStore.currentService.id,
|
||||||
|
serviceInstanceIds: serviceInstanceIds.value,
|
||||||
|
duration: Number(duration.value) * 60,
|
||||||
|
events: asyncEvents.value,
|
||||||
|
execArgs: execArgs.value,
|
||||||
|
};
|
||||||
|
loading.value = true;
|
||||||
|
const res = await asyncProfilingStore.createTask(params);
|
||||||
|
loading.value = false;
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { errorReason } = res.data;
|
||||||
|
if (errorReason) {
|
||||||
|
ElMessage.error(errorReason);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emits("close");
|
||||||
|
ElMessage.success("Task created successfully");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.async-profile-task {
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date {
|
||||||
|
font-size: $font-size-smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
margin-top: 10px;
|
||||||
|
font-size: $font-size-normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-input {
|
||||||
|
width: 600px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-task-btn {
|
||||||
|
width: 600px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,259 @@
|
|||||||
|
<!-- 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-list flex-v" v-loading="asyncProfilingStore.loadingTasks">
|
||||||
|
<div class="profile-t-tool flex-h">{{ t("taskList") }}</div>
|
||||||
|
<div class="profile-t-wrapper">
|
||||||
|
<div class="no-data" v-show="!asyncProfilingStore.taskList.length">
|
||||||
|
{{ t("noData") }}
|
||||||
|
</div>
|
||||||
|
<table class="profile-t">
|
||||||
|
<tr
|
||||||
|
class="profile-tr cp"
|
||||||
|
v-for="(i, index) in asyncProfilingStore.taskList"
|
||||||
|
@click="changeTask(i)"
|
||||||
|
:key="index"
|
||||||
|
:class="{
|
||||||
|
selected: asyncProfilingStore.selectedTask.id === i.id,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<td class="profile-td">
|
||||||
|
<div class="ell">
|
||||||
|
<span>{{ i.id }}</span>
|
||||||
|
<a class="profile-btn r" @click="() => (showDetail = true)">
|
||||||
|
<Icon iconName="view" size="middle" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="grey ell sm">
|
||||||
|
<span class="mr-10 sm">
|
||||||
|
{{ dateFormat(i.createTime) }}
|
||||||
|
</span>
|
||||||
|
<span class="mr-10 sm">
|
||||||
|
{{ dateFormat(i.createTime + i.duration * 1000) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<el-dialog v-model="showDetail" :destroy-on-close="true" fullscreen @closed="showDetail = false">
|
||||||
|
<div class="profile-detail flex-v" v-if="asyncProfilingStore.selectedTask.id">
|
||||||
|
<div>
|
||||||
|
<h5 class="mb-10">{{ t("task") }}.</h5>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">ID:</span>
|
||||||
|
<span class="g-sm-8 wba">{{ asyncProfilingStore.selectedTask.id }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("service") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">{{ service }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("execArgs") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">{{ asyncProfilingStore.selectedTask.execArgs }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("duration") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">{{ asyncProfilingStore.selectedTask.duration / 60 }}min</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("events") }}:</span>
|
||||||
|
<span class="g-sm-8 wba"> {{ asyncProfilingStore.selectedTask.events.join(", ") }} </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h5
|
||||||
|
class="mb-5 mt-10"
|
||||||
|
v-show="asyncProfilingStore.selectedTask.logs && asyncProfilingStore.selectedTask.logs.length"
|
||||||
|
>
|
||||||
|
{{ t("logs") }}.
|
||||||
|
</h5>
|
||||||
|
<div v-for="(i, index) in Object.keys(instanceLogs)" :key="index">
|
||||||
|
<div class="sm">
|
||||||
|
<span class="mr-10 grey">{{ t("instance") }}:</span>
|
||||||
|
<span>{{ i }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-for="(d, index) in instanceLogs[i]" :key="index">
|
||||||
|
<span class="mr-10 grey">{{ t("operationType") }}:</span>
|
||||||
|
<span class="mr-20">{{ d.operationType }}</span>
|
||||||
|
<span class="mr-10 grey">{{ t("time") }}:</span>
|
||||||
|
<span>{{ dateFormat(d.operationTime) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h5 class="mb-10 mt-10" v-show="errorInstances.length"> {{ t("errorInstances") }}</h5>
|
||||||
|
<div v-for="(instance, index) in errorInstances" :key="instance.value || index">
|
||||||
|
<div class="mb-10 sm">
|
||||||
|
<span class="mr-10 grey">{{ t("instance") }}:</span>
|
||||||
|
<span>{{ instance.label }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-for="(d, index) in instance.attributes" :key="d.value + index">
|
||||||
|
<span class="mr-10 grey">{{ d.name }}:</span>
|
||||||
|
<span class="mr-20">{{ d.value }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h5 class="mb-10 mt-10" v-show="successInstances.length"> {{ t("successInstances") }}</h5>
|
||||||
|
<div v-for="(instance, index) in successInstances" :key="instance.value || index">
|
||||||
|
<div class="mb-10 sm">
|
||||||
|
<span class="mr-10 grey">{{ t("instance") }}:</span>
|
||||||
|
<span>{{ instance.label }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-for="(d, index) in instance.attributes" :key="d.value + index">
|
||||||
|
<span class="mr-10 grey">{{ d.name }}:</span>
|
||||||
|
<span class="mr-20">{{ d.value }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { useAsyncProfilingStore } from "@/store/modules/async-profiling";
|
||||||
|
import type { TaskLog, TaskListItem } from "@/types/profile";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { dateFormat } from "@/utils/dateFormat";
|
||||||
|
import type { Instance, Service } from "@/types/selector";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const asyncProfilingStore = useAsyncProfilingStore();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
const showDetail = ref<boolean>(false);
|
||||||
|
const service = ref<string>("");
|
||||||
|
const instanceLogs = ref<TaskLog | any>({});
|
||||||
|
const errorInstances = ref<Instance[]>([]);
|
||||||
|
const successInstances = ref<Instance[]>([]);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchTasks();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function fetchTasks() {
|
||||||
|
const res = await asyncProfilingStore.getTaskList();
|
||||||
|
if (res.errors) {
|
||||||
|
return ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
if (res.data.errorReason) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function changeTask(item: TaskListItem) {
|
||||||
|
if (item.id !== asyncProfilingStore.selectedTask.id) {
|
||||||
|
asyncProfilingStore.setAnalyzeTrees([]);
|
||||||
|
asyncProfilingStore.setSelectedTask(item);
|
||||||
|
}
|
||||||
|
service.value = (selectorStore.services.filter((s: Service) => s.id === item.serviceId)[0] ?? {}).label;
|
||||||
|
const res = await asyncProfilingStore.getTaskLogs({ taskId: item.id });
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
item = {
|
||||||
|
...item,
|
||||||
|
...asyncProfilingStore.taskProgress,
|
||||||
|
};
|
||||||
|
asyncProfilingStore.setSelectedTask(item);
|
||||||
|
errorInstances.value = asyncProfilingStore.instances.filter(
|
||||||
|
(d: Instance) => d.id && item.errorInstanceIds.includes(d.id),
|
||||||
|
);
|
||||||
|
successInstances.value = asyncProfilingStore.instances.filter(
|
||||||
|
(d: Instance) => d.id && item.successInstanceIds.includes(d.id),
|
||||||
|
);
|
||||||
|
instanceLogs.value = {};
|
||||||
|
for (const d of item.logs) {
|
||||||
|
if (instanceLogs.value[d.instanceName]) {
|
||||||
|
instanceLogs.value[d.instanceName].push({
|
||||||
|
operationType: d.operationType,
|
||||||
|
operationTime: d.operationTime,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
instanceLogs.value[d.instanceName] = [{ operationType: d.operationType, operationTime: d.operationTime }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-task-list {
|
||||||
|
width: 300px;
|
||||||
|
height: calc(100% - 20px);
|
||||||
|
overflow: auto;
|
||||||
|
border-right: 1px solid var(--sw-trace-list-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item span {
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-td {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-bottom: 1px solid var(--sw-trace-list-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected {
|
||||||
|
background-color: var(--sw-list-selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-data {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-t-wrapper {
|
||||||
|
overflow: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-t {
|
||||||
|
width: 100%;
|
||||||
|
border-spacing: 0;
|
||||||
|
table-layout: fixed;
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-tr {
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--sw-list-selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-segment {
|
||||||
|
border-top: 1px solid var(--sw-trace-list-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-t-tool {
|
||||||
|
padding: 5px 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-right: 1px solid var(--sw-trace-list-border);
|
||||||
|
border-bottom: 1px solid var(--sw-trace-list-border);
|
||||||
|
background-color: var(--sw-table-header);
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile-btn {
|
||||||
|
color: $font-color;
|
||||||
|
padding: 1px 3px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: $font-size-smaller;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
</style>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user