mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-07-18 14:45:25 +00:00
feat: add trace list
This commit is contained in:
parent
a15eabd67c
commit
d2cf41c7d1
@ -31,6 +31,7 @@ interface TraceState {
|
|||||||
traceTotal: number;
|
traceTotal: number;
|
||||||
traceSpans: Span[];
|
traceSpans: Span[];
|
||||||
currentTrace: Nullable<Trace>;
|
currentTrace: Nullable<Trace>;
|
||||||
|
conditions: any;
|
||||||
// traceSpanLogs: any[];
|
// traceSpanLogs: any[];
|
||||||
// traceSpanLogsTotal: number;
|
// traceSpanLogsTotal: number;
|
||||||
// traceListErrors: string;
|
// traceListErrors: string;
|
||||||
@ -49,10 +50,25 @@ export const traceStore = defineStore({
|
|||||||
traceSpans: [],
|
traceSpans: [],
|
||||||
traceTotal: 0,
|
traceTotal: 0,
|
||||||
currentTrace: null,
|
currentTrace: null,
|
||||||
|
conditions: {
|
||||||
|
queryDuration: useAppStoreWithOut().durationTime,
|
||||||
|
traceState: "ALL",
|
||||||
|
queryOrder: "BY_START_TIME",
|
||||||
|
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
||||||
|
},
|
||||||
durationTime: useAppStoreWithOut().durationTime,
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
selectorStore: useSelectorStore(),
|
selectorStore: useSelectorStore(),
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
|
setCondition(data: any) {
|
||||||
|
this.condition = data;
|
||||||
|
},
|
||||||
|
setCurrentTrace(trace: Trace) {
|
||||||
|
this.currentTrace = trace;
|
||||||
|
},
|
||||||
|
setTraceSpans(spans: Span) {
|
||||||
|
this.traceSpans = spans;
|
||||||
|
},
|
||||||
async getInstances() {
|
async getInstances() {
|
||||||
const res: AxiosResponse = await graphql
|
const res: AxiosResponse = await graphql
|
||||||
.query("queryServiceInstance")
|
.query("queryServiceInstance")
|
||||||
@ -61,7 +77,9 @@ export const traceStore = defineStore({
|
|||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.instances = res.data.data.pods || [];
|
this.instances = [{ value: 0, label: "All" }, ...res.data.data.pods] || [
|
||||||
|
{ value: 0, label: "All" },
|
||||||
|
];
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getEndpoints() {
|
async getEndpoints() {
|
||||||
@ -73,19 +91,30 @@ export const traceStore = defineStore({
|
|||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.endpoints = res.data.data.pods || [];
|
this.endpoints = [{ value: 0, label: "All" }, ...res.data.data.pods] || [
|
||||||
|
{ value: 0, label: "All" },
|
||||||
|
];
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getTraces(condition: any) {
|
async getTraces() {
|
||||||
const res: AxiosResponse = await graphql
|
const res: AxiosResponse = await graphql
|
||||||
.query("queryTraces")
|
.query("queryTraces")
|
||||||
.params({ condition });
|
.params({ condition: this.condition });
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.traceList = res.data.data.data.traces;
|
this.traceList = res.data.data.data.traces;
|
||||||
this.traceTotal = res.data.data.data.total;
|
this.traceTotal = res.data.data.data.total;
|
||||||
},
|
},
|
||||||
|
async getTraceSpans(params: any) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("queryTrace")
|
||||||
|
.params(params);
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.setTraceSpans(res.data.data.trace.spans || []);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,14 +13,19 @@ 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 class="header">
|
<div class="trace-list">
|
||||||
<Filter />
|
<div class="header">
|
||||||
|
<Filter />
|
||||||
|
</div>
|
||||||
|
<div class="content flex-h">
|
||||||
|
<TraceList />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">xxx</div>
|
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import Filter from "../related/trace/Filter.vue";
|
import Filter from "../related/trace/Filter.vue";
|
||||||
|
import TraceList from "../related/trace/TraceList.vue";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@ -32,6 +37,11 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
.trace-list {
|
||||||
|
height: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -208,3 +208,7 @@ export const Status = [
|
|||||||
{ label: "Success", value: "SUCCESS" },
|
{ label: "Success", value: "SUCCESS" },
|
||||||
{ label: "Error", value: "ERROR" },
|
{ label: "Error", value: "ERROR" },
|
||||||
];
|
];
|
||||||
|
export const QueryOrders = [
|
||||||
|
{ label: "startTime", value: "BY_START_TIME" },
|
||||||
|
{ label: "duration", value: "BY_DURATION" },
|
||||||
|
];
|
||||||
|
@ -66,7 +66,12 @@ limitations under the License. -->
|
|||||||
/>
|
/>
|
||||||
</div> -->
|
</div> -->
|
||||||
<ConditionTags :type="'TRACE'" @update="updateTags" />
|
<ConditionTags :type="'TRACE'" @update="updateTags" />
|
||||||
<el-button class="search-btn" size="small" type="primary">
|
<el-button
|
||||||
|
class="search-btn"
|
||||||
|
size="small"
|
||||||
|
type="primary"
|
||||||
|
@click="searchTraces"
|
||||||
|
>
|
||||||
{{ t("search") }}
|
{{ t("search") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</div>
|
||||||
@ -77,11 +82,14 @@ import { useI18n } from "vue-i18n";
|
|||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import { Status } from "../../data";
|
import { Status } from "../../data";
|
||||||
import { useTraceStore } from "@/store/modules/trace";
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import ConditionTags from "@/views/components/ConditionTags.vue";
|
import ConditionTags from "@/views/components/ConditionTags.vue";
|
||||||
// import type { PropType } from "vue";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
const traceStore = useTraceStore();
|
const traceStore = useTraceStore();
|
||||||
const traceId = ref<string>("");
|
const traceId = ref<string>("");
|
||||||
const minTraceDuration = ref<string>("");
|
const minTraceDuration = ref<string>("");
|
||||||
@ -89,7 +97,7 @@ const maxTraceDuration = ref<string>("");
|
|||||||
const tagsList = ref<string[]>([]);
|
const tagsList = ref<string[]>([]);
|
||||||
const tagsMap = ref<Option[]>([]);
|
const tagsMap = ref<Option[]>([]);
|
||||||
const state = reactive<any>({
|
const state = reactive<any>({
|
||||||
status: "",
|
status: "ALL",
|
||||||
instance: "",
|
instance: "",
|
||||||
endpoint: "",
|
endpoint: "",
|
||||||
});
|
});
|
||||||
@ -98,10 +106,29 @@ const state = reactive<any>({
|
|||||||
// appStore.durationRow.start,
|
// appStore.durationRow.start,
|
||||||
// appStore.durationRow.end,
|
// appStore.durationRow.end,
|
||||||
// ]);
|
// ]);
|
||||||
traceStore.getTraces({
|
searchTraces();
|
||||||
queryOrder: "DES",
|
function searchTraces() {
|
||||||
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
traceStore.setCondition({
|
||||||
});
|
serviceId: selectorStore.currentService.id || 0,
|
||||||
|
traceId: traceId.value || undefined,
|
||||||
|
endpointId: state.endpoint || undefined,
|
||||||
|
serviceInstanceId: state.instance || undefined,
|
||||||
|
traceState: state.status || "ALL",
|
||||||
|
queryDuration: appStore.durationTime,
|
||||||
|
minTraceDuration: appStore.minTraceDuration || undefined,
|
||||||
|
maxTraceDuration: appStore.maxTraceDuration || undefined,
|
||||||
|
queryOrder: "BY_DURATION",
|
||||||
|
tags: tagsMap.value.length ? tagsMap.value : undefined,
|
||||||
|
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
||||||
|
});
|
||||||
|
queryTraces();
|
||||||
|
}
|
||||||
|
async function queryTraces() {
|
||||||
|
const res = await traceStore.getTraces();
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
function changeField(type: string, opt: any[]) {
|
function changeField(type: string, opt: any[]) {
|
||||||
state[type] = opt[0].value;
|
state[type] = opt[0].value;
|
||||||
}
|
}
|
||||||
|
0
src/views/dashboard/related/trace/Graph.vue
Normal file
0
src/views/dashboard/related/trace/Graph.vue
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="trace-t flex-v">
|
||||||
|
<div class="trace-t-tool flex-h">
|
||||||
|
<el-pagination
|
||||||
|
v-model:currentPage="traceStore.conditions.paging.pageNum"
|
||||||
|
v-model:page-size="pageSize"
|
||||||
|
:small="true"
|
||||||
|
layout="prev, pager, next, jumper"
|
||||||
|
:total="traceStore.traceTotal"
|
||||||
|
@current-change="updatePage"
|
||||||
|
/>
|
||||||
|
<Selector
|
||||||
|
size="small"
|
||||||
|
v-model="traceStore.conditions.queryOrder"
|
||||||
|
:options="QueryOrders"
|
||||||
|
placeholder="Select a option"
|
||||||
|
@change="changeSort"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="trace-t-loading" v-loading="loading">
|
||||||
|
<Icon iconName="spinner" size="sm" />
|
||||||
|
</div>
|
||||||
|
<div class="trace-t-wrapper scroll_hide">
|
||||||
|
<table class="trace-t">
|
||||||
|
<tr
|
||||||
|
class="trace-tr cp"
|
||||||
|
v-for="(i, index) in traceStore.traceList"
|
||||||
|
@click="selectTrace(i)"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<td
|
||||||
|
class="trace-td"
|
||||||
|
:class="{
|
||||||
|
'trace-success': !i.isError,
|
||||||
|
'trace-error': i.isError,
|
||||||
|
selected: selectedKey == i.key,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="ell mb-5"
|
||||||
|
:class="{
|
||||||
|
blue: !i.isError,
|
||||||
|
red: i.isError,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span class="b">{{ i.endpointNames[0] }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="grey ell sm">
|
||||||
|
<span class="tag mr-10 sm">{{ i.duration }} ms</span
|
||||||
|
>{{ parseInt(i.start, 10) }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { QueryOrders } from "../../data";
|
||||||
|
import { Option } from "@/types/app";
|
||||||
|
import { Trace } from "@/types/trace";
|
||||||
|
|
||||||
|
const traceStore = useTraceStore();
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
const selectedKey = ref<string>("");
|
||||||
|
const pageSize = ref<number>(15);
|
||||||
|
|
||||||
|
function searchTrace() {
|
||||||
|
loading.value = true;
|
||||||
|
queryTraces();
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePage(p: number) {
|
||||||
|
traceStore.setCondition({
|
||||||
|
type: "paging",
|
||||||
|
data: { pageNum: p, pageSize: 15, needTotal: true },
|
||||||
|
});
|
||||||
|
searchTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeSort(opt: Option[]) {
|
||||||
|
traceStore.setCondition({
|
||||||
|
queryOrder: opt[0].value,
|
||||||
|
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
||||||
|
});
|
||||||
|
searchTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectTrace(i: Trace) {
|
||||||
|
this.setCurrentTrace(i);
|
||||||
|
selectedKey.value = i.key;
|
||||||
|
if (i.traceIds.length) {
|
||||||
|
traceStore.getTraceSpans({ traceId: i.traceIds[0] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function queryTraces() {
|
||||||
|
const res = await traceStore.getTraces();
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss">
|
||||||
|
.trace-t-tool {
|
||||||
|
flex-shrink: 0;
|
||||||
|
background-color: rgba(196, 200, 225, 0.2);
|
||||||
|
justify-content: space-between;
|
||||||
|
padding-right: 5px;
|
||||||
|
padding-top: 1px;
|
||||||
|
border-bottom: 1px solid #c1c5ca41;
|
||||||
|
border-right: 1px solid #c1c5ca41;
|
||||||
|
height: 35px;
|
||||||
|
|
||||||
|
select {
|
||||||
|
background-color: rgba(0, 0, 0, 0);
|
||||||
|
outline: 0;
|
||||||
|
border-style: unset;
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-t-wrapper {
|
||||||
|
overflow: auto;
|
||||||
|
flex-grow: 1;
|
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-t-loading {
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 70px;
|
||||||
|
margin-top: 40px;
|
||||||
|
line-height: 88px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-t {
|
||||||
|
width: 100%;
|
||||||
|
border-spacing: 0;
|
||||||
|
table-layout: fixed;
|
||||||
|
flex-grow: 1;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-tr {
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.04);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-td {
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
background-color: #ededed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-success {
|
||||||
|
border-left: 4px solid rgba(46, 47, 51, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-warning {
|
||||||
|
border-left: 4px solid #fbb03b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-error {
|
||||||
|
border-left: 4px solid #e54c17;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag {
|
||||||
|
border-radius: 4px;
|
||||||
|
padding-right: 5px;
|
||||||
|
padding-left: 5px;
|
||||||
|
background-color: #40454e;
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user