aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/util
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2015-01-29 03:42:27 +0100
committerIvan Topolnjak <ivantopo@gmail.com>2015-01-29 03:42:27 +0100
commit75bd9503aebee628da394a935816991e7a790092 (patch)
treef4df3333826cec805fadc14894579f1bc1054279 /kamon-core/src/main/scala/kamon/util
parent61089a75240f5cc21b056087f1d633dd31981c61 (diff)
parent9839db9d46312435822b6b5faffbbc445af80077 (diff)
downloadKamon-75bd9503aebee628da394a935816991e7a790092.tar.gz
Kamon-75bd9503aebee628da394a935816991e7a790092.tar.bz2
Kamon-75bd9503aebee628da394a935816991e7a790092.zip
Merge branch 'wip/improve-metric-recorders-infrastructure'
Conflicts: kamon-system-metrics/src/main/scala/kamon/system/SystemMetricsCollector.scala
Diffstat (limited to 'kamon-core/src/main/scala/kamon/util')
-rw-r--r--kamon-core/src/main/scala/kamon/util/ConfigTools.scala26
-rw-r--r--kamon-core/src/main/scala/kamon/util/FastDispatch.scala22
-rw-r--r--kamon-core/src/main/scala/kamon/util/MapMerge.scala27
-rw-r--r--kamon-core/src/main/scala/kamon/util/Timestamp.scala85
-rw-r--r--kamon-core/src/main/scala/kamon/util/TriemapAtomicGetOrElseUpdate.scala18
5 files changed, 178 insertions, 0 deletions
diff --git a/kamon-core/src/main/scala/kamon/util/ConfigTools.scala b/kamon-core/src/main/scala/kamon/util/ConfigTools.scala
new file mode 100644
index 00000000..9810428e
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/ConfigTools.scala
@@ -0,0 +1,26 @@
+package kamon.util
+
+import java.util.concurrent.TimeUnit
+
+import com.typesafe.config.Config
+
+import scala.concurrent.duration.FiniteDuration
+
+object ConfigTools {
+ implicit class Syntax(val config: Config) extends AnyVal {
+ // We are using the deprecated .getNanoseconds option to keep Kamon source code compatible with
+ // versions of Akka using older typesafe-config versions.
+
+ def getFiniteDuration(path: String): FiniteDuration =
+ FiniteDuration(config.getNanoseconds(path), TimeUnit.NANOSECONDS)
+
+ def firstLevelKeys: Set[String] = {
+ import scala.collection.JavaConverters._
+
+ config.entrySet().asScala.map {
+ case entry ⇒ entry.getKey.takeWhile(_ != '.')
+ } toSet
+ }
+ }
+
+}
diff --git a/kamon-core/src/main/scala/kamon/util/FastDispatch.scala b/kamon-core/src/main/scala/kamon/util/FastDispatch.scala
new file mode 100644
index 00000000..8f23164a
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/FastDispatch.scala
@@ -0,0 +1,22 @@
+package kamon.util
+
+import akka.actor.ActorRef
+
+import scala.concurrent.{ ExecutionContext, Future }
+
+/**
+ * Extension for Future[ActorRef]. Try to dispatch a message to a Future[ActorRef] in the same thread if it has already
+ * completed or do the regular scheduling otherwise. Specially useful when using the ModuleSupervisor extension to
+ * create actors.
+ */
+object FastDispatch {
+ implicit class Syntax(val target: Future[ActorRef]) extends AnyVal {
+
+ def fastDispatch(message: Any)(implicit ec: ExecutionContext): Unit =
+ if (target.isCompleted)
+ target.value.get.map(_ ! message)
+ else
+ target.map(_ ! message)
+ }
+
+}
diff --git a/kamon-core/src/main/scala/kamon/util/MapMerge.scala b/kamon-core/src/main/scala/kamon/util/MapMerge.scala
new file mode 100644
index 00000000..b7f18788
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/MapMerge.scala
@@ -0,0 +1,27 @@
+package kamon.util
+
+object MapMerge {
+
+ /**
+ * Merge to immutable maps with the same key and value types, using the provided valueMerge function.
+ */
+ implicit class Syntax[K, V](val map: Map[K, V]) extends AnyVal {
+ def merge(that: Map[K, V], valueMerge: (V, V) ⇒ V): Map[K, V] = {
+ val merged = Map.newBuilder[K, V]
+
+ map.foreach {
+ case (key, value) ⇒
+ val mergedValue = that.get(key).map(v ⇒ valueMerge(value, v)).getOrElse(value)
+ merged += key -> mergedValue
+ }
+
+ that.foreach {
+ case kv @ (key, _) if !map.contains(key) ⇒ merged += kv
+ case other ⇒ // ignore, already included.
+ }
+
+ merged.result();
+ }
+ }
+
+}
diff --git a/kamon-core/src/main/scala/kamon/util/Timestamp.scala b/kamon-core/src/main/scala/kamon/util/Timestamp.scala
new file mode 100644
index 00000000..4ff031a6
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/Timestamp.scala
@@ -0,0 +1,85 @@
+package kamon.util
+
+/**
+ * Epoch time stamp.
+ */
+class Timestamp(val seconds: Long) extends AnyVal {
+ def <(that: Timestamp): Boolean = this.seconds < that.seconds
+ def >(that: Timestamp): Boolean = this.seconds > that.seconds
+ def ==(that: Timestamp): Boolean = this.seconds == that.seconds
+ def >=(that: Timestamp): Boolean = this.seconds >= that.seconds
+ def <=(that: Timestamp): Boolean = this.seconds <= that.seconds
+
+ override def toString: String = String.valueOf(seconds) + ".seconds"
+}
+
+object Timestamp {
+ def now: Timestamp = new Timestamp(System.currentTimeMillis() / 1000)
+ def earlier(l: Timestamp, r: Timestamp): Timestamp = if (l <= r) l else r
+ def later(l: Timestamp, r: Timestamp): Timestamp = if (l >= r) l else r
+}
+
+/**
+ * Epoch time stamp in milliseconds.
+ */
+class MilliTimestamp(val millis: Long) extends AnyVal {
+ override def toString: String = String.valueOf(millis) + ".millis"
+
+ def toTimestamp: Timestamp = new Timestamp(millis / 1000)
+ def toRelativeNanoTimestamp: RelativeNanoTimestamp = {
+ val diff = (System.currentTimeMillis() - millis) * 1000000
+ new RelativeNanoTimestamp(System.nanoTime() - diff)
+ }
+}
+
+object MilliTimestamp {
+ def now: MilliTimestamp = new MilliTimestamp(System.currentTimeMillis())
+}
+
+/**
+ * Epoch time stamp in nanoseconds.
+ *
+ * NOTE: This doesn't have any better precision than MilliTimestamp, it is just a convenient way to get a epoch
+ * timestamp in nanoseconds.
+ */
+class NanoTimestamp(val nanos: Long) extends AnyVal {
+ override def toString: String = String.valueOf(nanos) + ".nanos"
+}
+
+object NanoTimestamp {
+ def now: NanoTimestamp = new NanoTimestamp(System.currentTimeMillis() * 1000000)
+}
+
+/**
+ * Number of nanoseconds between a arbitrary origin timestamp provided by the JVM via System.nanoTime()
+ */
+class RelativeNanoTimestamp(val nanos: Long) extends AnyVal {
+ override def toString: String = String.valueOf(nanos) + ".nanos"
+
+ def toMilliTimestamp: MilliTimestamp =
+ new MilliTimestamp(System.currentTimeMillis - ((System.nanoTime - nanos) / 1000000))
+}
+
+object RelativeNanoTimestamp {
+ def now: RelativeNanoTimestamp = new RelativeNanoTimestamp(System.nanoTime())
+ def relativeTo(milliTimestamp: MilliTimestamp): RelativeNanoTimestamp =
+ new RelativeNanoTimestamp(now.nanos - (MilliTimestamp.now.millis - milliTimestamp.millis) * 1000000)
+}
+
+/**
+ * Number of nanoseconds that passed between two points in time.
+ */
+class NanoInterval(val nanos: Long) extends AnyVal {
+ def <(that: NanoInterval): Boolean = this.nanos < that.nanos
+ def >(that: NanoInterval): Boolean = this.nanos > that.nanos
+ def ==(that: NanoInterval): Boolean = this.nanos == that.nanos
+ def >=(that: NanoInterval): Boolean = this.nanos >= that.nanos
+ def <=(that: NanoInterval): Boolean = this.nanos <= that.nanos
+
+ override def toString: String = String.valueOf(nanos) + ".nanos"
+}
+
+object NanoInterval {
+ def default: NanoInterval = new NanoInterval(0L)
+ def since(relative: RelativeNanoTimestamp): NanoInterval = new NanoInterval(System.nanoTime() - relative.nanos)
+}
diff --git a/kamon-core/src/main/scala/kamon/util/TriemapAtomicGetOrElseUpdate.scala b/kamon-core/src/main/scala/kamon/util/TriemapAtomicGetOrElseUpdate.scala
new file mode 100644
index 00000000..cd457cdc
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/TriemapAtomicGetOrElseUpdate.scala
@@ -0,0 +1,18 @@
+package kamon.util
+
+import scala.collection.concurrent.TrieMap
+
+object TriemapAtomicGetOrElseUpdate {
+
+ /**
+ * Workaround to the non thread-safe [[scala.collection.concurrent.TrieMap#getOrElseUpdate]] method. More details on
+ * why this is necessary can be found at [[https://issues.scala-lang.org/browse/SI-7943]].
+ */
+ implicit class Syntax[K, V](val trieMap: TrieMap[K, V]) extends AnyVal {
+ def atomicGetOrElseUpdate(key: K, op: ⇒ V): V =
+ trieMap.get(key) match {
+ case Some(v) ⇒ v
+ case None ⇒ val d = op; trieMap.putIfAbsent(key, d).getOrElse(d)
+ }
+ }
+}