diff --git a/public/app/plugins/datasource/loki/datasource.test.ts b/public/app/plugins/datasource/loki/datasource.test.ts index 1e5158630aa..c650ba4e4e9 100644 --- a/public/app/plugins/datasource/loki/datasource.test.ts +++ b/public/app/plugins/datasource/loki/datasource.test.ts @@ -269,7 +269,7 @@ describe('LokiDatasource', () => { }, ]; expect(ds.applyTemplateVariables(query, {}, adhocFilters).expr).toBe( - 'rate({bar="baz", job="foo", k1=~"v.*", k2=~"v\\\\\'.*"} |= "bar" [5m])' + `rate({bar="baz", job="foo", k1=~"v.*", k2=~"v'.*"} |= "bar" [5m])` ); }); @@ -325,8 +325,15 @@ describe('LokiDatasource', () => { variable = {} as unknown as CustomVariableModel; }); - it('should only escape single quotes', () => { - expect(ds.interpolateQueryExpr("abc'$^*{}[]+?.()|", variable)).toEqual("abc\\\\'$^*{}[]+?.()|"); + it('should not escape', () => { + expect(ds.interpolateQueryExpr("abc'$^*{}[]+?.()|", variable)).toEqual("abc'$^*{}[]+?.()|"); + }); + + it('should not escape single quotes in line filters', () => { + expect(ds.interpolateQueryExpr("|= `abc'$^*{}[]+?.()|`", variable)).toEqual("|= `abc'$^*{}[]+?.()|`"); + expect(ds.interpolateQueryExpr("|~ `abc'$^*{}[]+?.()|`", variable)).toEqual("|~ `abc'$^*{}[]+?.()|`"); + expect(ds.interpolateQueryExpr("!= `abc'$^*{}[]+?.()|`", variable)).toEqual("!= `abc'$^*{}[]+?.()|`"); + expect(ds.interpolateQueryExpr("!~ `abc'$^*{}[]+?.()|`", variable)).toEqual("!~ `abc'$^*{}[]+?.()|`"); }); it('should return a number', () => { diff --git a/public/app/plugins/datasource/loki/datasource.ts b/public/app/plugins/datasource/loki/datasource.ts index 4a436dc4b87..ca87c5de46f 100644 --- a/public/app/plugins/datasource/loki/datasource.ts +++ b/public/app/plugins/datasource/loki/datasource.ts @@ -814,7 +814,7 @@ export class LokiDatasource interpolateQueryExpr(value: any, variable: QueryVariableModel | CustomVariableModel) { // if no multi or include all do not regexEscape if (!variable.multi && !variable.includeAll) { - return lokiRegularEscape(value); + return value; } if (typeof value === 'string') { @@ -1097,13 +1097,8 @@ export class LokiDatasource expr = adhocFilters.reduce((acc: string, filter: { key: string; operator: string; value: string }) => { const { key, operator } = filter; let { value } = filter; - if (isRegexSelector(operator)) { - // Adhoc filters don't support multiselect, therefore if user selects regex operator - // we are going to consider value to be regex filter and use lokiRegularEscape - // that does not escape regex special characters (e.g. .*test.* => .*test.*) - value = lokiRegularEscape(value); - } else { - // Otherwise, we want to escape special characters in value + if (!isRegexSelector(operator)) { + // We want to escape special characters in value for non-regex selectors to match the same char in the log line as the user types in the input value = escapeLabelValueInSelector(value, operator); } return addLabelToQuery(acc, key, operator, value); @@ -1207,20 +1202,9 @@ export class LokiDatasource }; } } - -// NOTE: these two functions are very similar to the escapeLabelValueIn* functions -// in language_utils.ts, but they are not exactly the same algorithm, and we found -// no way to reuse one in the another or vice versa. -export function lokiRegularEscape(value: T) { - if (typeof value === 'string') { - return value.replace(/'/g, "\\\\'"); - } - return value; -} - export function lokiSpecialRegexEscape(value: T) { if (typeof value === 'string') { - return lokiRegularEscape(value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()|]/g, '\\\\$&')); + return value.replace(/\\/g, '\\\\\\\\').replace(/[$^*{}\[\]+?.()|]/g, '\\\\$&'); } return value; }