mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-06-17 10:27:34 +00:00
feat: support cold stage data for metrics, trace and log (#469)
This commit is contained in:
parent
0c2cfa5630
commit
a28972bc5c
@ -169,12 +169,13 @@ limitations under the License. -->
|
||||
value: { type: Date },
|
||||
left: { type: Boolean, default: false },
|
||||
right: { type: Boolean, default: false },
|
||||
dates: { type: Array as PropType<number[] | string[]>, default: () => [] },
|
||||
dates: { type: Array as PropType<Date[]>, default: () => [] },
|
||||
disabledDate: { type: Function, default: () => false },
|
||||
format: {
|
||||
type: String,
|
||||
default: "YYYY-MM-DD",
|
||||
},
|
||||
maxRange: { type: Array as PropType<Date[]>, default: () => [] },
|
||||
});
|
||||
const state = reactive({
|
||||
pre: "",
|
||||
@ -241,6 +242,12 @@ limitations under the License. -->
|
||||
const end = computed(() => {
|
||||
return parse(Number(props.dates[1]));
|
||||
});
|
||||
const minStart = computed(() => {
|
||||
return parse(Number(props.maxRange[0]));
|
||||
});
|
||||
const maxEnd = computed(() => {
|
||||
return parse(Number(props.maxRange[1]));
|
||||
});
|
||||
const ys = computed(() => {
|
||||
return Math.floor(state.year / 10) * 10;
|
||||
});
|
||||
@ -369,7 +376,10 @@ limitations under the License. -->
|
||||
flag = tf(props.value, format) === tf(time, format);
|
||||
}
|
||||
classObj[`${state.pre}-date`] = true;
|
||||
classObj[`${state.pre}-date-disabled`] = (props.right && t < start.value) || props.disabledDate(time, format);
|
||||
const rightDisabled = props.right && (t < start.value || t > maxEnd.value || !props.maxRange?.length);
|
||||
const leftDisabled =
|
||||
props.left && (t < minStart.value || t > end.value || !props.maxRange?.length || t > maxEnd.value);
|
||||
classObj[`${state.pre}-date-disabled`] = rightDisabled || leftDisabled || props.disabledDate(time, format);
|
||||
classObj[`${state.pre}-date-on`] = (props.left && t > start.value) || (props.right && t < end.value);
|
||||
classObj[`${state.pre}-date-selected`] = flag;
|
||||
return classObj;
|
||||
|
@ -68,6 +68,7 @@ limitations under the License. -->
|
||||
:left="true"
|
||||
:disabledDate="disabledDate"
|
||||
:format="format"
|
||||
:maxRange="maxRange"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
@ -78,6 +79,7 @@ limitations under the License. -->
|
||||
:right="true"
|
||||
:disabledDate="disabledDate"
|
||||
:format="format"
|
||||
:maxRange="maxRange"
|
||||
@ok="ok"
|
||||
@setDates="setDates"
|
||||
/>
|
||||
@ -112,11 +114,11 @@ limitations under the License. -->
|
||||
import { useI18n } from "vue-i18n";
|
||||
import DateCalendar from "./DateCalendar.vue";
|
||||
import { useTimeoutFn } from "@/hooks/useTimeout";
|
||||
/*global defineProps, defineEmits*/
|
||||
/*global PropType, defineProps, defineEmits*/
|
||||
const datepicker = ref(null);
|
||||
const { t } = useI18n();
|
||||
const show = ref<boolean>(false);
|
||||
const dates = ref<Date | string[] | any>([]);
|
||||
const dates = ref<Date[]>([]);
|
||||
const props = defineProps({
|
||||
position: { type: String, default: "bottom" },
|
||||
name: [String],
|
||||
@ -149,7 +151,7 @@ limitations under the License. -->
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dateRangeSelect: [Function],
|
||||
maxRange: { type: Array as PropType<Date[]>, default: () => [] },
|
||||
});
|
||||
const emit = defineEmits(["clear", "input", "confirm", "cancel"]);
|
||||
const local = computed(() => {
|
||||
|
@ -49,3 +49,22 @@ export const MenuItems = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const RecordsTTL = {
|
||||
query: `getRecordsTTL {
|
||||
value
|
||||
superDataset
|
||||
coldValue
|
||||
coldSuperDataset
|
||||
}`,
|
||||
};
|
||||
export const MetricsTTL = {
|
||||
query: `getMetricsTTL {
|
||||
minute
|
||||
hour
|
||||
day
|
||||
coldMinute
|
||||
coldHour
|
||||
coldDay
|
||||
}`,
|
||||
};
|
||||
|
@ -103,3 +103,63 @@ export const TraceTagValues = {
|
||||
query: `
|
||||
tagValues: queryTraceTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
|
||||
};
|
||||
|
||||
export const TraceSpansFromColdStage = {
|
||||
variable: "$traceId: ID!, $duration: Duration!, $debug: Boolean",
|
||||
query: `
|
||||
trace: queryTrace(traceId: $traceId, duration: $duration, debug: $debug) {
|
||||
spans {
|
||||
traceId
|
||||
segmentId
|
||||
spanId
|
||||
parentSpanId
|
||||
refs {
|
||||
traceId
|
||||
parentSegmentId
|
||||
parentSpanId
|
||||
type
|
||||
}
|
||||
serviceCode
|
||||
serviceInstanceName
|
||||
startTime
|
||||
endTime
|
||||
endpointName
|
||||
type
|
||||
peer
|
||||
component
|
||||
isError
|
||||
layer
|
||||
tags {
|
||||
key
|
||||
value
|
||||
}
|
||||
logs {
|
||||
time
|
||||
data {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
attachedEvents {
|
||||
startTime {
|
||||
seconds
|
||||
nanos
|
||||
}
|
||||
event
|
||||
endTime {
|
||||
seconds
|
||||
nanos
|
||||
}
|
||||
tags {
|
||||
key
|
||||
value
|
||||
}
|
||||
summary {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@ -14,10 +14,14 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { OAPTimeInfo, OAPVersion, MenuItems } from "../fragments/app";
|
||||
import { OAPTimeInfo, OAPVersion, MenuItems, MetricsTTL, RecordsTTL } from "../fragments/app";
|
||||
|
||||
export const queryOAPTimeInfo = `query queryOAPTimeInfo {${OAPTimeInfo.query}}`;
|
||||
|
||||
export const queryOAPVersion = `query ${OAPVersion.query}`;
|
||||
|
||||
export const queryMenuItems = `query menuItems {${MenuItems.query}}`;
|
||||
|
||||
export const queryMetricsTTL = `query MetricsTTL {${MetricsTTL.query}}`;
|
||||
|
||||
export const queryRecordsTTL = `query RecordsTTL {${RecordsTTL.query}}`;
|
||||
|
@ -15,12 +15,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Traces, TraceSpans, TraceTagKeys, TraceTagValues } from "../fragments/trace";
|
||||
import { Traces, TraceSpans, TraceTagKeys, TraceTagValues, TraceSpansFromColdStage } from "../fragments/trace";
|
||||
|
||||
export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`;
|
||||
|
||||
export const queryTrace = `query queryTrace(${TraceSpans.variable}) {${TraceSpans.query}}`;
|
||||
export const querySpans = `query querySpans(${TraceSpans.variable}) {${TraceSpans.query}}`;
|
||||
|
||||
export const queryTraceTagKeys = `query queryTraceTagKeys(${TraceTagKeys.variable}) {${TraceTagKeys.query}}`;
|
||||
|
||||
export const queryTraceTagValues = `query queryTraceTagValues(${TraceTagValues.variable}) {${TraceTagValues.query}}`;
|
||||
|
||||
export const queryTraceSpansFromColdStage = `query queryTraceSpansFromColdStage(${TraceSpansFromColdStage.variable}) {${TraceSpansFromColdStage.query}}`;
|
||||
|
55
src/hooks/useDuration.ts
Normal file
55
src/hooks/useDuration.ts
Normal file
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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 { useAppStoreWithOut, InitializationDurationRow } from "@/store/modules/app";
|
||||
import type { Duration, DurationTime } from "@/types/app";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
import dateFormatStep from "@/utils/dateFormat";
|
||||
|
||||
export function useDuration() {
|
||||
let durationRow: Duration = InitializationDurationRow;
|
||||
|
||||
function getDuration() {
|
||||
const appStore = useAppStoreWithOut();
|
||||
return {
|
||||
start: getLocalTime(appStore.utc, durationRow.start),
|
||||
end: getLocalTime(appStore.utc, durationRow.end),
|
||||
step: durationRow.step,
|
||||
};
|
||||
}
|
||||
function getDurationTime(): DurationTime {
|
||||
const { start, step, end } = getDuration();
|
||||
return {
|
||||
start: dateFormatStep(start, step, true),
|
||||
end: dateFormatStep(end, step, true),
|
||||
step: step,
|
||||
};
|
||||
}
|
||||
function setDurationRow(data: Duration) {
|
||||
durationRow = data;
|
||||
}
|
||||
function getMaxRange(day: number) {
|
||||
if (day === -1) {
|
||||
return [];
|
||||
}
|
||||
const gap = (day + 1) * 24 * 60 * 60 * 1000;
|
||||
const dates: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
||||
|
||||
return dates;
|
||||
}
|
||||
|
||||
return { setDurationRow, getDurationTime, getMaxRange };
|
||||
}
|
@ -40,14 +40,25 @@ limitations under the License. -->
|
||||
</el-breadcrumb>
|
||||
<div class="title" v-else>{{ pageTitle }}</div>
|
||||
<div class="app-config">
|
||||
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
||||
<span class="red" v-show="showTimeRangeTips">{{ t("timeTips") }}</span>
|
||||
<TimePicker
|
||||
:value="[appStore.durationRow.start, appStore.durationRow.end]"
|
||||
:maxRange="appStore.maxRange"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeTimeRange"
|
||||
/>
|
||||
<span> UTC{{ appStore.utcHour >= 0 ? "+" : "" }}{{ `${appStore.utcHour}:${appStore.utcMin}` }} </span>
|
||||
<span class="ml-5">
|
||||
<el-switch
|
||||
v-model="coldStage"
|
||||
inline-prompt
|
||||
active-text="Active Data"
|
||||
inactive-text="Cold Data"
|
||||
@change="changeDataMode"
|
||||
width="90px"
|
||||
/>
|
||||
</span>
|
||||
<span class="ml-5" ref="themeSwitchRef">
|
||||
<el-switch
|
||||
v-model="theme"
|
||||
@ -75,7 +86,7 @@ limitations under the License. -->
|
||||
<script lang="ts" setup>
|
||||
import { Themes } from "@/constants/data";
|
||||
import router from "@/router";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useAppStoreWithOut, InitializationDurationRow } from "@/store/modules/app";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import type { DashboardItem } from "@/types/dashboard";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
@ -92,10 +103,11 @@ limitations under the License. -->
|
||||
const dashboardStore = useDashboardStore();
|
||||
const route = useRoute();
|
||||
const pathNames = ref<{ path?: string; name: string; selected: boolean }[][]>([]);
|
||||
const timeRange = ref<number>(0);
|
||||
const showTimeRangeTips = ref<boolean>(false);
|
||||
const pageTitle = ref<string>("");
|
||||
const theme = ref<boolean>(true);
|
||||
const themeSwitchRef = ref<HTMLElement>();
|
||||
const coldStage = ref<boolean>(false);
|
||||
|
||||
const savedTheme = window.localStorage.getItem("theme-is-dark");
|
||||
if (savedTheme === "false") {
|
||||
@ -110,6 +122,7 @@ limitations under the License. -->
|
||||
resetDuration();
|
||||
getVersion();
|
||||
getNavPaths();
|
||||
setTTL();
|
||||
|
||||
function changeTheme() {
|
||||
const root = document.documentElement;
|
||||
@ -126,6 +139,24 @@ limitations under the License. -->
|
||||
window.localStorage.setItem("theme-is-dark", String(theme.value));
|
||||
}
|
||||
|
||||
function changeDataMode() {
|
||||
appStore.setColdStageMode(coldStage.value);
|
||||
if (coldStage.value) {
|
||||
handleMetricsTTL({
|
||||
minute: appStore.metricsTTL.coldMinute,
|
||||
hour: appStore.metricsTTL.coldHour,
|
||||
day: appStore.metricsTTL.coldDay,
|
||||
});
|
||||
} else {
|
||||
handleMetricsTTL({
|
||||
minute: appStore.metricsTTL.minute,
|
||||
hour: appStore.metricsTTL.hour,
|
||||
day: appStore.metricsTTL.day,
|
||||
});
|
||||
}
|
||||
appStore.setDuration(InitializationDurationRow);
|
||||
}
|
||||
|
||||
function handleChangeTheme() {
|
||||
const x = themeSwitchRef.value?.offsetLeft ?? 0;
|
||||
const y = themeSwitchRef.value?.offsetTop ?? 0;
|
||||
@ -184,13 +215,48 @@ limitations under the License. -->
|
||||
}
|
||||
|
||||
function changeTimeRange(val: Date[]) {
|
||||
timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||
if (timeRange.value) {
|
||||
showTimeRangeTips.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000;
|
||||
if (showTimeRangeTips.value) {
|
||||
return;
|
||||
}
|
||||
appStore.setDuration(timeFormat(val));
|
||||
}
|
||||
|
||||
function setTTL() {
|
||||
getMetricsTTL();
|
||||
getRecordsTTL();
|
||||
changeDataMode();
|
||||
}
|
||||
async function getRecordsTTL() {
|
||||
const resp = await appStore.queryRecordsTTL();
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
}
|
||||
}
|
||||
|
||||
async function getMetricsTTL() {
|
||||
const resp = await appStore.queryMetricsTTL();
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
}
|
||||
}
|
||||
|
||||
function handleMetricsTTL({ minute, hour, day }: { minute: number; hour: number; day: number }) {
|
||||
if (minute === -1 || hour === -1 || day === -1) {
|
||||
return appStore.setMaxRange([]);
|
||||
}
|
||||
if (!day) {
|
||||
return appStore.setMaxRange([]);
|
||||
}
|
||||
const gap = Math.max(day, hour, minute);
|
||||
const dates: Date[] = [new Date(new Date().getTime() - dayToMS(gap + 1)), new Date()];
|
||||
appStore.setMaxRange(dates);
|
||||
}
|
||||
|
||||
function dayToMS(day: number) {
|
||||
return day * 24 * 60 * 60 * 1000;
|
||||
}
|
||||
|
||||
function getNavPaths() {
|
||||
pathNames.value = [];
|
||||
pageTitle.value = "";
|
||||
|
@ -21,11 +21,11 @@ import type { Duration, DurationTime } from "@/types/app";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
||||
import { TimeType } from "@/constants/data";
|
||||
import type { MenuOptions, SubItem } from "@/types/app";
|
||||
import type { MenuOptions, SubItem, MetricsTTL, RecordsTTL } from "@/types/app";
|
||||
import { Themes } from "@/constants/data";
|
||||
/*global Nullable*/
|
||||
interface AppState {
|
||||
durationRow: Recordable;
|
||||
durationRow: Duration;
|
||||
utc: string;
|
||||
utcHour: number;
|
||||
utcMin: number;
|
||||
@ -37,16 +37,22 @@ interface AppState {
|
||||
reloadTimer: Nullable<IntervalHandle>;
|
||||
allMenus: MenuOptions[];
|
||||
theme: string;
|
||||
coldStageMode: boolean;
|
||||
maxRange: Date[];
|
||||
metricsTTL: Recordable<MetricsTTL>;
|
||||
recordsTTL: Recordable<RecordsTTL>;
|
||||
}
|
||||
|
||||
export const InitializationDurationRow = {
|
||||
start: new Date(new Date().getTime() - 1800000),
|
||||
end: new Date(),
|
||||
step: TimeType.MINUTE_TIME,
|
||||
};
|
||||
|
||||
export const appStore = defineStore({
|
||||
id: "app",
|
||||
state: (): AppState => ({
|
||||
durationRow: {
|
||||
start: new Date(new Date().getTime() - 1800000),
|
||||
end: new Date(),
|
||||
step: TimeType.MINUTE_TIME,
|
||||
},
|
||||
durationRow: InitializationDurationRow,
|
||||
utc: "",
|
||||
utcHour: 0,
|
||||
utcMin: 0,
|
||||
@ -58,6 +64,10 @@ export const appStore = defineStore({
|
||||
reloadTimer: null,
|
||||
allMenus: [],
|
||||
theme: Themes.Dark,
|
||||
coldStageMode: false,
|
||||
maxRange: [],
|
||||
metricsTTL: {},
|
||||
recordsTTL: {},
|
||||
}),
|
||||
getters: {
|
||||
duration(): Duration {
|
||||
@ -122,6 +132,9 @@ export const appStore = defineStore({
|
||||
updateDurationRow(data: Duration) {
|
||||
this.durationRow = data;
|
||||
},
|
||||
setMaxRange(times: Date[]) {
|
||||
this.maxRange = times;
|
||||
},
|
||||
setTheme(data: string) {
|
||||
this.theme = data;
|
||||
},
|
||||
@ -143,6 +156,9 @@ export const appStore = defineStore({
|
||||
setAutoRefresh(auto: boolean) {
|
||||
this.autoRefresh = auto;
|
||||
},
|
||||
setColdStageMode(mode: boolean) {
|
||||
this.coldStageMode = mode;
|
||||
},
|
||||
runEventStack() {
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
@ -206,6 +222,22 @@ export const appStore = defineStore({
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async queryMetricsTTL() {
|
||||
const res = await graphql.query("queryMetricsTTL").params({});
|
||||
if (res.errors) {
|
||||
return res;
|
||||
}
|
||||
this.metricsTTL = res.data.getMetricsTTL;
|
||||
return res.data;
|
||||
},
|
||||
async queryRecordsTTL() {
|
||||
const res = await graphql.query("queryRecordsTTL").params({});
|
||||
if (res.errors) {
|
||||
return res;
|
||||
}
|
||||
this.recordsTTL = res.data.getRecordsTTL;
|
||||
return res.data;
|
||||
},
|
||||
setReloadTimer(timer: IntervalHandle) {
|
||||
this.reloadTimer = timer;
|
||||
},
|
||||
|
@ -21,6 +21,7 @@ import graphql from "@/graphql";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useDuration } from "@/hooks/useDuration";
|
||||
import { EndpointsTopNDefault } from "../data";
|
||||
|
||||
interface LogState {
|
||||
@ -33,6 +34,7 @@ interface LogState {
|
||||
logs: Recordable[];
|
||||
loadLogs: boolean;
|
||||
}
|
||||
const { getDurationTime } = useDuration();
|
||||
|
||||
export const logStore = defineStore({
|
||||
id: "log",
|
||||
@ -41,7 +43,7 @@ export const logStore = defineStore({
|
||||
instances: [{ value: "0", label: "All" }],
|
||||
endpoints: [{ value: "0", label: "All" }],
|
||||
conditions: {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
queryDuration: getDurationTime(),
|
||||
paging: { pageNum: 1, pageSize: 15 },
|
||||
},
|
||||
supportQueryLogsByKeywords: true,
|
||||
@ -56,7 +58,7 @@ export const logStore = defineStore({
|
||||
resetState() {
|
||||
this.logs = [];
|
||||
this.conditions = {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
queryDuration: getDurationTime(),
|
||||
paging: { pageNum: 1, pageSize: 15 },
|
||||
};
|
||||
},
|
||||
|
@ -23,6 +23,7 @@ import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { QueryOrders } from "@/views/dashboard/data";
|
||||
import { EndpointsTopNDefault } from "../data";
|
||||
import { useDuration } from "@/hooks/useDuration";
|
||||
interface TraceState {
|
||||
services: Service[];
|
||||
instances: Instance[];
|
||||
@ -35,6 +36,7 @@ interface TraceState {
|
||||
selectorStore: Recordable;
|
||||
selectedSpan: Recordable<Span>;
|
||||
}
|
||||
const { getDurationTime } = useDuration();
|
||||
|
||||
export const traceStore = defineStore({
|
||||
id: "trace",
|
||||
@ -47,7 +49,7 @@ export const traceStore = defineStore({
|
||||
currentTrace: {},
|
||||
selectedSpan: {},
|
||||
conditions: {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
queryDuration: getDurationTime(),
|
||||
traceState: "ALL",
|
||||
queryOrder: QueryOrders[0].value,
|
||||
paging: { pageNum: 1, pageSize: 20 },
|
||||
@ -73,7 +75,7 @@ export const traceStore = defineStore({
|
||||
this.traceList = [];
|
||||
this.currentTrace = {};
|
||||
this.conditions = {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
queryDuration: getDurationTime(),
|
||||
paging: { pageNum: 1, pageSize: 20 },
|
||||
traceState: "ALL",
|
||||
queryOrder: QueryOrders[0].value,
|
||||
@ -166,7 +168,15 @@ export const traceStore = defineStore({
|
||||
return response;
|
||||
},
|
||||
async getTraceSpans(params: { traceId: string }) {
|
||||
const response = await graphql.query("queryTrace").params(params);
|
||||
const appStore = useAppStoreWithOut();
|
||||
let response;
|
||||
if (appStore.coldStageMode) {
|
||||
response = await graphql
|
||||
.query("queryTraceSpansFromColdStage")
|
||||
.params({ ...params, duration: this.conditions.queryDuration });
|
||||
} else {
|
||||
response = await graphql.query("querySpans").params(params);
|
||||
}
|
||||
if (response.errors) {
|
||||
return response;
|
||||
}
|
||||
|
16
src/types/app.d.ts
vendored
16
src/types/app.d.ts
vendored
@ -68,3 +68,19 @@ export interface SubItem {
|
||||
descKey: string;
|
||||
i18nKey: string;
|
||||
}
|
||||
|
||||
export interface MetricsTTL {
|
||||
minute: number;
|
||||
hour: number;
|
||||
day: number;
|
||||
coldMinute: number;
|
||||
coldHour: number;
|
||||
coldDay: number;
|
||||
}
|
||||
|
||||
export interface RecordsTTL {
|
||||
value: number;
|
||||
superDataset: number;
|
||||
coldValue: number;
|
||||
coldSuperDataset: number;
|
||||
}
|
||||
|
5
src/types/dashboard.d.ts
vendored
5
src/types/dashboard.d.ts
vendored
@ -60,10 +60,7 @@ export type Filters = {
|
||||
dataIndex: number;
|
||||
sourceId: string;
|
||||
isRange?: boolean;
|
||||
duration?: {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
};
|
||||
duration?: DurationTime;
|
||||
traceId?: string;
|
||||
spanId?: string;
|
||||
segmentId?: string;
|
||||
|
@ -30,6 +30,16 @@ limitations under the License. -->
|
||||
<span class="grey">{{ t("searchKeyword") }}: </span>
|
||||
<el-input size="small" v-model="keyword" class="alarm-tool-input" @change="refreshAlarms({ pageNum: 1 })" />
|
||||
</div>
|
||||
<div>
|
||||
<span class="sm b grey mr-5">{{ t("timeRange") }}:</span>
|
||||
<TimePicker
|
||||
:value="[durationRow.start, durationRow.end]"
|
||||
:maxRange="maxRange"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeDuration"
|
||||
/>
|
||||
</div>
|
||||
<div class="pagination">
|
||||
<el-pagination
|
||||
v-model="pageNum"
|
||||
@ -51,31 +61,40 @@ limitations under the License. -->
|
||||
</nav>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from "vue";
|
||||
import { ref, computed, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ElMessage } from "element-plus";
|
||||
import ConditionTags from "@/views/components/ConditionTags.vue";
|
||||
import { AlarmOptions } from "./data";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useAppStoreWithOut, InitializationDurationRow } from "@/store/modules/app";
|
||||
import { useAlarmStore } from "@/store/modules/alarm";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDuration } from "@/hooks/useDuration";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import type { DurationTime, Duration } from "@/types/app";
|
||||
import { Themes } from "@/constants/data";
|
||||
|
||||
/*global Recordable */
|
||||
const appStore = useAppStoreWithOut();
|
||||
const alarmStore = useAlarmStore();
|
||||
const { t } = useI18n();
|
||||
const { setDurationRow, getDurationTime, getMaxRange } = useDuration();
|
||||
const pageSize = 20;
|
||||
const entity = ref<string>("");
|
||||
const keyword = ref<string>("");
|
||||
const pageNum = ref<number>(1);
|
||||
const duration = ref<DurationTime>(getDurationTime());
|
||||
const durationRow = ref<Duration>(InitializationDurationRow);
|
||||
const total = computed(() =>
|
||||
alarmStore.alarms.length === pageSize ? pageSize * pageNum.value + 1 : pageSize * pageNum.value,
|
||||
);
|
||||
const maxRange = computed(() =>
|
||||
getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldValue : appStore.recordsTTL.value),
|
||||
);
|
||||
|
||||
refreshAlarms({ pageNum: 1 });
|
||||
|
||||
async function refreshAlarms(param: { pageNum: number; tagsMap?: any }) {
|
||||
const params: any = {
|
||||
duration: appStore.durationTime,
|
||||
async function refreshAlarms(param: { pageNum: number; tagsMap?: Recordable }) {
|
||||
const params: Recordable = {
|
||||
duration: duration.value,
|
||||
paging: {
|
||||
pageNum: param.pageNum,
|
||||
pageSize,
|
||||
@ -91,7 +110,14 @@ limitations under the License. -->
|
||||
}
|
||||
}
|
||||
|
||||
function changeEntity(param: any) {
|
||||
function changeDuration(val: Date[]) {
|
||||
durationRow.value = timeFormat(val);
|
||||
setDurationRow(durationRow.value);
|
||||
duration.value = getDurationTime();
|
||||
refreshAlarms({ pageNum: 1 });
|
||||
}
|
||||
|
||||
function changeEntity(param: { value: string }[]) {
|
||||
entity.value = param[0].value;
|
||||
refreshAlarms({ pageNum: 1 });
|
||||
}
|
||||
@ -100,6 +126,16 @@ limitations under the License. -->
|
||||
pageNum.value = p;
|
||||
refreshAlarms({ pageNum: p });
|
||||
}
|
||||
|
||||
watch(
|
||||
() => appStore.coldStageMode,
|
||||
() => {
|
||||
durationRow.value = InitializationDurationRow;
|
||||
setDurationRow(durationRow.value);
|
||||
duration.value = getDurationTime();
|
||||
refreshAlarms({ pageNum: 1 });
|
||||
},
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.alarm-tool {
|
||||
|
@ -56,6 +56,16 @@ limitations under the License. -->
|
||||
@change="changeField('category', $event)"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<span class="sm b grey mr-5">{{ t("timeRange") }}:</span>
|
||||
<TimePicker
|
||||
:value="[durationRow.start, durationRow.end]"
|
||||
:maxRange="maxRange"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeDuration"
|
||||
/>
|
||||
</div>
|
||||
<el-button class="search-btn" size="small" type="primary" @click="searchLogs">
|
||||
{{ t("search") }}
|
||||
</el-button>
|
||||
@ -119,20 +129,21 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch, onUnmounted } from "vue";
|
||||
import { ref, reactive, watch, onUnmounted, computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import type { Option } from "@/types/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useLogStore } from "@/store/modules/log";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useAppStoreWithOut, InitializationDurationRow } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useDuration } from "@/hooks/useDuration";
|
||||
import ConditionTags from "@/views/components/ConditionTags.vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import { EntityType } from "../../data";
|
||||
import { ErrorCategory } from "./data";
|
||||
import type { LayoutConfig } from "@/types/dashboard";
|
||||
import type { DurationTime } from "@/types/app";
|
||||
import type { Option, DurationTime, Duration } from "@/types/app";
|
||||
|
||||
/*global defineProps, Recordable */
|
||||
const props = defineProps({
|
||||
@ -147,8 +158,9 @@ limitations under the License. -->
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const logStore = useLogStore();
|
||||
const { setDurationRow, getDurationTime, getMaxRange } = useDuration();
|
||||
const traceId = ref<string>((props.data.filters && props.data.filters.traceId) || "");
|
||||
const duration = ref<DurationTime>((props.data.filters && props.data.filters.duration) || appStore.durationTime);
|
||||
const duration = ref<DurationTime>((props.data.filters && props.data.filters.duration) || getDurationTime());
|
||||
const keywordsOfContent = ref<string[]>([]);
|
||||
const excludingKeywordsOfContent = ref<string[]>([]);
|
||||
const tagsList = ref<string[]>([]);
|
||||
@ -156,12 +168,16 @@ limitations under the License. -->
|
||||
const contentStr = ref<string>("");
|
||||
const excludingContentStr = ref<string>("");
|
||||
const isBrowser = ref<boolean>(dashboardStore.layerId === "BROWSER");
|
||||
const durationRow = ref<Duration>(InitializationDurationRow);
|
||||
const state = reactive<Recordable>({
|
||||
instance: { value: "0", label: "All" },
|
||||
endpoint: { value: "0", label: "All" },
|
||||
service: { value: "", label: "" },
|
||||
category: { value: "ALL", label: "All" },
|
||||
});
|
||||
const maxRange = computed(() =>
|
||||
getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldSuperDataset : appStore.recordsTTL.superDataset),
|
||||
);
|
||||
if (props.needQuery) {
|
||||
init();
|
||||
}
|
||||
@ -275,6 +291,11 @@ limitations under the License. -->
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
function changeDuration(val: Date[]) {
|
||||
durationRow.value = timeFormat(val);
|
||||
setDurationRow(durationRow.value);
|
||||
duration.value = getDurationTime();
|
||||
}
|
||||
function changeField(type: string, opt: any) {
|
||||
state[type] = opt[0];
|
||||
if (type === "service") {
|
||||
@ -352,12 +373,12 @@ limitations under the License. -->
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => appStore.coldStageMode,
|
||||
() => {
|
||||
duration.value = appStore.durationTime;
|
||||
if (dashboardStore.entity === EntityType[1].value) {
|
||||
init();
|
||||
}
|
||||
durationRow.value = InitializationDurationRow;
|
||||
setDurationRow(durationRow.value);
|
||||
duration.value = getDurationTime();
|
||||
init();
|
||||
},
|
||||
);
|
||||
watch(
|
||||
@ -368,7 +389,7 @@ limitations under the License. -->
|
||||
return;
|
||||
}
|
||||
traceId.value = props.data.filters.traceId || "";
|
||||
duration.value = props.data.filters.duration || appStore.durationTime;
|
||||
duration.value = props.data.filters.duration || getDurationTime();
|
||||
init();
|
||||
}
|
||||
},
|
||||
|
@ -71,24 +71,36 @@ limitations under the License. -->
|
||||
<span class="grey mr-5">-</span>
|
||||
<el-input size="small" class="inputs" v-model="maxTraceDuration" type="number" />
|
||||
</div>
|
||||
<div>
|
||||
<span class="sm b grey mr-5">{{ t("timeRange") }}:</span>
|
||||
<TimePicker
|
||||
:value="[durationRow.start, durationRow.end]"
|
||||
:maxRange="maxRange"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeDuration"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-h">
|
||||
<ConditionTags :type="'TRACE'" @update="updateTags" />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch, onUnmounted } from "vue";
|
||||
import { ref, reactive, watch, onUnmounted, computed } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import type { Option, DurationTime } from "@/types/app";
|
||||
import type { Option, DurationTime, Duration } from "@/types/app";
|
||||
import { useTraceStore } from "@/store/modules/trace";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useAppStoreWithOut, InitializationDurationRow } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import ConditionTags from "@/views/components/ConditionTags.vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { EntityType, QueryOrders, Status } from "../../data";
|
||||
import type { LayoutConfig } from "@/types/dashboard";
|
||||
import { useDuration } from "@/hooks/useDuration";
|
||||
|
||||
/*global defineProps, defineEmits, Recordable */
|
||||
const emits = defineEmits(["get", "search"]);
|
||||
@ -99,14 +111,15 @@ limitations under the License. -->
|
||||
default: () => ({ graph: {} }),
|
||||
},
|
||||
});
|
||||
const filters = reactive<Recordable>(props.data.filters || {});
|
||||
const traceId = ref<string>(filters.traceId || "");
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const traceStore = useTraceStore();
|
||||
const duration = ref<DurationTime>(filters.duration || appStore.durationTime);
|
||||
const { setDurationRow, getDurationTime, getMaxRange } = useDuration();
|
||||
const filters = reactive<Recordable>(props.data.filters || {});
|
||||
const traceId = ref<string>(filters.traceId || "");
|
||||
const duration = ref<DurationTime>(filters.duration || getDurationTime());
|
||||
const minTraceDuration = ref<number>();
|
||||
const maxTraceDuration = ref<number>();
|
||||
const tagsList = ref<string[]>([]);
|
||||
@ -117,6 +130,10 @@ limitations under the License. -->
|
||||
endpoint: { value: "0", label: "All" },
|
||||
service: { value: "", label: "" },
|
||||
});
|
||||
const durationRow = ref<Duration>(InitializationDurationRow);
|
||||
const maxRange = computed(() =>
|
||||
getMaxRange(appStore.coldStageMode ? appStore.recordsTTL.coldSuperDataset : appStore.recordsTTL.superDataset),
|
||||
);
|
||||
if (filters.queryOrder) {
|
||||
traceStore.setTraceCondition({
|
||||
queryOrder: filters.queryOrder,
|
||||
@ -255,6 +272,11 @@ limitations under the License. -->
|
||||
ElMessage.error(resp.errors);
|
||||
}
|
||||
}
|
||||
function changeDuration(val: Date[]) {
|
||||
durationRow.value = timeFormat(val);
|
||||
setDurationRow(durationRow.value);
|
||||
duration.value = getDurationTime();
|
||||
}
|
||||
onUnmounted(() => {
|
||||
traceStore.resetState();
|
||||
const config = props.data;
|
||||
@ -280,12 +302,12 @@ limitations under the License. -->
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => appStore.coldStageMode,
|
||||
() => {
|
||||
duration.value = appStore.durationTime;
|
||||
if (dashboardStore.entity === EntityType[1].value) {
|
||||
init();
|
||||
}
|
||||
durationRow.value = InitializationDurationRow;
|
||||
setDurationRow(durationRow.value);
|
||||
duration.value = getDurationTime();
|
||||
init();
|
||||
},
|
||||
);
|
||||
// Event widget associate with trace widget
|
||||
@ -299,7 +321,7 @@ limitations under the License. -->
|
||||
return;
|
||||
}
|
||||
traceId.value = props.data.filters.traceId || "";
|
||||
duration.value = props.data.filters.duration || appStore.durationTime;
|
||||
duration.value = props.data.filters.duration || getDurationTime();
|
||||
init();
|
||||
},
|
||||
);
|
||||
|
@ -31,6 +31,12 @@ limitations under the License. -->
|
||||
@change="changeLatency"
|
||||
class="ml-10"
|
||||
/>
|
||||
<TimePicker
|
||||
:value="[appStore.durationRow.start, appStore.durationRow.end]"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeTimeRange"
|
||||
/>
|
||||
<el-popover trigger="hover" width="250" placement="bottom">
|
||||
<template #reference>
|
||||
<div class="cp conditions-popup">
|
||||
@ -82,6 +88,7 @@ limitations under the License. -->
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import ConditionTags from "@/views/components/ConditionTags.vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { EntityType, QueryOrders, Status } from "../../data";
|
||||
@ -107,6 +114,7 @@ limitations under the License. -->
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const traceStore = useTraceStore();
|
||||
const timeRange = ref<number>(NaN);
|
||||
const tagsList = ref<string[]>([]);
|
||||
const tagsMap = ref<Option[]>([]);
|
||||
const traceId = ref<string>(filters.refId || "");
|
||||
@ -169,6 +177,15 @@ limitations under the License. -->
|
||||
}
|
||||
await queryTraces();
|
||||
}
|
||||
|
||||
function changeTimeRange(val: Date[]) {
|
||||
timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||
if (timeRange.value) {
|
||||
return;
|
||||
}
|
||||
appStore.setDuration(timeFormat(val));
|
||||
}
|
||||
|
||||
function changeCondition() {
|
||||
if (conditions.value === "latency") {
|
||||
currentLatency.value = filters.latency ? filters.latency[0].data : [];
|
||||
|
Loading…
Reference in New Issue
Block a user