Skip to content

Commit

Permalink
Added matcher syntax support for Routing tree editor. (prometheus#2065)
Browse files Browse the repository at this point in the history
* Added feature for matcher syntax to Visual Editor. (prometheus#1638)

* feat: Added matcher syntax support for Alertmanager visual editor. First four examples from here https://prometheus.io/docs/alerting/latest/configuration/#matcher should be fine. The last one has an issue, escaped quotes make regexp test fail.

Signed-off-by: Alex Antipin <[email protected]>

* Added feature for matcher syntax to Visual Editor. (prometheus#1638)

* fix: parseSearch method behave incorrect for matchers syntax:
It's intended to split string to label\value pairs, but it would split values also if comma is present there. It is legitimate to have comma in values according to matcher value rules listed here https://prometheus.io/docs/alerting/latest/configuration/#matcher
Also it couldn't handle strings properly by ignoring escaped quotes that is produced after new syntax parsing.

Signed-off-by: Alex Antipin <[email protected]>

* Added feature for matcher syntax to Visual Editor. (prometheus#1638)

* fix: there could be zero or one heading\trailing spaces around selector

Signed-off-by: Alex Antipin <[email protected]>

* Added feature for matcher syntax to Visual Editor. (prometheus#1638)

* add: Matcher enum-like object holding relevant PromQL matcher operators
* add: matchNewSyntax method to check equality for values using Matcher operator
* fix: negative matchers should not be considered as Regexp

Signed-off-by: Alex Antipin <[email protected]>
  • Loading branch information
Evreke authored Feb 9, 2022
1 parent fd1d9aa commit 6c1f1a3
Showing 1 changed file with 72 additions and 9 deletions.
81 changes: 72 additions & 9 deletions static/routing-tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ var tooltip = d3.select("body")
.style("z-index", "10")
.style("visibility", "hidden");

const promQlRegExp = /\b(?<label>[a-z0-9_]\w*)\s?(?<selector>=~?|![=~])\s?"?(?<value>(?<=")(?:[^\\"]|\\.)*(?=")|\w+[^\s},]+)/gmi;

function parseSearch(searchString) {
var labels = searchString.replace(/{|}|\"|\'/g, "").split(",");
var o = {};
labels.forEach(function(label) {
var l = label.trim().split("=");
o[l[0]] = l[1];
});
let o = {};
let matchedExpressions;
while ((matchedExpressions = promQlRegExp.exec(searchString)) !== null) {
o[matchedExpressions[1]] = matchedExpressions[3];
}
return o;
}

Expand Down Expand Up @@ -113,18 +114,44 @@ function matchLabels(matchers, labelSet) {
return true;
}

const Matcher = Object.freeze({
EQ: "MatchEqual",
NE: "MatchNotEqual",
RE: "MatchRegexp",
NRE: "MatchNotRegexp",
})

// Compare single matcher to labelSet
function matchLabel(matcher, labelSet) {
var v = "";
if (matcher.name in labelSet) {
v = labelSet[matcher.name];
}

if (matcher.isRegex) {
return matcher.value.test(v)
if (matcher.op !== undefined) {
return matchNewSyntax(matcher, v);
} else {
// Deprecated matchers check
if (matcher.isRegex) {
return matcher.value.test(v)
}
return matcher.value === v;
}
}

return matcher.value === v;
function matchNewSyntax(matcher, v) {
switch (matcher.op) {
case Matcher.EQ:
return matcher.value === v;
case Matcher.NE:
return matcher.value !== v;
case Matcher.RE:
case Matcher.NRE:
return matcher.value.test(v);
default:
console.log("Invalid matcher");
break;
}
}

// Load the parsed config and create the tree
Expand Down Expand Up @@ -166,6 +193,42 @@ function massage(root, receivers) {
}
}

// PromQL matcher syntax check
if (root.matchers) {
root.matchers.forEach((matcher) => {
let o = {};
let matchedExpressions;

while ((matchedExpressions = promQlRegExp.exec(matcher)) !== null) {
let [match, label, selector, value] = matchedExpressions;
o.name = label;

switch (selector) {
case "=~":
o.value = new RegExp("^(?:" + value + ")$");
o.op = Matcher.RE;
matchers.push(o);
break;
case "!=":
o.op = Matcher.NE
o.value = value;
matchers.push(o);
break;
case "!~":
o.op = Matcher.NRE
o.value = new RegExp("^(?!" + value + "$)");
matchers.push(o);
break;
case "=":
o.op = Matcher.EQ
o.value = value
matchers.push(o);
break;
}
}
});
}

root.matchers = matchers;

root.receiverConfig = getReceiverConfig(root.receiver, receivers);
Expand Down

0 comments on commit 6c1f1a3

Please sign in to comment.