Tempo: Send current filters when retrieving tags for AdHocFilters (#88270)

* Send current filters when retrieving tags

* Tests

* Syntax update

* Update if
This commit is contained in:
Joey 2024-06-04 13:20:06 +01:00 committed by GitHub
parent 66bc0fa9e9
commit a52f99246f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 55 additions and 6 deletions

View File

@ -2,7 +2,14 @@ import { uniq } from 'lodash';
import { TraceqlSearchScope } from '../dataquery.gen';
import { generateQueryFromFilters, getUnscopedTags, getFilteredTags, getAllTags, getTagsByScope } from './utils';
import {
generateQueryFromFilters,
getUnscopedTags,
getFilteredTags,
getAllTags,
getTagsByScope,
generateQueryFromAdHocFilters,
} from './utils';
describe('generateQueryFromFilters generates the correct query for', () => {
it('an empty array', () => {
@ -129,6 +136,31 @@ describe('generateQueryFromFilters generates the correct query for', () => {
});
});
describe('generateQueryFromAdHocFilters generates the correct query for', () => {
it('an empty array', () => {
expect(generateQueryFromAdHocFilters([])).toBe('{}');
});
it('a filter with values', () => {
expect(generateQueryFromAdHocFilters([{ key: 'footag', operator: '=', value: 'foovalue' }])).toBe(
'{footag="foovalue"}'
);
});
it('two filters with values', () => {
expect(
generateQueryFromAdHocFilters([
{ key: 'footag', operator: '=', value: 'foovalue' },
{ key: 'bartag', operator: '=', value: 'barvalue' },
])
).toBe('{footag="foovalue" && bartag="barvalue"}');
});
it('a filter with intrinsic values', () => {
expect(generateQueryFromAdHocFilters([{ key: 'kind', operator: '=', value: 'server' }])).toBe('{kind=server}');
});
});
describe('gets correct tags', () => {
it('for filtered tags when no tags supplied', () => {
const tags = getFilteredTags(emptyTags, []);

View File

@ -1,6 +1,6 @@
import { startCase, uniq } from 'lodash';
import { SelectableValue } from '@grafana/data';
import { AdHocVariableFilter, SelectableValue } from '@grafana/data';
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
import { intrinsics } from '../traceql/traceql';
@ -22,6 +22,7 @@ const valueHelper = (f: TraceqlFilter) => {
}
return f.value;
};
const scopeHelper = (f: TraceqlFilter) => {
// Intrinsic fields don't have a scope
if (intrinsics.find((t) => t === f.tag)) {
@ -31,6 +32,7 @@ const scopeHelper = (f: TraceqlFilter) => {
(f.scope === TraceqlSearchScope.Resource || f.scope === TraceqlSearchScope.Span ? f.scope?.toLowerCase() : '') + '.'
);
};
const tagHelper = (f: TraceqlFilter, filters: TraceqlFilter[]) => {
if (f.tag === 'duration') {
const durationType = filters.find((f) => f.id === 'duration-type');
@ -42,6 +44,20 @@ const tagHelper = (f: TraceqlFilter, filters: TraceqlFilter[]) => {
return f.tag;
};
export const generateQueryFromAdHocFilters = (filters: AdHocVariableFilter[]) => {
return `{${filters
.filter((f) => f.key && f.operator && f.value)
.map((f) => `${f.key}${f.operator}${adHocValueHelper(f)}`)
.join(' && ')}}`;
};
const adHocValueHelper = (f: AdHocVariableFilter) => {
if (intrinsics.find((t) => t === f.key)) {
return f.value;
}
return `"${f.value}"`;
};
export const filterScopedTag = (f: TraceqlFilter) => {
return scopeHelper(f) + f.tag;
};

View File

@ -34,7 +34,7 @@ import {
} from '@grafana/runtime';
import { BarGaugeDisplayMode, TableCellDisplayMode, VariableFormatID } from '@grafana/schema';
import { generateQueryFromFilters } from './SearchTraceQLEditor/utils';
import { generateQueryFromAdHocFilters, generateQueryFromFilters } from './SearchTraceQLEditor/utils';
import { TempoVariableQuery, TempoVariableQueryType } from './VariableQueryEditor';
import { PrometheusDatasource, PromQuery } from './_importedDependencies/datasources/prometheus/types';
import { TraceqlFilter, TraceqlSearchScope } from './dataquery.gen';
@ -170,7 +170,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
return tags.filter((tag) => tag !== undefined).map((tag) => ({ text: tag }));
}
async labelValuesQuery(labelName?: string): Promise<Array<{ text: string }>> {
async labelValuesQuery(labelName?: string, query?: string): Promise<Array<{ text: string }>> {
if (!labelName) {
return [];
}
@ -192,7 +192,7 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
// For V2, we need to send scope and tag name, e.g. `span.http.status_code`,
// unless the tag has intrinsic scope
const scopeAndTag = scope === 'intrinsic' ? labelName : `${scope}.${labelName}`;
options = await this.languageProvider.getOptionsV2(scopeAndTag);
options = await this.languageProvider.getOptionsV2(scopeAndTag, query);
} catch {
// For V1, the tag name (e.g. `http.status_code`) is enough
options = await this.languageProvider.getOptionsV1(labelName);
@ -217,7 +217,8 @@ export class TempoDatasource extends DataSourceWithBackend<TempoQuery, TempoJson
// Allows to retrieve the list of tag values for ad-hoc filters
getTagValues(options: DataSourceGetTagValuesOptions<TempoQuery>): Promise<Array<{ text: string }>> {
return this.labelValuesQuery(options.key.replace(/^(resource|span)\./, ''));
const query = generateQueryFromAdHocFilters(options.filters);
return this.labelValuesQuery(options.key.replace(/^(resource|span)\./, ''), query);
}
init = async () => {