From 8af94310494d912c9b09e851601e14cd46890c2a Mon Sep 17 00:00:00 2001 From: Diego Date: Mon, 22 Dec 2014 17:35:11 -0300 Subject: = core: modified version of GlobPathFilter and improve GlobPahFilterSpec --- .../src/main/java/kamon/util/GlobPathFilter.java | 110 +++++++++++++++++++++ .../main/scala/kamon/metric/MetricsExtension.scala | 4 +- .../src/main/scala/kamon/util/GlobPathFilter.scala | 44 --------- .../test/scala/kamon/util/GlobPathFilterSpec.scala | 29 ++++-- 4 files changed, 132 insertions(+), 55 deletions(-) create mode 100644 kamon-core/src/main/java/kamon/util/GlobPathFilter.java delete mode 100644 kamon-core/src/main/scala/kamon/util/GlobPathFilter.scala (limited to 'kamon-core/src') diff --git a/kamon-core/src/main/java/kamon/util/GlobPathFilter.java b/kamon-core/src/main/java/kamon/util/GlobPathFilter.java new file mode 100644 index 00000000..0c7b999c --- /dev/null +++ b/kamon-core/src/main/java/kamon/util/GlobPathFilter.java @@ -0,0 +1,110 @@ +/* + * ========================================================================================= + * Copyright 2013-2014 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 java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Default implementation of PathFilter. Uses glob based includes and excludes to determine whether to export. + * + * @author John E. Bailey + * @author David M. Lloyd + */ +public final class GlobPathFilter { + private static final Pattern GLOB_PATTERN = Pattern.compile("(\\*\\*?)|(\\?)|(\\\\.)|(/+)|([^*?]+)"); + + private final String glob; + private final Pattern pattern; + + /** + * Construct a new instance. + * + * @param glob the path glob to match + */ + public GlobPathFilter(final String glob) { + pattern = getGlobPattern(glob); + this.glob = glob; + } + + /** + * Determine whether a path should be accepted. + * + * @param path the path to check + * @return true if the path should be accepted, false if not + */ + public boolean accept(final String path) { + return pattern.matcher(path).matches(); + } + + /** + * Get a regular expression pattern which accept any path names which match the given glob. The glob patterns + * function similarly to {@code ant} file patterns. Valid metacharacters in the glob pattern include: + * + * In addition, any glob pattern matches all subdirectories thereof. A glob pattern ending in {@code /} is equivalent + * to a glob pattern ending in /** in that the named directory is not itself included in the glob. + *

+ * See also: "Patterns" in the Ant Manual + * + * @param glob the glob to match + * + * @return the pattern + */ + private static Pattern getGlobPattern(final String glob) { + StringBuilder patternBuilder = new StringBuilder(); + final Matcher m = GLOB_PATTERN.matcher(glob); + boolean lastWasSlash = false; + while (m.find()) { + lastWasSlash = false; + String grp; + if ((grp = m.group(1)) != null) { + // match a * or ** + if (grp.length() == 2) { + // it's a *workers are able to process multiple metrics* + patternBuilder.append(".*"); + } else { + // it's a * + patternBuilder.append("[^/]*"); + } + } else if ((grp = m.group(2)) != null) { + // match a '?' glob pattern; any non-slash character + patternBuilder.append("[^/]"); + } else if ((grp = m.group(3)) != null) { + // backslash-escaped value + patternBuilder.append(Pattern.quote(m.group().substring(1))); + } else if ((grp = m.group(4)) != null) { + // match any number of / chars + patternBuilder.append("/+"); + lastWasSlash = true; + } else { + // some other string + patternBuilder.append(Pattern.quote(m.group())); + } + } + if (lastWasSlash) { + // ends in /, append ** + patternBuilder.append(".*"); + } + return Pattern.compile(patternBuilder.toString()); + } +} \ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/MetricsExtension.scala b/kamon-core/src/main/scala/kamon/metric/MetricsExtension.scala index 88802d52..ed55ab06 100644 --- a/kamon-core/src/main/scala/kamon/metric/MetricsExtension.scala +++ b/kamon-core/src/main/scala/kamon/metric/MetricsExtension.scala @@ -88,8 +88,8 @@ class MetricsExtension(system: ExtendedActorSystem) extends Kamon.Extension { val key = entry.getKey val keyBasedConfig = entry.getValue.atKey(key) - val includes = keyBasedConfig.getStringList(s"$key.includes").asScala.map(inc ⇒ GlobPathFilter(inc)).toList - val excludes = keyBasedConfig.getStringList(s"$key.excludes").asScala.map(exc ⇒ GlobPathFilter(exc)).toList + val includes = keyBasedConfig.getStringList(s"$key.includes").asScala.map(inc ⇒ new GlobPathFilter(inc)).toList + val excludes = keyBasedConfig.getStringList(s"$key.excludes").asScala.map(exc ⇒ new GlobPathFilter(exc)).toList (key, MetricGroupFilter(includes, excludes)) } diff --git a/kamon-core/src/main/scala/kamon/util/GlobPathFilter.scala b/kamon-core/src/main/scala/kamon/util/GlobPathFilter.scala deleted file mode 100644 index a980773f..00000000 --- a/kamon-core/src/main/scala/kamon/util/GlobPathFilter.scala +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2014 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 scala.util.matching.Regex - -class GlobPathFilter(glob: String) { - - val regex = globAsRegex(glob) - - def accept(path: String): Boolean = path.matches(regex.toString()) - - private def globAsRegex(glob: String): Regex = { - val regexStr = new StringBuilder('^') - - glob.foreach { - case '.' ⇒ regexStr append """\.""" - case '*' ⇒ regexStr append """[^/]*""" - case '?' ⇒ regexStr append """.""" - case ch ⇒ regexStr append ch - } - regexStr append """/?$""" - - new Regex(regexStr.toString()) - } -} - -object GlobPathFilter { - def apply(glob: String): GlobPathFilter = new GlobPathFilter(glob) -} diff --git a/kamon-core/src/test/scala/kamon/util/GlobPathFilterSpec.scala b/kamon-core/src/test/scala/kamon/util/GlobPathFilterSpec.scala index 0611e169..e0b837f3 100644 --- a/kamon-core/src/test/scala/kamon/util/GlobPathFilterSpec.scala +++ b/kamon-core/src/test/scala/kamon/util/GlobPathFilterSpec.scala @@ -22,22 +22,33 @@ class GlobPathFilterSpec extends WordSpecLike with Matchers { "The GlobPathFilter" should { "match a single expression" in { - val filter = GlobPathFilter("/user/actor") + val filter = new GlobPathFilter("/user/actor") - filter.accept("/user/actor") should be (true) + filter.accept("/user/actor") shouldBe true - filter.accept("/user/actor/something") should be (false) - filter.accept("/user/actor/somethingElse") should be (false) + filter.accept("/user/actor/something") shouldBe false + filter.accept("/user/actor/somethingElse") shouldBe false } "match all expressions in the same level" in { - val filter = GlobPathFilter("/user/*") + val filter = new GlobPathFilter("/user/*") - filter.accept("/user/actor") should be (true) - filter.accept("/user/otherActor") should be (true) + filter.accept("/user/actor") shouldBe true + filter.accept("/user/otherActor") shouldBe true - filter.accept("/user/something/actor") should be (false) - filter.accept("/user/something/otherActor") should be (false) + filter.accept("/user/something/actor") shouldBe false + filter.accept("/user/something/otherActor") shouldBe false + } + + "match all expressions in all levels" in { + val filter = new GlobPathFilter("/user/actor-**") + + filter.accept("/user/actor-") shouldBe true + filter.accept("/user/actor-one") shouldBe true + filter.accept("/user/actor-one/other") shouldBe true + + filter.accept("/user/something/actor") shouldBe false + filter.accept("/user/something/otherActor")shouldBe false } } } -- cgit v1.2.3