From 1bd2fcc712cea984864d5a7e13be81a5f150d236 Mon Sep 17 00:00:00 2001 From: Daniel Bimschas Date: Sat, 5 Nov 2016 04:10:03 +0100 Subject: + core: support for regex path filters (#388) --- .../src/main/java/kamon/util/GlobPathFilter.java | 4 +- .../main/scala/kamon/metric/MetricsSettings.scala | 14 +++-- .../src/main/scala/kamon/util/PathFilter.scala | 5 ++ .../main/scala/kamon/util/RegexPathFilter.scala | 27 ++++++++++ .../scala/kamon/util/RegexPathFilterSpec.scala | 59 ++++++++++++++++++++++ 5 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 kamon-core/src/main/scala/kamon/util/PathFilter.scala create mode 100644 kamon-core/src/main/scala/kamon/util/RegexPathFilter.scala create mode 100644 kamon-core/src/test/scala/kamon/util/RegexPathFilterSpec.scala diff --git a/kamon-core/src/main/java/kamon/util/GlobPathFilter.java b/kamon-core/src/main/java/kamon/util/GlobPathFilter.java index 0c7b999c..ac5d08a6 100644 --- a/kamon-core/src/main/java/kamon/util/GlobPathFilter.java +++ b/kamon-core/src/main/java/kamon/util/GlobPathFilter.java @@ -25,7 +25,7 @@ import java.util.regex.Pattern; * @author John E. Bailey * @author David M. Lloyd */ -public final class GlobPathFilter { +public final class GlobPathFilter implements PathFilter { private static final Pattern GLOB_PATTERN = Pattern.compile("(\\*\\*?)|(\\?)|(\\\\.)|(/+)|([^*?]+)"); private final String glob; @@ -107,4 +107,4 @@ public final class GlobPathFilter { } return Pattern.compile(patternBuilder.toString()); } -} \ No newline at end of file +} diff --git a/kamon-core/src/main/scala/kamon/metric/MetricsSettings.scala b/kamon-core/src/main/scala/kamon/metric/MetricsSettings.scala index a472a89b..018a6584 100644 --- a/kamon-core/src/main/scala/kamon/metric/MetricsSettings.scala +++ b/kamon-core/src/main/scala/kamon/metric/MetricsSettings.scala @@ -18,7 +18,9 @@ package kamon.metric import com.typesafe.config.Config import kamon.metric.instrument._ +import kamon.util.PathFilter import kamon.util.GlobPathFilter +import kamon.util.RegexPathFilter import scala.concurrent.duration.FiniteDuration @@ -43,7 +45,7 @@ case class MetricsSettings( /** * */ -case class EntityFilter(includes: List[GlobPathFilter], excludes: List[GlobPathFilter]) { +case class EntityFilter(includes: List[PathFilter], excludes: List[PathFilter]) { def accept(name: String): Boolean = includes.exists(_.accept(name)) && !excludes.exists(_.accept(name)) } @@ -71,7 +73,7 @@ object MetricsSettings { /** * Load all the default filters configured under the `kamon.metric.filters` configuration key. All filters are * defined with the entity category as a sub-key of the `kamon.metric.filters` key and two sub-keys to it: includes - * and excludes with lists of string glob patterns as values. Example: + * and excludes with lists of string glob or regex patterns as values ('asRegex' defaults to false). Example: * * {{{ * @@ -79,6 +81,7 @@ object MetricsSettings { * actor { * includes = ["user/test-actor", "user/service/worker-*"] * excludes = ["user/IO-*"] + * asRegex = false * } * } * @@ -90,8 +93,11 @@ object MetricsSettings { import scala.collection.JavaConverters._ filtersConfig.firstLevelKeys map { category: String ⇒ - val includes = filtersConfig.getStringList(s"$category.includes").asScala.map(inc ⇒ new GlobPathFilter(inc)).toList - val excludes = filtersConfig.getStringList(s"$category.excludes").asScala.map(exc ⇒ new GlobPathFilter(exc)).toList + val asRegex = if (filtersConfig.hasPath(s"$category.asRegex")) filtersConfig.getBoolean(s"$category.asRegex") else false + val includes = filtersConfig.getStringList(s"$category.includes").asScala.map(inc ⇒ + if (asRegex) RegexPathFilter(inc) else new GlobPathFilter(inc)).toList + val excludes = filtersConfig.getStringList(s"$category.excludes").asScala.map(exc ⇒ + if (asRegex) RegexPathFilter(exc) else new GlobPathFilter(exc)).toList (category, EntityFilter(includes, excludes)) } toMap diff --git a/kamon-core/src/main/scala/kamon/util/PathFilter.scala b/kamon-core/src/main/scala/kamon/util/PathFilter.scala new file mode 100644 index 00000000..50e14ace --- /dev/null +++ b/kamon-core/src/main/scala/kamon/util/PathFilter.scala @@ -0,0 +1,5 @@ +package kamon.util + +trait PathFilter { + def accept(path: String): Boolean +} diff --git a/kamon-core/src/main/scala/kamon/util/RegexPathFilter.scala b/kamon-core/src/main/scala/kamon/util/RegexPathFilter.scala new file mode 100644 index 00000000..848fca87 --- /dev/null +++ b/kamon-core/src/main/scala/kamon/util/RegexPathFilter.scala @@ -0,0 +1,27 @@ +/* + * ========================================================================================= + * Copyright © 2013-2015 the kamon project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + * ========================================================================================= + */ + +package kamon.util + +case class RegexPathFilter(path: String) extends PathFilter { + private val pathRegex = path.r + override def accept(path: String): Boolean = { + path match { + case pathRegex(_*) ⇒ true + case _ ⇒ false + } + } +} diff --git a/kamon-core/src/test/scala/kamon/util/RegexPathFilterSpec.scala b/kamon-core/src/test/scala/kamon/util/RegexPathFilterSpec.scala new file mode 100644 index 00000000..edbf14b3 --- /dev/null +++ b/kamon-core/src/test/scala/kamon/util/RegexPathFilterSpec.scala @@ -0,0 +1,59 @@ +/* + * ========================================================================================= + * Copyright © 2013-2015 the kamon project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + * ========================================================================================= + */ + +package kamon.util + +import org.scalatest.{ Matchers, WordSpecLike } + +class RegexPathFilterSpec extends WordSpecLike with Matchers { + "The RegexPathFilter" should { + + "match a single expression" in { + val filter = new RegexPathFilter("/user/actor") + + filter.accept("/user/actor") shouldBe true + + filter.accept("/user/actor/something") shouldBe false + filter.accept("/user/actor/somethingElse") shouldBe false + } + + "match arbitray expressions ending with wildcard" in { + val filter = new RegexPathFilter("/user/.*") + + filter.accept("/user/actor") shouldBe true + filter.accept("/user/otherActor") shouldBe true + filter.accept("/user/something/actor") shouldBe true + filter.accept("/user/something/otherActor") shouldBe true + + filter.accept("/otheruser/actor") shouldBe false + filter.accept("/otheruser/otherActor") shouldBe false + filter.accept("/otheruser/something/actor") shouldBe false + filter.accept("/otheruser/something/otherActor") shouldBe false + } + + "match numbers" in { + val filter = new RegexPathFilter("/user/actor-\\d") + + filter.accept("/user/actor-1") shouldBe true + filter.accept("/user/actor-2") shouldBe true + filter.accept("/user/actor-3") shouldBe true + + filter.accept("/user/actor-one") shouldBe false + filter.accept("/user/actor-two") shouldBe false + filter.accept("/user/actor-tree") shouldBe false + } + } +} -- cgit v1.2.3