diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 6338cf58b98..fc5f71eb8bb 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -782,6 +782,9 @@ export class TempoDatasource extends DataSourceWithBackend { + return enhanceTraceQlMetricsResponse(response, this.instanceSettings); + }), catchError((error) => { reportTempoQueryMetrics('grafana_traces_traceql_metrics_response', options, { success: false, diff --git a/public/app/plugins/datasource/tempo/resultTransformer.ts b/public/app/plugins/datasource/tempo/resultTransformer.ts index 49a7b0faa9e..01934cc97bf 100644 --- a/public/app/plugins/datasource/tempo/resultTransformer.ts +++ b/public/app/plugins/datasource/tempo/resultTransformer.ts @@ -1,6 +1,7 @@ import { SpanStatus } from '@opentelemetry/api'; import { collectorTypes } from '@opentelemetry/exporter-collector'; import { SemanticResourceAttributes } from '@opentelemetry/semantic-conventions'; +import { isEqual } from 'lodash'; import { createDataFrame, @@ -474,9 +475,20 @@ export function enhanceTraceQlMetricsResponse( const traceIDField = frame.fields.find((field: Field) => field.name === 'traceId'); if (traceIDField) { const links = getDataLinks(instanceSettings); - traceIDField.config.links = traceIDField.config.links?.length - ? [...traceIDField.config.links, ...links] - : links; + const existingLinks = traceIDField.config.links || []; + + // Filter out links that already exist + const newLinks = links.filter( + (link) => + !existingLinks.some( + (existing: DataLink) => + existing.title === link.title && + existing.internal?.datasourceUid === link.internal?.datasourceUid && + isEqual(existing.internal?.query, link.internal?.query) + ) + ); + + traceIDField.config.links = existingLinks.length ? [...existingLinks, ...newLinks] : newLinks; } return frame; });