From dd90ab5ea7bfe18901bc98d4fef28d4dfe705ea8 Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Sun, 28 Sep 2025 19:01:23 +0800 Subject: [PATCH] feat: adapt new trace protocol and implement new trace view (#499) --- src/assets/icons/download.svg | 17 + src/components/TimePicker.vue | 3 + src/graphql/fragments/trace.ts | 70 ++++ src/graphql/http/index.ts | 42 +- src/graphql/query/trace.ts | 14 +- src/layout/components/NavBar.vue | 6 +- src/layout/components/SideBar.vue | 2 +- src/locales/lang/en.ts | 8 +- src/locales/lang/es.ts | 6 + src/locales/lang/zh.ts | 6 + src/store/modules/trace.ts | 98 ++++- src/styles/lib.scss | 27 +- src/styles/theme.scss | 12 +- src/types/trace.ts | 7 + src/utils/color.ts | 70 ++++ src/utils/file.ts | 23 +- src/views/dashboard/List.vue | 4 +- src/views/dashboard/controls/Trace.vue | 140 +------ src/views/dashboard/data.ts | 2 +- .../related/async-profiling/Content.vue | 2 +- .../related/profile/components/SpanTree.vue | 4 +- src/views/dashboard/related/trace/Content.vue | 193 +++++++++ src/views/dashboard/related/trace/Index.vue | 30 +- .../trace/components/D3Graph/Index.vue | 389 ++++++------------ .../trace/components/D3Graph/SpanDetail.vue | 20 +- .../D3Graph}/utils/d3-trace-list.ts | 160 ++++--- .../D3Graph}/utils/d3-trace-tree.ts | 75 ++-- .../trace/components/D3Graph/utils/helper.ts | 281 +++++++++++++ .../D3Graph}/utils/trace-table.ts | 0 .../trace/components/Table/TableContainer.vue | 67 ++- .../trace/components/Table/TableItem.vue | 281 +++++++------ .../related/trace/components/Table/data.ts | 6 +- .../{ => components/TraceList}/Filter.vue | 135 +++--- .../TraceList/SearchBar.vue} | 2 +- .../TraceList/SegmentList.vue} | 6 +- .../TraceList/SpanList.vue} | 73 ++-- .../trace/components/TraceQuery/Index.vue | 47 +++ .../components/TraceQuery/MinTimeline.vue | 107 +++++ .../TraceQuery/MinTimelineMarker.vue | 57 +++ .../TraceQuery/MinTimelineOverlay.vue | 147 +++++++ .../TraceQuery/MinTimelineSelector.vue | 157 +++++++ .../trace/components/TraceQuery/SpanNode.vue | 120 ++++++ .../components/TraceQuery/TimelineTool.vue | 59 +++ .../components/TraceQuery/TraceContent.vue | 175 ++++++++ .../components/TraceQuery/TracesTable.vue | 379 +++++++++++++++++ .../trace/components/TraceQuery/useHooks.ts | 128 ++++++ .../trace/components/{ => VisGraph}/List.vue | 50 +-- .../components/{ => VisGraph}/Statistics.vue | 36 +- .../trace/components/{ => VisGraph}/Table.vue | 32 +- .../trace/components/{ => VisGraph}/Tree.vue | 45 +- .../components/{ => VisGraph}/constant.ts | 6 + .../trace/components/{ => VisGraph}/index.ts | 0 52 files changed, 2889 insertions(+), 937 deletions(-) create mode 100644 src/assets/icons/download.svg create mode 100644 src/utils/color.ts create mode 100644 src/views/dashboard/related/trace/Content.vue rename src/views/dashboard/related/trace/{ => components/D3Graph}/utils/d3-trace-list.ts (73%) rename src/views/dashboard/related/trace/{ => components/D3Graph}/utils/d3-trace-tree.ts (87%) create mode 100644 src/views/dashboard/related/trace/components/D3Graph/utils/helper.ts rename src/views/dashboard/related/trace/{ => components/D3Graph}/utils/trace-table.ts (100%) rename src/views/dashboard/related/trace/{ => components/TraceList}/Filter.vue (77%) rename src/views/dashboard/related/trace/{Header.vue => components/TraceList/SearchBar.vue} (99%) rename src/views/dashboard/related/trace/{TraceList.vue => components/TraceList/SegmentList.vue} (97%) rename src/views/dashboard/related/trace/{Detail.vue => components/TraceList/SpanList.vue} (78%) create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/Index.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/MinTimeline.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/MinTimelineMarker.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/MinTimelineOverlay.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/MinTimelineSelector.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/SpanNode.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/TimelineTool.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/TraceContent.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/TracesTable.vue create mode 100644 src/views/dashboard/related/trace/components/TraceQuery/useHooks.ts rename src/views/dashboard/related/trace/components/{ => VisGraph}/List.vue (73%) rename src/views/dashboard/related/trace/components/{ => VisGraph}/Statistics.vue (82%) rename src/views/dashboard/related/trace/components/{ => VisGraph}/Table.vue (65%) rename src/views/dashboard/related/trace/components/{ => VisGraph}/Tree.vue (76%) rename src/views/dashboard/related/trace/components/{ => VisGraph}/constant.ts (75%) rename src/views/dashboard/related/trace/components/{ => VisGraph}/index.ts (100%) diff --git a/src/assets/icons/download.svg b/src/assets/icons/download.svg new file mode 100644 index 00000000..6c138a32 --- /dev/null +++ b/src/assets/icons/download.svg @@ -0,0 +1,17 @@ + + + + \ No newline at end of file diff --git a/src/components/TimePicker.vue b/src/components/TimePicker.vue index 422d0644..c762e021 100755 --- a/src/components/TimePicker.vue +++ b/src/components/TimePicker.vue @@ -310,6 +310,9 @@ limitations under the License. --> break; } dates.value = [start, end]; + if (!props.showButtons) { + ok(true); + } }; const submit = () => { inputDates.value = dates.value; diff --git a/src/graphql/fragments/trace.ts b/src/graphql/fragments/trace.ts index 58c28f30..0aac354d 100644 --- a/src/graphql/fragments/trace.ts +++ b/src/graphql/fragments/trace.ts @@ -163,3 +163,73 @@ export const TraceSpansFromColdStage = { } `, }; +export const HasQueryTracesV2Support = { + query: ` + hasQueryTracesV2Support + `, +}; + +export const QueryV2Traces = { + variable: "$condition: TraceQueryCondition", + query: ` + queryTraces(condition: $condition) { + traces { + 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 + } + } + } + } + retrievedTimeRange { + startTime + endTime + } + }`, +}; diff --git a/src/graphql/http/index.ts b/src/graphql/http/index.ts index d9825404..f09f1241 100644 --- a/src/graphql/http/index.ts +++ b/src/graphql/http/index.ts @@ -17,11 +17,45 @@ import { httpQuery } from "../base"; import { HttpURL } from "./url"; -export default async function fetchQuery({ method, json, path }: { method: string; json?: unknown; path: string }) { +export default async function fetchQuery({ + method, + json, + path, +}: { + method: string; + json?: Record; + path: string; +}) { + const upperMethod = method.toUpperCase(); + let url = (HttpURL as Record)[path]; + let body: unknown | undefined = json; + + if (upperMethod === "GET" && json && typeof json === "object") { + const params = new URLSearchParams(); + const stringifyValue = (val: unknown): string => { + if (val instanceof Date) return val.toISOString(); + if (typeof val === "object") return JSON.stringify(val); + return String(val); + }; + for (const [key, value] of Object.entries(json)) { + if (value === undefined || value === null) continue; + if (Array.isArray(value)) { + for (const v of value as unknown[]) params.append(key, stringifyValue(v)); + continue; + } + params.append(key, stringifyValue(value)); + } + const queryString = params.toString(); + if (queryString) { + url += (url.includes("?") ? "&" : "?") + queryString; + } + body = undefined; + } + const response = await httpQuery({ - method, - json, - url: (HttpURL as { [key: string]: string })[path], + method: upperMethod, + json: body, + url, }); if (response.errors) { response.errors = response.errors.map((e: { message: string }) => e.message).join(" "); diff --git a/src/graphql/query/trace.ts b/src/graphql/query/trace.ts index 77b1dfe3..eac2bfdd 100644 --- a/src/graphql/query/trace.ts +++ b/src/graphql/query/trace.ts @@ -15,7 +15,15 @@ * limitations under the License. */ -import { Traces, TraceSpans, TraceTagKeys, TraceTagValues, TraceSpansFromColdStage } from "../fragments/trace"; +import { + Traces, + TraceSpans, + TraceTagKeys, + TraceTagValues, + TraceSpansFromColdStage, + HasQueryTracesV2Support, + QueryV2Traces, +} from "../fragments/trace"; export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`; @@ -26,3 +34,7 @@ export const queryTraceTagKeys = `query queryTraceTagKeys(${TraceTagKeys.variabl export const queryTraceTagValues = `query queryTraceTagValues(${TraceTagValues.variable}) {${TraceTagValues.query}}`; export const queryTraceSpansFromColdStage = `query queryTraceSpansFromColdStage(${TraceSpansFromColdStage.variable}) {${TraceSpansFromColdStage.query}}`; + +export const queryHasQueryTracesV2Support = `query queryHasQueryTracesV2Support {${HasQueryTracesV2Support.query}}`; + +export const queryV2Traces = `query queryV2Traces(${QueryV2Traces.variable}) {${QueryV2Traces.query}}`; diff --git a/src/layout/components/NavBar.vue b/src/layout/components/NavBar.vue index bf5710cb..7dc6ab75 100644 --- a/src/layout/components/NavBar.vue +++ b/src/layout/components/NavBar.vue @@ -89,6 +89,7 @@ limitations under the License. --> import router from "@/router"; import { useAppStoreWithOut, InitializationDurationRow } from "@/store/modules/app"; import { useDashboardStore } from "@/store/modules/dashboard"; + import { useTraceStore } from "@/store/modules/trace"; import type { DashboardItem } from "@/types/dashboard"; import timeFormat from "@/utils/timeFormat"; import { MetricCatalog } from "@/views/dashboard/data"; @@ -98,10 +99,10 @@ limitations under the License. --> import { useI18n } from "vue-i18n"; import { useRoute } from "vue-router"; - /*global Indexable */ const { t, te } = useI18n(); const appStore = useAppStoreWithOut(); const dashboardStore = useDashboardStore(); + const traceStore = useTraceStore(); const route = useRoute(); const pathNames = ref<{ path?: string; name: string; selected: boolean }[][]>([]); const showTimeRangeTips = ref(false); @@ -124,6 +125,7 @@ limitations under the License. --> getVersion(); getNavPaths(); setTTL(); + traceStore.getHasQueryTracesV2Support(); function changeTheme() { const root = document.documentElement; @@ -391,7 +393,7 @@ limitations under the License. --> } function resetDuration() { - const { duration }: Indexable = route.params; + const { duration } = route.params as { duration: string }; if (duration) { const d = JSON.parse(duration); diff --git a/src/layout/components/SideBar.vue b/src/layout/components/SideBar.vue index 955f847f..73b4c114 100644 --- a/src/layout/components/SideBar.vue +++ b/src/layout/components/SideBar.vue @@ -17,7 +17,7 @@ limitations under the License. -->
-