aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala
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/scala
parent77f2666650726352a9e15dcf6019064d91393b2e (diff)
downloadKamon-e1e7853255131f26702229735e37e160c38f2d08.tar.gz
Kamon-e1e7853255131f26702229735e37e160c38f2d08.tar.bz2
Kamon-e1e7853255131f26702229735e37e160c38f2d08.zip
implement entity filters
Diffstat (limited to 'kamon-core/src/main/scala')
-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
7 files changed, 138 insertions, 32 deletions
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
-}