diff --git a/codequality/checkstyle.xml b/codequality/checkstyle.xml
index 76df51deb..642098094 100644
--- a/codequality/checkstyle.xml
+++ b/codequality/checkstyle.xml
@@ -166,17 +166,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/spectator-reg-atlas/src/main/java/com/netflix/spectator/atlas/impl/Parser.java b/spectator-reg-atlas/src/main/java/com/netflix/spectator/atlas/impl/Parser.java
index c2723d107..6272af69e 100644
--- a/spectator-reg-atlas/src/main/java/com/netflix/spectator/atlas/impl/Parser.java
+++ b/spectator-reg-atlas/src/main/java/com/netflix/spectator/atlas/impl/Parser.java
@@ -15,6 +15,8 @@
*/
package com.netflix.spectator.atlas.impl;
+import com.netflix.spectator.impl.matcher.PatternUtils;
+
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
@@ -56,7 +58,7 @@ public static Query parseQuery(String expr) {
}
}
- @SuppressWarnings({"unchecked", "PMD"})
+ @SuppressWarnings({"unchecked", "checkstyle:MethodLength", "PMD"})
private static Object parse(String expr) {
DataExpr.AggregateFunction af;
Query q, q1, q2;
@@ -156,6 +158,21 @@ private static Object parse(String expr) {
k = (String) stack.pop();
pushRegex(stack, new Query.Regex(k, v, true, ":reic"));
break;
+ case ":contains":
+ v = (String) stack.pop();
+ k = (String) stack.pop();
+ pushRegex(stack, new Query.Regex(k, ".*" + PatternUtils.escape(v)));
+ break;
+ case ":starts":
+ v = (String) stack.pop();
+ k = (String) stack.pop();
+ pushRegex(stack, new Query.Regex(k, PatternUtils.escape(v)));
+ break;
+ case ":ends":
+ v = (String) stack.pop();
+ k = (String) stack.pop();
+ pushRegex(stack, new Query.Regex(k, ".*" + PatternUtils.escape(v) + "$"));
+ break;
case ":all":
q = (Query) stack.pop();
stack.push(new DataExpr.All(q));
diff --git a/spectator-reg-atlas/src/test/java/com/netflix/spectator/atlas/impl/QueryTest.java b/spectator-reg-atlas/src/test/java/com/netflix/spectator/atlas/impl/QueryTest.java
index c87a806ca..a91345453 100644
--- a/spectator-reg-atlas/src/test/java/com/netflix/spectator/atlas/impl/QueryTest.java
+++ b/spectator-reg-atlas/src/test/java/com/netflix/spectator/atlas/impl/QueryTest.java
@@ -42,7 +42,10 @@ private Query parse(String expr) {
Query q1 = Parser.parseQuery(expr);
Query q2 = Parser.parseQuery(expr);
Assertions.assertEquals(q1, q2);
- Assertions.assertEquals(expr, q1.toString());
+
+ Query q3 = Parser.parseQuery(q1.toString());
+ Assertions.assertEquals(q1, q3);
+ Assertions.assertEquals(q1.toString(), q3.toString());
return q1;
}
@@ -210,6 +213,63 @@ public void reEqualsContract() {
.verify();
}
+ @Test
+ public void containsQuery() {
+ Query q = parse("name,foo,:contains");
+ Assertions.assertTrue(q.matches(registry.createId("foo")));
+ Assertions.assertTrue(q.matches(registry.createId("foo_")));
+ Assertions.assertTrue(q.matches(registry.createId("_foo_")));
+ Assertions.assertTrue(q.matches(registry.createId("_foo")));
+ Assertions.assertFalse(q.matches(registry.createId("_Foo_")));
+ }
+
+ @Test
+ public void containsQueryEscape() {
+ Query q = parse("name,^$.?*+[](){}\\#&!%,:contains");
+ Assertions.assertEquals(
+ "name,.*\\^\\$\\.\\?\\*\\+\\[\\]\\(\\)\\{\\}\\\\#&!%,:re",
+ q.toString());
+ Assertions.assertTrue(q.matches(registry.createId("^$.?*+[](){}\\#&!%")));
+ }
+
+ @Test
+ public void startsQuery() {
+ Query q = parse("name,foo,:starts");
+ Assertions.assertTrue(q.matches(registry.createId("foo")));
+ Assertions.assertTrue(q.matches(registry.createId("foo_")));
+ Assertions.assertFalse(q.matches(registry.createId("_foo_")));
+ Assertions.assertFalse(q.matches(registry.createId("_foo")));
+ Assertions.assertFalse(q.matches(registry.createId("Foo_")));
+ }
+
+ @Test
+ public void startsQueryEscape() {
+ Query q = parse("name,^$.?*+[](){}\\#&!%,:starts");
+ Assertions.assertEquals(
+ "name,\\^\\$\\.\\?\\*\\+\\[\\]\\(\\)\\{\\}\\\\#&!%,:re",
+ q.toString());
+ Assertions.assertTrue(q.matches(registry.createId("^$.?*+[](){}\\#&!%")));
+ }
+
+ @Test
+ public void endsQuery() {
+ Query q = parse("name,foo,:ends");
+ Assertions.assertTrue(q.matches(registry.createId("foo")));
+ Assertions.assertFalse(q.matches(registry.createId("foo_")));
+ Assertions.assertFalse(q.matches(registry.createId("_foo_")));
+ Assertions.assertTrue(q.matches(registry.createId("_foo")));
+ Assertions.assertFalse(q.matches(registry.createId("_Foo")));
+ }
+
+ @Test
+ public void endsQueryEscape() {
+ Query q = parse("name,^$.?*+[](){}\\#&!%,:ends");
+ Assertions.assertEquals(
+ "name,.*\\^\\$\\.\\?\\*\\+\\[\\]\\(\\)\\{\\}\\\\#&!%$,:re",
+ q.toString());
+ Assertions.assertTrue(q.matches(registry.createId("^$.?*+[](){}\\#&!%")));
+ }
+
@Test
public void andQuery() {
Query q = parse("name,foo,:eq,bar,baz,:eq,:and");