From c95eda4b3557f02fa6dfc3473461501080849dc3 Mon Sep 17 00:00:00 2001 From: Joey <90795735+joey-grafana@users.noreply.github.com> Date: Fri, 12 May 2023 10:30:17 +0100 Subject: [PATCH] [v9.5.x] Tempo: Escape regex-sensitive characters in span name before building promql query (#68318) * Tempo: Escape regex-sensitive characters in span name before building promql query (#66301) * Tempo: escape regex-sensitive characters in span name before building promql query * Make gen-cue * Add type * Add tests * Test * Minor update --------- Co-authored-by: Joey Tawadrous (cherry picked from commit 8b1afb594dc375c1c7ac5ba39304f42eaf66586b) * Changelog prettier --------- Co-authored-by: gordeevnm --- .../plugins/datasource/tempo/datasource.test.ts | 15 +++++++++++++++ public/app/plugins/datasource/tempo/datasource.ts | 6 +++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/tempo/datasource.test.ts b/public/app/plugins/datasource/tempo/datasource.test.ts index f55f93e9696..179bd6c5e70 100644 --- a/public/app/plugins/datasource/tempo/datasource.test.ts +++ b/public/app/plugins/datasource/tempo/datasource.test.ts @@ -31,6 +31,7 @@ import { makeServiceGraphViewRequest, makeTempoLink, getFieldConfig, + getEscapedSpanNames, } from './datasource'; import mockJson from './mockJsonResponse.json'; import mockServiceGraph from './mockServiceGraph.json'; @@ -590,6 +591,20 @@ describe('Tempo service graph view', () => { expect(builtQuery).toBe('sum(rate(traces_spanmetrics_calls_total{}[$__rate_interval]))'); }); + it('should escape span names correctly', () => { + const spanNames = [ + '/actuator/health/**', + '$type + [test]|HTTP POST - post', + 'server.cluster.local:9090^/sample.test(.*)?', + ]; + let escaped = getEscapedSpanNames(spanNames); + expect(escaped).toEqual([ + '/actuator/health/\\\\*\\\\*', + '\\\\$type \\\\+ \\\\[test\\\\]\\\\|HTTP POST - post', + 'server\\\\.cluster\\\\.local:9090\\\\^/sample\\\\.test\\\\(\\\\.\\\\*\\\\)\\\\?', + ]); + }); + it('should get field config correctly', () => { let datasourceUid = 's4Jvz8Qnk'; let tempoDatasourceUid = 'EbPO1fYnz'; diff --git a/public/app/plugins/datasource/tempo/datasource.ts b/public/app/plugins/datasource/tempo/datasource.ts index 14e2598a55e..374437d4d4b 100644 --- a/public/app/plugins/datasource/tempo/datasource.ts +++ b/public/app/plugins/datasource/tempo/datasource.ts @@ -597,7 +597,7 @@ function errorAndDurationQuery( let serviceGraphViewMetrics = []; let errorRateBySpanName = ''; let durationsBySpanName: string[] = []; - const spanNames = rateResponse.data[0][0]?.fields[1]?.values.toArray() ?? []; + const spanNames = getEscapedSpanNames(rateResponse.data[0][0]?.fields[1]?.values.toArray() ?? []); if (spanNames.length > 0) { errorRateBySpanName = buildExpr(errorRateMetric, 'span_name=~"' + spanNames.join('|') + '"', request); @@ -663,6 +663,10 @@ function makePromLink(title: string, expr: string, datasourceUid: string, instan }; } +export function getEscapedSpanNames(values: string[]) { + return values.map((value: string) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\\\$&')); +} + export function getFieldConfig( datasourceUid: string, tempoDatasourceUid: string,