From 8ac74e24df1ff9e5de0c1d0f78dcd8be12305b4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Falksk=C3=A4r?= <457523+edvard-falkskar@users.noreply.github.com> Date: Sat, 2 Aug 2025 16:13:02 +0200 Subject: [PATCH] TraceView: Add span attributes to attributes extension point (#107756) --- .../src/types/pluginExtensions.ts | 1 + .../TraceTimelineViewer/SpanDetail/index.tsx | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/grafana-data/src/types/pluginExtensions.ts b/packages/grafana-data/src/types/pluginExtensions.ts index 32764409a8d..488eced154a 100644 --- a/packages/grafana-data/src/types/pluginExtensions.ts +++ b/packages/grafana-data/src/types/pluginExtensions.ts @@ -250,6 +250,7 @@ export type PluginExtensionCommandPaletteContext = {}; export type PluginExtensionResourceAttributesContext = { // Key-value pairs of resource attributes, attribute name is the key attributes: Record; + spanAttributes?: Record; datasource: { type: string; uid: string; diff --git a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx index 627e8fc2ec4..99575f7badc 100644 --- a/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx +++ b/public/app/features/explore/TraceView/components/TraceTimelineViewer/SpanDetail/index.tsx @@ -51,7 +51,12 @@ import { ShareSpanButton } from './ShareSpanButton'; import { getSpanDetailLinkButtons } from './SpanDetailLinkButtons'; import SpanFlameGraph from './SpanFlameGraph'; -const useResourceAttributesExtensionLinks = (process: TraceProcess, datasourceType: string, datasourceUid: string) => { +const useResourceAttributesExtensionLinks = ( + process: TraceProcess, + spanTags: TraceKeyValuePair[], + datasourceType: string, + datasourceUid: string +) => { // Stable context for useMemo inside usePluginLinks const context: PluginExtensionResourceAttributesContext = useMemo(() => { const attributes = (process.tags ?? []).reduce>((acc, tag) => { @@ -63,14 +68,24 @@ const useResourceAttributesExtensionLinks = (process: TraceProcess, datasourceTy return acc; }, {}); + const spanAttributes = (spanTags ?? []).reduce>((acc, tag) => { + if (acc[tag.key]) { + acc[tag.key].push(tag.value); + } else { + acc[tag.key] = [tag.value]; + } + return acc; + }, {}); + return { attributes, + spanAttributes, datasource: { type: datasourceType, uid: datasourceUid, }, }; - }, [process.tags, datasourceType, datasourceUid]); + }, [process.tags, spanTags, datasourceType, datasourceUid]); const { links } = usePluginLinks({ extensionPointId: PluginExtensionPoints.TraceViewResourceAttributes, @@ -328,7 +343,7 @@ export default function SpanDetail(props: SpanDetailProps) { }); const focusSpanLink = createFocusSpanLink(traceID, spanID); - const resourceLinksGetter = useResourceAttributesExtensionLinks(process, datasourceType, datasourceUid); + const resourceLinksGetter = useResourceAttributesExtensionLinks(process, tags, datasourceType, datasourceUid); return (
@@ -348,6 +363,7 @@ export default function SpanDetail(props: SpanDetailProps) { data={tags} label={t('explore.span-detail.label-span-attributes', 'Span attributes')} isOpen={isTagsOpen} + linksGetter={resourceLinksGetter} onToggle={() => tagsToggle(spanID)} /> {process.tags && (