aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2017-05-20 14:06:03 +0200
committerIvan Topolnjak <ivantopo@gmail.com>2017-05-20 14:06:03 +0200
commite1e7853255131f26702229735e37e160c38f2d08 (patch)
tree98202bb2b62a9c0dd29d0fb7f020da232703844a /kamon-core/src/main
parent77f2666650726352a9e15dcf6019064d91393b2e (diff)
downloadKamon-e1e7853255131f26702229735e37e160c38f2d08.tar.gz
Kamon-e1e7853255131f26702229735e37e160c38f2d08.tar.bz2
Kamon-e1e7853255131f26702229735e37e160c38f2d08.zip
implement entity filters
Diffstat (limited to 'kamon-core/src/main')
-rw-r--r--kamon-core/src/main/java/kamon/util/GlobPathFilter.java110
-rw-r--r--kamon-core/src/main/resources/reference.conf4
-rw-r--r--kamon-core/src/main/scala/kamon/Util.scala2
-rw-r--r--kamon-core/src/main/scala/kamon/metric/EntityFilter.scala110
-rw-r--r--kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala22
-rw-r--r--kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala14
-rw-r--r--kamon-core/src/main/scala/kamon/trace/Span.scala6
-rw-r--r--kamon-core/src/main/scala/kamon/trace/SpanContext.scala9
-rw-r--r--kamon-core/src/main/scala/kamon/util/EntityFilter.scala7
9 files changed, 142 insertions, 142 deletions
diff --git a/kamon-core/src/main/java/kamon/util/GlobPathFilter.java b/kamon-core/src/main/java/kamon/util/GlobPathFilter.java
deleted file mode 100644
index 1bfbaefc..00000000
--- a/kamon-core/src/main/java/kamon/util/GlobPathFilter.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * =========================================================================================
- * Copyright 2013-2014 the kamon project <http://kamon.io/>
- *
- * 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 <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
- */
-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:
- * <ul>
- * <li><code>"\"</code> - escape the next character (treat it literally, even if it is itself a recognized metacharacter)</li>
- * <li><code>"?"</code> - match any non-slash character</li>
- * <li><code>"*"</code> - match zero or more non-slash characters</li>
- * <li><code>"**"</code> - match zero or more characters, including slashes</li>
- * <li><code>"/"</code> - match one or more slash characters. Consecutive {@code /} characters are collapsed down into one.</li>
- * </ul>
- * In addition, any glob pattern matches all subdirectories thereof. A glob pattern ending in {@code /} is equivalent
- * to a glob pattern ending in <code>/**</code> in that the named directory is not itself included in the glob.
- * <p/>
- * <b>See also:</b> <a href="http://ant.apache.org/manual/dirtasks.html#patterns">"Patterns" in the Ant Manual</a>
- *
- * @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());
- }
-}
diff --git a/kamon-core/src/main/resources/reference.conf b/kamon-core/src/main/resources/reference.conf
index 61072507..aac718ca 100644
--- a/kamon-core/src/main/resources/reference.conf
+++ b/kamon-core/src/main/resources/reference.conf
@@ -2,6 +2,10 @@ kamon {
metric {
tick-interval = 1 second
+ filters {
+ accept-unmatched = true
+ }
+
instrument-factory {
# Default instrument settings for histograms and min max counters. The actual settings to be used when creating
diff --git a/kamon-core/src/main/scala/kamon/Util.scala b/kamon-core/src/main/scala/kamon/Util.scala
index 04ce7a04..c8efbdc0 100644
--- a/kamon-core/src/main/scala/kamon/Util.scala
+++ b/kamon-core/src/main/scala/kamon/Util.scala
@@ -1,6 +1,6 @@
package kamon
-import kamon.util.EntityFilter
+import kamon.metric.EntityFilter
/**
* Useful classes for Kamon and submodules.
diff --git a/kamon-core/src/main/scala/kamon/metric/EntityFilter.scala b/kamon-core/src/main/scala/kamon/metric/EntityFilter.scala
new file mode 100644
index 00000000..cf203609
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/metric/EntityFilter.scala
@@ -0,0 +1,110 @@
+package kamon
+package metric
+
+import java.util.regex.Pattern
+import com.typesafe.config.Config
+
+object EntityFilter {
+ def fromConfig(config: Config): EntityFilter = {
+ val filtersConfig = config.getConfig("kamon.metric.filters")
+ val acceptUnmatched = filtersConfig.getBoolean("accept-unmatched")
+
+ val perCategoryFilters = filtersConfig.firstLevelKeys.filter(_ != "accept-unmatched") map { category: String ⇒
+ val includes = readFilters(filtersConfig, s"$category.includes")
+ val excludes = readFilters(filtersConfig, s"$category.excludes")
+
+ (category, new IncludeExcludeNameFilter(includes, excludes, acceptUnmatched))
+ } toMap
+
+ new EntityFilter(perCategoryFilters, acceptUnmatched)
+ }
+
+ private def readFilters(filtersConfig: Config, name: String): Seq[NameFilter] = {
+ import scala.collection.JavaConverters._
+ if(filtersConfig.hasPath(name))
+ filtersConfig.getStringList(name).asScala.map(readNameFilter)
+ else
+ Seq.empty
+ }
+
+ private def readNameFilter(pattern: String): NameFilter = {
+ if(pattern.startsWith("regex:"))
+ new RegexNameFilter(pattern.drop(6))
+ else if(pattern.startsWith("glob:"))
+ new GlobPathFilter(pattern.drop(5))
+ else
+ new GlobPathFilter(pattern)
+ }
+}
+
+class EntityFilter(perCategoryFilters: Map[String, NameFilter], acceptUnmatched: Boolean) {
+ def accept(entity: Entity): Boolean =
+ perCategoryFilters
+ .get(entity.category)
+ .map(_.accept(entity.name))
+ .getOrElse(acceptUnmatched)
+}
+
+trait NameFilter {
+ def accept(name: String): Boolean
+}
+
+class IncludeExcludeNameFilter(includes: Seq[NameFilter], excludes: Seq[NameFilter], acceptUnmatched: Boolean) extends NameFilter {
+ override def accept(name: String): Boolean =
+ (includes.exists(_.accept(name)) || acceptUnmatched) && !excludes.exists(_.accept(name))
+}
+
+class RegexNameFilter(path: String) extends NameFilter {
+ private val pathRegex = path.r
+
+ override def accept(path: String): Boolean = path match {
+ case pathRegex(_*) ⇒ true
+ case _ ⇒ false
+ }
+}
+
+class GlobPathFilter(glob: String) extends NameFilter {
+ private val globPattern = Pattern.compile("(\\*\\*?)|(\\?)|(\\\\.)|(/+)|([^*?]+)")
+ private val compiledPattern = getGlobPattern(glob)
+
+ override def accept(name: String): Boolean =
+ compiledPattern.matcher(name).matches()
+
+ private def getGlobPattern(glob: String) = {
+ val patternBuilder = new StringBuilder
+ val matcher = globPattern.matcher(glob)
+ while (matcher.find()) {
+ val (grp1, grp2, grp3, grp4) = (matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(4))
+ if (grp1 != null) {
+ // match a * or **
+ if (grp1.length == 2) {
+ // it's a *workers are able to process multiple metrics*
+ patternBuilder.append(".*")
+ }
+ else {
+ // it's a *
+ patternBuilder.append("[^/]*")
+ }
+ }
+ else if (grp2 != null) {
+ // match a '?' glob pattern; any non-slash character
+ patternBuilder.append("[^/]")
+ }
+ else if (grp3 != null) {
+ // backslash-escaped value
+ patternBuilder.append(Pattern.quote(grp3.substring(1)))
+ }
+ else if (grp4 != null) {
+ // match any number of / chars
+ patternBuilder.append("/+")
+ }
+ else {
+ // some other string
+ patternBuilder.append(Pattern.quote(matcher.group))
+ }
+ }
+
+ Pattern.compile(patternBuilder.toString)
+ }
+}
+
diff --git a/kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala b/kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala
index a4d2f4cd..53081760 100644
--- a/kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala
+++ b/kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala
@@ -10,31 +10,31 @@ import scala.collection.concurrent.TrieMap
trait RecorderRegistry {
+ def shouldTrack(entity: Entity): Boolean
def getRecorder(entity: Entity): EntityRecorder
- def getRecorder(name: String, category: String, tags: Map[String, String]): EntityRecorder
-
def removeRecorder(entity: Entity): Boolean
- def removeRecorder(name: String, category: String, tags: Map[String, String]): Boolean
}
class RecorderRegistryImpl(initialConfig: Config) extends RecorderRegistry {
private val instrumentFactory = new AtomicReference[InstrumentFactory]()
+ private val entityFilter = new AtomicReference[EntityFilter]()
private val entities = TrieMap.empty[Entity, EntityRecorder with EntitySnapshotProducer]
reconfigure(initialConfig)
- override def getRecorder(entity: Entity): EntityRecorder =
- entities.atomicGetOrElseUpdate(entity, new DefaultEntityRecorder(entity, instrumentFactory.get()))
- override def getRecorder(name: String, category: String, tags: Map[String, String]): EntityRecorder =
- getRecorder(Entity(name, category, tags))
+ override def shouldTrack(entity: Entity): Boolean =
+ entityFilter.get().accept(entity)
- override def removeRecorder(entity: Entity): Boolean = ???
+ override def getRecorder(entity: Entity): EntityRecorder =
+ entities.atomicGetOrElseUpdate(entity, new DefaultEntityRecorder(entity, instrumentFactory.get()))
- override def removeRecorder(name: String, category: String, tags: Map[String, String]): Boolean = ???
+ override def removeRecorder(entity: Entity): Boolean =
+ entities.remove(entity).nonEmpty
- private[kamon] def reconfigure(config: Config): Unit = {
- instrumentFactory.set(InstrumentFactory(config.getConfig("kamon.metric.instrument-factory")))
+ private[kamon] def reconfigure(config: Config): Unit = synchronized {
+ instrumentFactory.set(InstrumentFactory.fromConfig(config))
+ entityFilter.set(EntityFilter.fromConfig(config))
}
private[kamon] def snapshot(): Seq[EntitySnapshot] = {
diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala b/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala
index e8d4d569..33a34bdf 100644
--- a/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala
+++ b/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala
@@ -63,14 +63,15 @@ private[kamon] class InstrumentFactory private (
)
}
-private[kamon] object InstrumentFactory {
+object InstrumentFactory {
- private[kamon] def apply(config: Config): InstrumentFactory = {
- val histogramDynamicRange = readDynamicRange(config.getConfig("default-settings.histogram"))
- val mmCounterDynamicRange = readDynamicRange(config.getConfig("default-settings.min-max-counter"))
- val mmCounterSampleInterval = config.getDuration("default-settings.min-max-counter.sample-interval")
+ def fromConfig(config: Config): InstrumentFactory = {
+ val factoryConfig = config.getConfig("kamon.metric.instrument-factory")
+ val histogramDynamicRange = readDynamicRange(factoryConfig.getConfig("default-settings.histogram"))
+ val mmCounterDynamicRange = readDynamicRange(factoryConfig.getConfig("default-settings.min-max-counter"))
+ val mmCounterSampleInterval = factoryConfig.getDuration("default-settings.min-max-counter.sample-interval")
- val customSettings = config.getConfig("custom-settings")
+ val customSettings = factoryConfig.getConfig("custom-settings")
.configurations
.filter(nonEmptyCategories)
.flatMap(buildCustomInstrumentSettings)
@@ -96,7 +97,6 @@ private[kamon] object InstrumentFactory {
significantValueDigits = config.getInt("significant-value-digits")
)
-
private case class CustomInstrumentSettings(
lowestDiscernibleValue: Option[Long],
highestTrackableValue: Option[Long],
diff --git a/kamon-core/src/main/scala/kamon/trace/Span.scala b/kamon-core/src/main/scala/kamon/trace/Span.scala
index 87115e19..804627dc 100644
--- a/kamon-core/src/main/scala/kamon/trace/Span.scala
+++ b/kamon-core/src/main/scala/kamon/trace/Span.scala
@@ -1,7 +1,7 @@
package kamon
package trace
-import kamon.metric.RecorderRegistry
+import kamon.metric.{Entity, RecorderRegistry}
import kamon.metric.instrument.DynamicRange
import scala.collection.JavaConverters._
@@ -167,7 +167,8 @@ class Span(spanContext: SpanContext, initialOperationName: String, startTimestam
private def recordSpanMetrics(): Unit = {
val elapsedTime = endTimestampMicros - startTimestampMicros
- val recorder = recorderRegistry.getRecorder(operationName, Span.MetricCategory, metricTags)
+ val entity = Entity(operationName, Span.MetricCategory, metricTags)
+ val recorder = recorderRegistry.getRecorder(entity)
recorder
.histogram(Span.LatencyMetricName, MeasurementUnit.time.microseconds, DynamicRange.Default)
@@ -178,6 +179,5 @@ class Span(spanContext: SpanContext, initialOperationName: String, startTimestam
recorder.counter(Span.ErrorMetricName).increment()
}
}
-
}
} \ No newline at end of file
diff --git a/kamon-core/src/main/scala/kamon/trace/SpanContext.scala b/kamon-core/src/main/scala/kamon/trace/SpanContext.scala
index 7f5962e0..a3afb36d 100644
--- a/kamon-core/src/main/scala/kamon/trace/SpanContext.scala
+++ b/kamon-core/src/main/scala/kamon/trace/SpanContext.scala
@@ -1,4 +1,5 @@
package kamon.trace
+
import java.lang
import java.util.Map
import scala.collection.JavaConverters._
@@ -6,16 +7,18 @@ import scala.collection.JavaConverters._
class SpanContext(val traceID: Long, val spanID: Long, val parentID: Long) extends io.opentracing.SpanContext {
private var baggage = scala.collection.immutable.Map.empty[String, String]
- private[kamon] def addBaggageItem(key: String, value: String): Unit = {
+ private[kamon] def addBaggageItem(key: String, value: String): Unit = synchronized {
baggage = baggage + (key -> value)
}
- private[kamon] def getBaggage(key: String): String =
+ private[kamon] def getBaggage(key: String): String = synchronized {
baggage.get(key).getOrElse(null)
+ }
private[kamon] def baggageMap: scala.collection.immutable.Map[String, String] =
baggage
- override def baggageItems(): lang.Iterable[Map.Entry[String, String]] =
+ override def baggageItems(): lang.Iterable[Map.Entry[String, String]] = synchronized {
baggage.asJava.entrySet()
+ }
}
diff --git a/kamon-core/src/main/scala/kamon/util/EntityFilter.scala b/kamon-core/src/main/scala/kamon/util/EntityFilter.scala
deleted file mode 100644
index a8456689..00000000
--- a/kamon-core/src/main/scala/kamon/util/EntityFilter.scala
+++ /dev/null
@@ -1,7 +0,0 @@
-package kamon.util
-
-import kamon.metric.Entity
-
-trait EntityFilter {
- def accept(entity: Entity): Boolean
-}