Tempo: Properly escape double quotes in TraceQL query (#106909)

* Properly escape double quotes

* Simplify regex
pull/103755/head
Joey 2 days ago committed by GitHub
parent 3503fc209e
commit 1f7cfda03c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 15
      public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts
  2. 7
      public/app/plugins/datasource/tempo/datasource.test.ts
  3. 10
      public/app/plugins/datasource/tempo/datasource.ts
  4. 2
      public/app/plugins/datasource/tempo/language_provider.test.ts

@ -5,7 +5,7 @@ import { getTemplateSrv } from '@grafana/runtime';
import { VariableFormatID } from '@grafana/schema';
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
import { getEscapedSpanNames } from '../datasource';
import { getEscapedRegexValues, getEscapedValues } from '../datasource';
import TempoLanguageProvider from '../language_provider';
import { intrinsics } from '../traceql/traceql';
import { Scope } from '../types';
@ -32,11 +32,16 @@ export const interpolateFilters = (filters: TraceqlFilter[], scopedVars?: Scoped
const isRegExpOperator = (operator: string) => operator === '=~' || operator === '!~';
const escapeValues = (values: string[]) => getEscapedSpanNames(values);
export const valueHelper = (f: TraceqlFilter) => {
const value =
Array.isArray(f.value) && isRegExpOperator(f.operator!) && !f.isCustomValue ? escapeValues(f.value) : f.value;
let value = f.value;
if (Array.isArray(value) && !f.isCustomValue) {
value = getEscapedValues(value);
if (isRegExpOperator(f.operator!)) {
value = getEscapedRegexValues(value);
}
}
if (Array.isArray(value) && value.length > 1) {
return `"${value.join('|')}"`;

@ -41,7 +41,8 @@ import {
makeServiceGraphViewRequest,
makeTempoLink,
getFieldConfig,
getEscapedSpanNames,
getEscapedRegexValues,
getEscapedValues,
makeHistogramLink,
makePromServiceMapRequest,
} from './datasource';
@ -778,12 +779,12 @@ describe('Tempo service graph view', () => {
'server.cluster.local:9090^/sample.test(.*)?',
'test\\path',
];
let escaped = getEscapedSpanNames(spanNames);
let escaped = getEscapedRegexValues(getEscapedValues(spanNames));
expect(escaped).toEqual([
'/actuator/health/\\\\*\\\\*',
'\\\\$type \\\\+ \\\\[test\\\\]\\\\|HTTP POST - post',
'server\\\\.cluster\\\\.local:9090\\\\^/sample\\\\.test\\\\(\\\\.\\\\*\\\\)\\\\?',
'test\\\\\\\\path',
'test\\\\path',
]);
});

@ -1081,7 +1081,7 @@ function errorAndDurationQuery(
}
});
}
const spanNames = getEscapedSpanNames(labels);
const spanNames = getEscapedRegexValues(getEscapedValues(labels));
if (spanNames.length > 0) {
errorRateBySpanName = buildExpr(errorRateMetric, 'span_name=~"' + spanNames.join('|') + '"', request);
@ -1151,8 +1151,12 @@ function makePromLink(title: string, expr: string, datasourceUid: string, instan
// TODO: this is basically the same as prometheus/datasource.ts#prometheusSpecialRegexEscape which is used to escape
// template variable values. It would be best to move it to some common place.
export function getEscapedSpanNames(values: string[]) {
return values.map((value: string) => value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]\'+?.()|]/g, '\\\\$&'));
export function getEscapedRegexValues(values: string[]) {
return values.map((value: string) => value.replace(/[$^*{}\[\]\'+?.()|]/g, '\\\\$&'));
}
export function getEscapedValues(values: string[]) {
return values.map((value: string) => value.replace(/["\\]/g, '\\$&'));
}
export function getFieldConfig(

@ -174,7 +174,7 @@ describe('Language_provider', () => {
},
],
})
).toBe(`{name${operator}"api/v2/variants/by-upc/\\\\(\\\\?P<upc>\\\\[\\\\\\\\s\\\\\\\\S\\\\]\\\\*\\\\)/\\\\$"}`);
).toBe(`{name${operator}"api/v2/variants/by-upc/\\\\(\\\\?P<upc>\\\\[\\\\s\\\\S\\\\]\\\\*\\\\)/\\\\$"}`);
});
it('two fields with everything filled in', () => {
expect(

Loading…
Cancel
Save