From 1631e4130393a2ccea8159ac99e8ebf1d0a726a0 Mon Sep 17 00:00:00 2001 From: Joey <90795735+joey-grafana@users.noreply.github.com> Date: Fri, 23 Feb 2024 14:03:35 +0000 Subject: [PATCH] Tempo: Add template variable interpolation for filters (#83213) * Interpolate template variables in filters * Add tests --- .../datasource/tempo/datasource.test.ts | 29 ++++++++++++-- .../plugins/datasource/tempo/datasource.ts | 39 ++++++++++++++----- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts index ac8dc49f37b..0ed1d22114e 100644 --- a/public/app/plugins/datasource/tempo/datasource.test.ts +++ b/public/app/plugins/datasource/tempo/datasource.test.ts @@ -93,7 +93,24 @@ describe('Tempo data source', () => { minDuration: '$interpolationVar', maxDuration: '$interpolationVar', serviceMapQuery, - filters: [], + filters: [ + { + id: 'service-name', + operator: '=', + scope: TraceqlSearchScope.Resource, + tag: 'service.name', + value: '$interpolationVarWithPipe', + valueType: 'string', + }, + { + id: 'tagId', + operator: '=', + scope: TraceqlSearchScope.Span, + tag: '$interpolationVar', + value: '$interpolationVar', + valueType: 'string', + }, + ], }; } let templateSrv: TemplateSrv; @@ -110,7 +127,7 @@ describe('Tempo data source', () => { templateSrv = initTemplateSrv([{ name: 'templateVariable1' }, { name: 'templateVariable2' }], expectedValues); }); - it('when traceId query for dashboard->explore', async () => { + it('when moving from dashboard to explore', async () => { const expectedValues = { interpolationVar: 'interpolationText', interpolationText: 'interpolationText', @@ -129,9 +146,12 @@ describe('Tempo data source', () => { expect(queries[0].minDuration).toBe(text); expect(queries[0].maxDuration).toBe(text); expect(queries[0].serviceMapQuery).toBe(text); + expect(queries[0].filters[0].value).toBe(textWithPipe); + expect(queries[0].filters[1].value).toBe(text); + expect(queries[0].filters[1].tag).toBe(text); }); - it('when traceId query for template variable', async () => { + it('when applying template variables', async () => { const scopedText = 'scopedInterpolationText'; const ds = new TempoDatasource(defaultSettings, templateSrv); const resp = ds.applyTemplateVariables(getQuery(), { @@ -144,6 +164,9 @@ describe('Tempo data source', () => { expect(resp.search).toBe(scopedText); expect(resp.minDuration).toBe(scopedText); expect(resp.maxDuration).toBe(scopedText); + expect(resp.filters[0].value).toBe(textWithPipe); + expect(resp.filters[1].value).toBe(scopedText); + expect(resp.filters[1].tag).toBe(scopedText); }); it('when serviceMapQuery is an array', async () => { diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 398fd25f185..13d82d9abfc 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -377,9 +377,12 @@ export class TempoDatasource extends DataSourceWithBackend this.hasGroupBy(t)); - if (groupBy) { - subQueries.push(this.handleMetricsSummary(groupBy, generateQueryFromFilters(groupBy.filters), options)); + const target = targets.traceqlSearch.find((t) => this.hasGroupBy(t)); + if (target) { + const appliedQuery = this.applyVariables(target, options.scopedVars); + subQueries.push( + this.handleMetricsSummary(appliedQuery, generateQueryFromFilters(appliedQuery.filters), options) + ); } } @@ -387,25 +390,23 @@ export class TempoDatasource extends DataSourceWithBackend !this.hasGroupBy(t)) : targets.traceqlSearch; if (traceqlSearchTargets.length > 0) { - const queryValueFromFilters = generateQueryFromFilters(traceqlSearchTargets[0].filters); - - // We want to support template variables also in Search for consistency with other data sources - const queryValue = this.templateSrv.replace(queryValueFromFilters, options.scopedVars); + const appliedQuery = this.applyVariables(traceqlSearchTargets[0], options.scopedVars); + const queryValueFromFilters = generateQueryFromFilters(appliedQuery.filters); reportInteraction('grafana_traces_traceql_search_queried', { datasourceType: 'tempo', app: options.app ?? '', grafana_version: config.buildInfo.version, - query: queryValue ?? '', + query: queryValueFromFilters ?? '', streaming: config.featureToggles.traceQLStreaming, }); if (config.featureToggles.traceQLStreaming && this.isFeatureAvailable(FeatureName.streaming)) { - subQueries.push(this.handleStreamingSearch(options, traceqlSearchTargets, queryValue)); + subQueries.push(this.handleStreamingSearch(options, traceqlSearchTargets, queryValueFromFilters)); } else { subQueries.push( this._request('/api/search', { - q: queryValue, + q: queryValueFromFilters, limit: options.targets[0].limit ?? DEFAULT_LIMIT, spss: options.targets[0].spss ?? DEFAULT_SPSS, start: options.range.from.unix(), @@ -522,6 +523,24 @@ export class TempoDatasource extends DataSourceWithBackend { + const updatedFilter = { + ...filter, + tag: this.templateSrv.replace(filter.tag ?? '', scopedVars), + }; + + if (filter.value) { + updatedFilter.value = + typeof filter.value === 'string' + ? this.templateSrv.replace(filter.value ?? '', scopedVars, VariableFormatID.Pipe) + : filter.value.map((v) => this.templateSrv.replace(v ?? '', scopedVars, VariableFormatID.Pipe)); + } + + return updatedFilter; + }); + } + return { ...expandedQuery, query: this.templateSrv.replace(query.query ?? '', scopedVars, VariableFormatID.Pipe),