diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.test.ts b/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.test.ts index bfc8cb955a2b8..a957c58167403 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.test.ts +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.test.ts @@ -23,6 +23,16 @@ describe('PainlessTinyMathParser', () => { // ✅ checked with Lens Formula editor expect(parser.parse()).toEqual('100*average(system.cpu.system.pct)'); }); + it('should parse a simple equation with multi-char aggregation name', () => { + const equation = '100 * ABC-abc'; + const parser = new PainlessTinyMathParser({ + equation, + aggMap: { + 'ABC-abc': 'average(system.cpu.system.pct)', + }, + }); + expect(parser.parse()).toEqual('100*average(system.cpu.system.pct)'); + }); it('should parse a simple equation with two aggregations A and B', () => { const equation = '100 * A + B / 100'; const parser = new PainlessTinyMathParser({ @@ -162,6 +172,20 @@ describe('PainlessTinyMathParser', () => { 'ifelse(ifelse(average(system.cpu.system.pct)>0,0,1) + ifelse(average(system.cpu.user.pct)==10,0,1) * ifelse(average(system.cpu.system.pct)<200,0,1) + ifelse(average(system.cpu.user.pct)==2,1,0) > 0, 100, ifelse(average(system.cpu.system.pct)==10, 200, 300))' ); }); + it('should parse a complex equation with multi char aggregation name', () => { + const equation = + '!(aa > 0) || baa !== 10 && !(aa < 200 || baa == 2) ? 100 : aa == 10 ? 200 : 300'; + const parser = new PainlessTinyMathParser({ + equation, + aggMap: { + aa: 'average(system.cpu.system.pct)', + baa: 'average(system.cpu.user.pct)', + }, + }); + expect(parser.parse()).toEqual( + 'ifelse(ifelse(average(system.cpu.system.pct)>0,0,1) + ifelse(average(system.cpu.user.pct)==10,0,1) * ifelse(average(system.cpu.system.pct)<200,0,1) + ifelse(average(system.cpu.user.pct)==2,1,0) > 0, 100, ifelse(average(system.cpu.system.pct)==10, 200, 300))' + ); + }); it('should parse a complex equation with many nested conditions and many aggregations', () => { const equation = diff --git a/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.ts b/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.ts index 0bbcab23948ba..25ec15d3a808b 100644 --- a/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.ts +++ b/x-pack/plugins/observability/public/components/custom_threshold/components/rule_condition_chart/painless_tinymath_parser.ts @@ -75,13 +75,16 @@ export class PainlessTinyMathParser { } replaceCharactersWithAggMap(inputString: string, aggMap: AggMap): string { - // Use a regular expression to match any character from 'A' to 'Z' - const regex = /[A-Z]/g; - - return inputString.replace(regex, (match) => { - const replacement = aggMap[match]; // Get the replacement from the map - return replacement ? replacement : match; // Use the replacement or the original character - }); + let parsedInputString = inputString; + // Iterate over aggregation names and replace them with equation + Object.keys(aggMap) + .sort() + .reverse() + .forEach((metricName) => { + parsedInputString = parsedInputString.replaceAll(metricName, aggMap[metricName]); + }); + + return parsedInputString; } parseCondition(condition: string): string {