From d1df0727e7b581a8e98190abfd9c8c7c7d51699f Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Thu, 24 Jun 2021 06:55:25 -0400 Subject: [PATCH] Loki: Fix highlight of logs when using filter expressions with backticks (#36024) * Add highlight for backticks and queries with parser * Fix escaping for backticks and quotes --- .../datasource/loki/query_utils.test.ts | 36 +++++++++++++++++-- .../plugins/datasource/loki/query_utils.ts | 22 ++++++++---- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/public/app/plugins/datasource/loki/query_utils.test.ts b/public/app/plugins/datasource/loki/query_utils.test.ts index 396bf46a37a..d69692462f6 100644 --- a/public/app/plugins/datasource/loki/query_utils.test.ts +++ b/public/app/plugins/datasource/loki/query_utils.test.ts @@ -5,18 +5,42 @@ describe('getHighlighterExpressionsFromQuery', () => { expect(getHighlighterExpressionsFromQuery('')).toEqual([]); }); - it('returns an expression for query with filter', () => { + it('returns an expression for query with filter using quotes', () => { expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= "x"')).toEqual(['x']); }); + it('returns an expression for query with filter using backticks', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= `x`')).toEqual(['x']); + }); + it('returns expressions for query with filter chain', () => { expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= "x" |~ "y"')).toEqual(['x', 'y']); }); - it('returns drops expressions for query with negative filter chain', () => { + it('returns expressions for query with filter chain using both backticks and quotes', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= "x" |~ `y`')).toEqual(['x', 'y']); + }); + + it('returns expression for query with log parser', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= "x" | logfmt')).toEqual(['x']); + }); + + it('returns expressions for query with filter chain folowed by log parser', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= "x" |~ "y" | logfmt')).toEqual(['x', 'y']); + }); + + it('returns drops expressions for query with negative filter chain using quotes', () => { expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= "x" != "y"')).toEqual(['x']); }); + it('returns expressions for query with filter chain using backticks', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= `x` |~ `y`')).toEqual(['x', 'y']); + }); + + it('returns expressions for query with filter chain using quotes and backticks', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= "x" |~ `y`')).toEqual(['x', 'y']); + }); + it('returns null if filter term is not wrapped in double quotes', () => { expect(getHighlighterExpressionsFromQuery('{foo="bar"} |= x')).toEqual([]); }); @@ -28,4 +52,12 @@ describe('getHighlighterExpressionsFromQuery', () => { it('does not escape filter term if regex filter operator is used', () => { expect(getHighlighterExpressionsFromQuery('{foo="bar"} |~ "x[yz].w" |~ "z.+"')).toEqual(['x[yz].w', 'z.+']); }); + + it('removes extra backslash escaping if regex filter operator and quotes are used', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |~ "\\\\w+"')).toEqual(['\\w+']); + }); + + it('does not remove backslash escaping if regex filter operator and backticks are used', () => { + expect(getHighlighterExpressionsFromQuery('{foo="bar"} |~ `\\w+`')).toEqual(['\\w+']); + }); }); diff --git a/public/app/plugins/datasource/loki/query_utils.ts b/public/app/plugins/datasource/loki/query_utils.ts index e8dd3353469..7c2d2244c93 100644 --- a/public/app/plugins/datasource/loki/query_utils.ts +++ b/public/app/plugins/datasource/loki/query_utils.ts @@ -37,15 +37,25 @@ export function getHighlighterExpressionsFromQuery(input: string): string[] { expression = expression.substr(filterEnd); } - // Unwrap the filter term by removing quotes - const quotedTerm = filterTerm.match(/^"((?:[^\\"]|\\")*)"$/); + const quotedTerm = filterTerm.match(/"(.*?)"/); + const backtickedTerm = filterTerm.match(/`(.*?)`/); + const term = quotedTerm || backtickedTerm; - if (quotedTerm) { - const unwrappedFilterTerm = quotedTerm[1]; + if (term) { + const unwrappedFilterTerm = term[1]; const regexOperator = filterOperator === '|~'; - results.push(regexOperator ? unwrappedFilterTerm : escapeRegExp(unwrappedFilterTerm)); + + // Only filter expressions with |~ operator are treated as regular expressions + if (regexOperator) { + // When using backticks, Loki doesn't require to escape special characters and we can just push regular expression to highlights array + // When using quotes, we have extra backslash escaping and we need to replace \\ with \ + results.push(backtickedTerm ? unwrappedFilterTerm : unwrappedFilterTerm.replace(/\\\\/g, '\\')); + } else { + // We need to escape this string so it is not matched as regular expression + results.push(escapeRegExp(unwrappedFilterTerm)); + } } else { - return []; + return results; } }