diff --git a/public/app/features/explore/TraceView/createSpanLink.test.ts b/public/app/features/explore/TraceView/createSpanLink.test.ts index eb98f159813..9ace5203e94 100644 --- a/public/app/features/explore/TraceView/createSpanLink.test.ts +++ b/public/app/features/explore/TraceView/createSpanLink.test.ts @@ -195,6 +195,25 @@ describe('createSpanLinkFactory', () => { )}` ); }); + + it('handles empty queries', () => { + const createLink = setupSpanLinkFactory({ + tags: [], + }); + expect(createLink).toBeDefined(); + const linkDef = createLink!( + createTraceSpan({ + process: { + serviceName: 'service', + tags: [ + { key: 'service.name', value: 'serviceName' }, + { key: 'k8s.pod.name', value: 'podName' }, + ], + }, + }) + ); + expect(linkDef).toBeUndefined(); + }); }); }); diff --git a/public/app/features/explore/TraceView/createSpanLink.tsx b/public/app/features/explore/TraceView/createSpanLink.tsx index 5170eb41236..5c74fecb728 100644 --- a/public/app/features/explore/TraceView/createSpanLink.tsx +++ b/public/app/features/explore/TraceView/createSpanLink.tsx @@ -75,12 +75,17 @@ function legacyCreateSpanLinkFactory(splitOpenFn: SplitOpen, traceToLogsOptions? return undefined; } - return function SpanLink(span: TraceSpan): SpanLinkDef { + return function SpanLink(span: TraceSpan): SpanLinkDef | undefined { // This is reusing existing code from derived fields which may not be ideal match so some data is a bit faked at // the moment. Issue is that the trace itself isn't clearly mapped to dataFrame (right now it's just a json blob // inside a single field) so the dataLinks as config of that dataFrame abstraction breaks down a bit and we do // it manually here instead of leaving it for the data source to supply the config. + const expr = getLokiQueryFromSpan(span, traceToLogsOptions); + if (!expr) { + return undefined; + } + const dataLink: DataLink = { title: dataSourceSettings.name, url: '', @@ -88,7 +93,7 @@ function legacyCreateSpanLinkFactory(splitOpenFn: SplitOpen, traceToLogsOptions? datasourceUid: dataSourceSettings.uid, datasourceName: dataSourceSettings.name, query: { - expr: getLokiQueryFromSpan(span, traceToLogsOptions), + expr, refId: '', }, }, @@ -122,7 +127,7 @@ function legacyCreateSpanLinkFactory(splitOpenFn: SplitOpen, traceToLogsOptions? */ const defaultKeys = ['cluster', 'hostname', 'namespace', 'pod']; -function getLokiQueryFromSpan(span: TraceSpan, options: TraceToLogsOptions): string { +function getLokiQueryFromSpan(span: TraceSpan, options: TraceToLogsOptions): string | undefined { const { tags: keys, filterByTraceID, filterBySpanID, mapTagNamesEnabled, mappedTags } = options; // In order, try to use mapped tags -> tags -> default tags @@ -143,6 +148,11 @@ function getLokiQueryFromSpan(span: TraceSpan, options: TraceToLogsOptions): str return acc; }, [] as string[]); + // If no tags found, return undefined to prevent an invalid Loki query + if (!tags.length) { + return undefined; + } + let query = `{${tags.join(', ')}}`; if (filterByTraceID && span.traceID) {