diff --git a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts index 8f4828073d0..bee794dec86 100644 --- a/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.ts +++ b/public/app/plugins/datasource/tempo/SearchTraceQLEditor/utils.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('|')}"`; diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts index 532e5835153..f66520555f5 100644 --- a/public/app/plugins/datasource/tempo/datasource.test.ts +++ b/public/app/plugins/datasource/tempo/datasource.test.ts @@ -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', ]); }); diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 968b59cd26b..6338cf58b98 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -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( diff --git a/public/app/plugins/datasource/tempo/language_provider.test.ts b/public/app/plugins/datasource/tempo/language_provider.test.ts index 4a8a8bb1b83..fb0c883a4ee 100644 --- a/public/app/plugins/datasource/tempo/language_provider.test.ts +++ b/public/app/plugins/datasource/tempo/language_provider.test.ts @@ -174,7 +174,7 @@ describe('Language_provider', () => { }, ], }) - ).toBe(`{name${operator}"api/v2/variants/by-upc/\\\\(\\\\?P\\\\[\\\\\\\\s\\\\\\\\S\\\\]\\\\*\\\\)/\\\\$"}`); + ).toBe(`{name${operator}"api/v2/variants/by-upc/\\\\(\\\\?P\\\\[\\\\s\\\\S\\\\]\\\\*\\\\)/\\\\$"}`); }); it('two fields with everything filled in', () => { expect(